学認IdPをShibboleth3にする際のメモ


Shibboleth 2.Xが2016年夏にEnd-of-Lifeを迎えるため、そろそろ各学認Shibboleth IdP管理者様の方でもShibboleth 3.Xへの移行作業をされていると思います。学認サイトもShibboleth 3.X系の情報が増えていますが、まだ2.Xの頃の情報の整理された充実ぶりには及ばないようで、アップデート作業はかなり難儀しました。そのため、現状の最新バージョンであるShibboleth 3.2.1にアップデートを行った際にはまった罠について簡単に紹介しておこうと思います。

なお、まだマイナーバージョンの違いで、一部の重要そうな機能の設定が異なったり、この機能は絶対に必要だ、というような機能が3.2.0や3.2.1になってから追加されていたりするので、色々悩ましいのですが、とりあえず3.2.1ではなんとか2.Xから我々が使っている概ねすべての機能を移行することができました。作業を3.2.0以前で始められている方は、今からでも3.2.1にターゲットを変更することを強くおすすめします。

なお、以下の記述はまずCentOS 6+OpenJDK 7+Tomcat 7で構築した後、もう一度CentOS 7+Oracle JDK 8+Tomcat 8の組み合わせで構築しなおした経験にもとづいています。双方の差は、Tomcatの違いに起因する、consent-interceptのバックエンドのMySQL接続設定(conf/global.xml)の部分のみでした(もちろん、OSのセットアップやJava, Tomcatのインストール手順などは大きく異なりますが、Shibboleth3の設定という観点からのみ考えると、差は大きくありません)。

それでは、はまった点を紹介していきます。

LDAP由来の属性がSPに送信されない

LDAPの設定ファイルconf/ldap.properties中のidp.attribute.resolver.LDAP.returnAttributesを適切に設定しないと、LDAP経由の属性がSPに送信されない(LDAPに要求する属性をコンマ区切りで並べる必要がある)。ちなみにデフォルトではこの値はcn,homephone,mailのみとなっている。

(2016/03/24 追記)学認MLでご指摘いただいたのですが、こちらの問題は学認技術ガイドが現在提供しているattribute-resolver-template.xmlを利用した場合は生じないようです。

情報提供ありがとうございました。

属性送信許可がデフォルトで有効

Shibboleth3.Xでは、かつてのuApprove.jpプラグイン相当のconsent-intercept機能がShibboleth本体に搭載され、さらにデフォルトで有効化されているため、もしこの機能を利用しない場合は、conf/relying-party.xmlに次の設定が必要である(もちろん学認の場合はこの機能を利用するほうがおすすめ設定である)。

既存のStoredIDのデータベースに接続できない

Shibboleth2.Xの時代に使っていたStoredIDのMySQLデータベースに接続しようとしたら、次のエラーが出て接続できない。

これはShibboleth 3.2.0から(競合状態の解消のため)StoredIDのテーブル定義に変更が必要となったためである。具体的にはshibpidテーブルのlocalEntity, peerEntity, persistentIdの3つのカラムはユニーク制約を持つ必要がある(詳細はhttps://wiki.shibboleth.net/confluence/display/IDP30/PersistentNameIDGenerationConfigurationで解説されている)。学認サイトにあるサンプルのテーブル定義に新しい変更をマージし、次のような定義に変更することで問題なく動作するようになった。

また、本当は古いテーブルから新しいテーブルにデータをコピーする必要が生じる必要があると思われるが、過去に一度もpersistentIDを手動で変更したりしたことがなければ、conf/attribute-resolver.xmlのstoredIDの初期値ソースやソルトの定義を変えないかぎり、新しいテーブルを用意してそちらを参照するようにしてしまえば実用上問題ないと思われる。

uApprove.jpで行っていた属性送信許可機能の移行

プラグインとして実現されたuApprove.jpと違い、Shibboleth 3.Xではそれに相当する属性送信制御のシステムであるconsent-intercept機能が標準で有効となっている。ただし、デフォルトではブラウザのCookieとHTMLローカルストレージに格納されるため、別のブラウザからアクセスしたりするともう一度選択のやり直しになるし、(デフォルトで無効化されている)利用規約への同意がクライアントサイドに格納されるのは趣旨的に何かおかしい。

そのため、Shibboleth2の時と同様に、StoredIDのサーバとなっているMySQLサーバに格納することとしたい。まず、データはuApprove.jpと別物なので、MySQLに新しいデータベースを作成し、次のテーブルを作成する。

conf/global.xmlに次の定義を追加する。ただし先述の通り、ここはTomcatが7と8の場合で少しだけ記述が異なる。まずはTomcat7の場合。

Tomcat8の場合は、上記の<bean id=”shibboleth.JPAStorageService.DataSource”/>を次のように記述する(残りの部分は上記と共通)。

conf/idp.propertiesを次のように変更する。

なお、consent-intercept機能では、許可に関するキーにuid以外の属性を指定することが可能である。たとえばconf/idp.propertiesに以下のように設定することで、キーをePPNに指定できる。なお、この機能がまともに動くようになったのはShibboleth 3.2.0以降のようである。

確認画面で属性の表示順を指定するには、conf/intercept/consent-intercept-config.xmlで次のように設定する(順番は一例)。この機能はShibboleth 3.2.1以降で利用可能(3.2.0では違った形式でサポート、それ以前は属性名の文字コード順固定)。

uApprove.jpで行っていた利用規約同意機能の移行

consent-intercept機能で利用規約への同意を取る場合は、次のように設定する。まず、conf/relying-party.xmlを次のように変更する。

conf/intercept/consent-intercept-config.xmlで、shibboleth.consent.terms-of-use.Keyのaliasの部分を次のように書き換える。

messages/consent-messages.propertiesのサンプルをコメントアウトし、上で指定した「my-terms-of-use-0」の定義を加える。

利用規約のバージョンを上げるには、my-terms-of-use-1のように、後ろに番号を足して新しい規約に更新すれば良い(consent-intercept機能はキーとしてmy-terms-of-use-0の部分を使うので、利用規約を更新した場合に新たに同意を取り直させたい場合は、この部分の文字列を変更する必要がある)。このあたりは利用規約のXML中にバージョン番号があったuApprove.jpよりわかりにくくなっているが、利用規約にHTMLが簡単に使えるようになっている点は、uApprove.jpよりわかりやすくなっている。

(利用規約同意機能に関してはこちらを参考にした。https://www.switch.ch/aai/guides/idp/user-consent/)

FPSPで実現されていたSP毎の属性送信設定機能の移行

以前パッチで提供されていたFPSP(Filter Per SP)機能は、似た機能がShibboleth 3では標準でサポートされた。有効化するには次のように設定する。

まず、conf/relying-party.xmlに次のように設定する(ここは先ほど利用規約の設定をした場所と同じなので、terms-of-useの設定が入っているが、同機能を利用しないのであれば不要)。

そして、conf/intercept/context-check-intercept-config.xmlに次のように設定する。ただしここでは、

  • entityID-A: edupersonAffiliationがfacultyもしくはstaffの場合に利用できる
  • entityID-B: edupersonAffiliationがfacultyの場合に利用できる
  • それ以外: 常に利用できる

という条件を仮定している(例の中のentityID-AとentityID-BはそれぞれのSPのentityIDに置き換える)。

この設定は https://meatwiki.nii.ac.jp/confluence/pages/viewpage.action?pageId=20021272 を参考にした。

ところが、このやり方だと、「それ以外」の定義部分にもAとBのEntityIDを書かなければならず、メンテナンス性が悪い上にミスをしやすく、ミスをした場合にセキュリティ上の問題が生じる可能性がある。

上のロジックを擬似コードで幾分わかりやすく書くと、次のようになる。

この3つめの「(relyingPartyID != “entityID-A” && relyingPartyID != “entityID-B”)」の部分を書かずにすむように、等価な次のロジックに変えてみる(許可する条件をorで並べるのではなく、許可しない条件をor並べてその全体を否定する)。

これをconf/intercept/context-check-intercept-config.xmlの形式に直すと、次のようになる。

たしかにentityIDを複数回書く必要はなくなったが、行数が長くなり、また二重否定になったため少し頭を使う必要が増えたので、やや痛し痒しである。

この方法は学認メーリングリストでのNII西村先生のアドバイスによるものである。

メッセージのローカライズ

/opt/shibboleth-idp/messagesにある以下のファイルがメッセージの多国語化のためのカタログファイルとなっている。

  • authn-messages.properties: ログイン画面等のためのメッセージ
  • consent-messages.properties: 属性送信許可・利用規約同意などのためのメッセージ
  • error-messages.properties:エラー画面のためのメッセージ

これらにそれぞれ「_ja」をつけたファイルを作成し(authn-messages_ja.properties, consent-messages_ja.properties, error-messages_ja.properties)、内容を日本語化すれば、ブラウザ設定で日本語が英語より上位にある場合は「_ja」の内容で画面表示される。

オリジナルのメッセージを加えたり、そもそも画面自体をカスタマイズしていた場合は、後述するVelocityテンプレートの内容をカスタマイズした上で、このファイルに新たなメッセージを追加すればよい。

ロゴファイルなど、言語によってファイル名を変えたい場合も、メッセージとしてファイル名の文字列を定義すればよい。

上記のように定義して、参照側のVelocityテンプレートの部分で

のように参照すれば良い。

なお、反映にはTomcatの再起動が必要な模様。

画面のカスタマイズ

画面のカスタマイズを行う場合は、Shibboleth 2の時代はJSPを直接編集していたが、Shibboleth 3ではVelocityで記述されたテンプレートのvmファイルを編集する。ファイルは/opt/shibboleth-idp/views以下にある。編集は即座に反映され、Tomcatの再起動などは不要である。

メッセージの参照は、次のように「#springMessageText(“パラメータ名”, “代替文字列”)」で参照可能。パラメータ名はmessages/*.propertiesファイルで自由に定義できる。

プロジェクトのトップのロケーションは次のように「$request.getContextPath()」で参照可能。

簡単なカスタマイズであれば上記2つがあれば何とかなる。

属性創出確認などのテンプレートはviews/interceptの下にあるが、uApprove.jpとは根本的に異なったロジックで作られているので、属性のリスト部分などに関しては新しいファイルを元に作りなおしたほうがよい。

なお、CSSや画像ファイルなどを更新する場合は、相変わらずidp.warファイルをbin/build.shでビルドして、/usr/java/tomcat/webapp/idp.warを上書きする必要がある(tomcatが動いている状態で上書きするのがおすすめ)。

CSSはVelocityによる管轄対象外のようなので、CSS中でurl()などでパラメータの展開が必要なパスを参照していたり、条件によって文言やファイル名を切り替えたい場合などは、vmファイル中のHTMLで、<style>タグを使ってその部分のCSSを記述するなどの方法が必要となる。

ログにクライアントのIPアドレスやセッションIDを入れる

以前、ここで紹介した方法でShibbolethのログをPostgreSQLに格納しているのだが、そこで紹介した「Shibbolethのidp-audit.logにクライアントのIPアドレスやセッションIDを入れる」方法にもShibboleth3では変更が必要だった。

なお、Shibboleth2ではログに入れられるパラメータとして、クライアントのIPアドレス、IdPセッションID、JSESSIONIDの3つがあったが、Shibboleth3ではクライアントのIPアドレス、JSESSIONID、サーバのホスト名、サーバのポート番号の4つになり、IdPセッションIDがなくなってしまった。ただし、私が見た限りではJSESSIONIDが等しいリクエストはIdPセッションIDも等しかったようなので、意味が無いために設定から消えたのかもしれない。

idp-audit.logとidp-consent-audit.logの各業末尾にクライアントIPアドレスとJSESSIONIDを追加する設定はconf/logback.xmlを次のように変更する(<encoder/>の中の<Pattern/>の部分を修正する)。

ちなみにその他のパラメータとしては、idp.server_hostname(サーバのホスト名)、idp.server_port(サーバのポート番号)があるようだが、どちらもShibboleth 3.2以降のサポートのようである。

問題点・TODO

現状で未解決な問題点。

属性送信・規約同意に関する承認状況の移行

uApprove-JPで承認した規約同意や属性送信内容を新しい属性送信機構に移行することが難しい(手間を掛かける価値がどの程度あるのか不明)。規約同意は、わりと単純な構成なので移行することも不可能ではないが、属性送信機構は複雑そうである。

属性送信同意機能が必須属性も非送信を選択することが可能

属性送信同意機能がShibboleth本体に取り込まれたのはよいが、必須属性もチェックボックスで外すことができるようになってしまった。SPは必須属性が送信されていないので、おそらくエラーで終了する。

学認IdPをShibboleth3にする際のメモ」への1件のフィードバック

  1. ピンバック: Shibboleth IdPのログをPostgreSQLに格納する | 慶應義塾ITC本部・技術メモ

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です