MoinMoin + SAML SSO

結構長い道のりなので、ググってヒットして喜んでる人がいたらとりあえず頭を冷やそうか。

環境は
  • SP (= MoinMoin側)
    • Ubuntu 12.04 LTS
    • python-moimoin 1.9.3-1ubuntu2
    • moinmoinsaml 最終更新 2012-06-12 時点
  • IdP
    • SimpleSAMLphp 1.8.2-1
      • 同じマシンで別のホスト名を使ってやりとりさせてるトリッキーな設定

○ MoinMoinってもわもわしてる。

いいえ、Pythonで書かれたWikiです。

SAML対応はプラグインを書いている方がいる。ただ、それほど親切な実装にはなってないので、比較的SAMLを理解してないとこれは使いづらい。分かってれば比較的大丈夫だけど、ライブラリの挙動を見つつ書くってのは結構骨が折れる。やりたいのはただのSSOなんだけど。

moimoinsamlをそのまま使うと、IdPから送られてきた「uid」のattributeを勝手にMoinMoin内のアカウント名として認識してログインする。

今回はその部分を「givenNameとsn (sur name = 姓)」の両方があった場合は結合して使おうとしてみる、というロジックも入れた。いやだってそういう名前でログインしてたんだもん!

○ やること

基本的に現在上記のページ (moinmoinsaml) に書いてあることの意味を汲み取って書く感じに

1. pysaml2 を入れる

思ったより問題なく入った。

そういえばこれに関連してpyxmlsecのメンテされなさ具合を意識してたんだが、pysaml2自体はxmlsecを直接使ってるだけなのね (ていうかコマンドライン経由で使ってるのか……!) 

# xmlsec自体は証明書周りの処理に使うのだと思う。コマンドラインツールは優秀だぞっ

というわけでpysaml2自体は安牌だった。

なお、本家で必要になるかもしれないと指摘されているパッケージはMoinMoinでのケースでは必要ないように見える。ただ、エラーが出たらその都度入れるべき。

2. とりあえずmoinmoinのログを見られるようにする

/usr/local/share/moin/moin.wsgi でコメントアウトされている from MoinMoin import log 辺りをいじる。
もともとあるファイルを参照する形で log.load_config('/usr/local/share/moin/config/logging/logfile') といった感じでやってしまったが、別の方法でも別に問題ない気がする。

なお、Apacheの再起動が必要に見えた。以降も逐一再起動した。reloadでも良い可能性はあるけど。

3. moinmoinsamlに入っているsaml.pyとSAMLMetadata.pyを指定された場所にコピー
Copy the saml.py file to the MoinMoin/auth directory. This may be located in
the Python site-packages directory or on a local directory depending on the
way you have installed MoinMoin.

Then copy the SAMLMetadata.py file to wiki/data/plugin/action/ directory of
your wiki instance.

今回の環境では
  • /usr/local/lib/python2.7/dist-packages/MoinMoin/auth/
  • /usr/local/share/moin/data/plugin/action/
よくわかんないときはlocateとか色々駆使するのだ。

4. wikiconfig.py に設定を書き連ねる

最大の山場

ちなみにこれをやって、再起動した時点から以前のユーザ名パスワード画面が出ずにSSOを強制使用するようになる。wikiconfig.pyは特に注意して設定しないと二度とログインできなくなる

こういう感じにした

ちなみに本家サイトの設定例にもある eduPersonAffiliation という部分は実際には使ってない。uidを使う。

この辺り、本家は「最後にこういう感じで」とか書いてあって超シンプルに終わってるのだけど、IdPのメタデータの断片をpysaml2形式で書き連ねるとかそういうところが密やかにどっちゃり入ってて、筆者のダルさが感じられる。うぐぅ

この辺りでSAMLの仕様を全力で利用しきった設定を書くにはpysaml2の方を理解する必要がある気がする。今回のプラグインはそれを使ってるだけなので。

テスト中はクッキーの挙動とかが未知なので、Chromeのincognito windowを使うとか、サブのブラウザを開いて閉じてを繰り返したりとか、IdP側のクッキーを逐一消すとかの工夫があったほうが良いかもしれない。今回は、はまらなかったけど……

5. attribute_map_dir を作って __init__.py にMAPを作る

これがないとMoinMoinがクラッシュする。

今回の環境で上の設定ファイルの場合は /usr/local/share/moin/attribute-maps。これはwikiconfig.pyで指定されたディレクトリを見に行くので、別にどこにしても良いとは思う。

基本的にはこの辺りなども参照しながらよろしくやる。


このattribute mapというものについての説明が全然ないのだが、attribute mapはIdPから送られてきたattributeをどこにマッピングするかを決めるもの「っぽい」 (ShibbolethにもAttribute Mapperってのがあるよね)。

今回については背後にLDAPがあってそのuidなどを使う前提にしていたので、この設定はかなりいい加減。具体的には、上記のサイトのをコピーした。

# Active Directory的な何かの設定に見えるな……

attribute_map_dirを設定しない場合にどうなるかは試してない。なくてエラーが出ないようならソッチの方が健全な気がする。

6. IdP 側にこのSPのメタデータを登録する。

http://(spのホスト)/moin/?action=SAMLMetadata にアクセスすると、moimoinsamlがうまく動いていればメタデータのxmlを吐き出してくれる。というわけでそれをIdPに教える。

ちなみに今回もIdPがSimpleSAMLphpなため、自前のxmltophp的ツール使ってみた。……そしたら、明らかなバグがあってドン引きした。ごめんよごめんよ。やる気なくてごめんよ。

6. とりあえずログイン出来るのを確認しよう。

エラーは Apache と moinmoinのどっちに出るかはケースバイケース。IdP側のログも見るべき。

7. ログインに使う名前を、IdPから与えられた givenName と sn から構築出来るか試す。

明らかにバックエンドが LDAP でスキーマとしてinetOrgPerson と posixAccount というのを前提にしているのだけど普通そうじゃね? eduPerson とかここでつかわねーよなぁ……つかうのかなぁ……

最初にコピーした saml.py の uid をMoiMoinの名前に変換するロジックに少しコードを挟むだけ。Python知ってればすぐできる。出来なかったら、ねんじろ!


givenNameとsnがない場合は素直に uid を使う実装になっている、はず。

このブログの人気の投稿

LibreOfficeで表紙、目次、本体でフッターのページ番号のスタイルを変える

WiiUのコントローラが通信不良に陥った話

技術書典2 あ-03 『もわねっとのPythonの本』