ShibbolethはApacheからの環境変数として属性を受け渡すため、多くの環境では非常に簡単にアプリケーションから属性を取得することができますが、Tomcatはその例外の一つです(Tomcatのアプリにすんなりと環境変数を渡す方法が無いため)。今回実験環境でテストしたので、そのメモを残しておきます。
システム構成
Tomcat単体ではShibbolethのSPとなることはできないため、Shibboleth SPをApacheで構築し、そこからAJP経由で接続するのがもっとも簡単なように思えます。
たとえばCentOSであれば、/etc/httpd/conf.d/proxy_ajp.confみたいな感じでファイルを作成し、その中でTomcatのアプリケーション(ここでは/myapp/とする)を、
1 |
ProxyPass /myapp/ ajp://localhost:8009/myapp/ |
のようにAJPで繋ぎます。そして/etc/httpd/conf.d/shib.confの最後辺りに、
1 2 3 4 5 6 |
<Location /myapp/> AuthType shibboleth ShibCompatWith24 On ShibRequestSetting requireSession 1 require shib-session </Location> |
みたいな感じで/myapp/をShibboleth認証します(実際の環境では、ログインに必要なロケーションのみをShibboleth認証するほうがおすすめだと思います)。CentOSにおけるSPの構築は、学認の技術ガイドに詳しく解説されています。FreeBSD上での構築はこのサイトの昔の記事にあります。
以上の環境を仮定して、TomcatにShibboleth属性を渡す設定について紹介します。IdP側の設定は通常のSPと同じなので省略します。渡す属性はeduPersonPrincipalName(以下ePPN)を仮定します。
Shibboleth SPの設定
実は設定自体はそれほど難しくありません。shibboleth2.xmlの<ApplicationDefaults/>の設定に、次のようにattributePrefixという属性を追加します。
設定前
1 2 3 4 5 |
<ApplicationDefaults entityID="https://testsp.hogehoge.ac.jp/shibboleth-sp" signing="false" encryption="false" REMOTE_USER="eppn"> <!-- 略 --> </ApplicationDefaults> |
設定後
1 2 3 4 5 |
<ApplicationDefaults entityID="https://testsp.hogehoge.ac.jp/shibboleth-sp" signing="false" encryption="false" REMOTE_USER="eppn" attributePrefix="AJP_"> <!-- 略 --> </ApplicationDefaults> |
これでAJP経由で属性eppnが渡されることになります(ちなみに「eppn」という名前がePPNに対応していることは、/etc/shibboleth/attribute-map.xmlに設定されています)。
Webアプリ側での属性取得
このようにして渡された属性は、次のようにして取得可能です。ここに辿り着くまでにはかなり試行錯誤しましたが、できてしまえば意外に簡単です。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class testsp extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { String eppn = (String)req.getAttribute("eppn"); res.setContentType("text/plain;"); PrintWriter out = res.getWriter(); out.println(eppn); } } |
「ShibUseHeaders On」のセキュリティ問題
なお、学認のMLのアーカイブを見ていると、このあたりで関連した議論が行われていますが、「ShibUseHeaders On」に関する議論がちょっとわかりにくい感じになっているかもしれません(私も最初混乱しました)。要するに、/etc/httpd/conf.d/shib.confの<Location/>に、
1 2 3 4 5 6 7 |
<Location /myapp/> AuthType shibboleth ShibCompatWith24 On ShibRequestSetting requireSession 1 ShibUseHeaders On require shib-session </Location> |
のように「ShibUseHeaders On」を追加するかどうかという話なのですが、結局次のような意味かと思われます。
- 「ShibUseHeaders On」を設定すると、req.getHeaderNames()で属性の「名前」を取得して、req.getHeader()で属性の「値」を取得することになる。
- 「ShibUseHeaders On」を設定しない場合は、先ほどの解説の通り、shibboleth2.xmlのApplicationDefaults/@attributePrefixに”AJP_”を設定した上で、req.getHeader() ではなく、req.getAttribute()で属性を取得することになる。ただし、req.getAttributeNames()では属性の「名前」は取得できないが、ほとんどの場合問題になることはないだろう。
- 「ShibUseHeaders On」を設定することは、ブラウザによる偽装ヘッダのセキュリティホールを作ってしまう可能性が否定出来ない。
- したがって「ShibUseHeaders On」は使わない方がいい。
というのが結論なのではないでしょうか。NativeSPSpoofCheckingの解説(上記記事ではリンク切れしているので新しい場所にリンクを張ってます)のところでも同様の話がされているようです。
実際のところ、先日Shibbolethリバースプロキシを構築した時に、HTTPヘッダをShibboleth環境で偽装できるか色々試してみたのですが、結局成功しませんでした。しかし、何か方法があるのかもしれません。Shibblethのリバースプロキシはまだ実際の環境でサービスとして提供していませんが、もう少し方法を考えたほうが良いかも知れません。