OpenAM 11.0とJ2EEエージェントの間で発生するリダイレクトループについて

今回は、OpenAM 11.0 と J2EEエージェント(以下エージェントと書きます)の間で発生するリダイレクトループの問題について解説します。OpenAM 11.0より前のバージョンでは発生しなかったこの問題が、なぜ発生するようになったのか、そしてそれをどのように回避するのかについて説明します。

なお、この問題はバグとしてJIRAに登録してあります。

https://bugster.forgerock.org/jira/browse/OPENAM-4022

 暫定対策の方法が分かっているため、現時点では対策をしていません。

この問題を理解するためには、まずOpenAMのセッションサービスの概要について知る必要があります。

■ OpenAMのセッションサービスの概要

OpenAMは、エージェントと連携するために、様々なサービスを提供しています。例えば、リモートログを出力させるためのロギングサービスや、名前解決をするためのネーミングサービスなどがあります。セッションサービスもその一つです。エージェントは、ユーザーとエージェント自身のセッションを管理するために、このセッションサービスとHTTPで通信をします。以下の図のように、セッションIDはOpenAMのセッションテーブルで管理され、以降のエージェントから送信されてくるセッションリクエスト内のセッションIDを検証する仕組みになっています。

rl01

このとき、エージェントから送信されてくるセッションIDがセッションテーブルに存在しない場合、OpenAMは以下のような例外メッセージを含むレスポンスを返します。

HTTP/1.1 200 OK

...

<!--?xml version="1.0" encoding="UTF-8" standalone="yes"?-->
<![CDATA[<SessionResponse vers="1.0" reqid="296">
<GetSession>
<Exception>
Application token passed in, is invalid.token:AQIC5wM2LY4SfczFan4NEECbrokOPn6dygV-23VAmEXT0Cg.*AAJTSQACMDEAAlNLABQtMjc3MjM4NTA2MTY2Mjc4NTcwMA..
</Exception>
</GetSession>
</SessionResponse>]]>

例えば、OpenAMのみを再起動した直後などはセッションテーブルは空になっているので、このレスポンスが返ります。これを受信したエージェントは、以下の条件で自身のセッションが無効になっているか判定します。

if (exceptionMessage.indexOf(
    SessionBundle.getString("appTokenInvalid")) != -1)  {

こ の条件式の SessionBundle.getString(“appTokenInvalid”) は上で例示したレスポンスに含まれている “Application token passed in, is invalid.” であり、この場合、エージェントはOpenAMサーバーが再起動したと判断して、自身のセッションIDを新たに生成し、OpenAMサーバーに再認証のリ クエストを送信します(セッションリフレッシュ)。

rl02

“Application token passed in, is invalid.”のような想定済みの例外メッセージ以外の例外メッセージがレスポンスに含まれている場合、エージェントはOpenAMサーバーで一時的な問題が発生したと判断して、再度セッションサービスにリクエストを送信し、正常なレスポンスが返るまでそれを繰り返します。実装は、次のようなになっています。

sres = sendPLLRequest(svcurl, sreq);
while (sres.getException() != null) {
    processSessionResponseException(sres, appSSOToken);
    if (context != null) {
        sreq.setRequester(RestrictedTokenContext.marshal(context));
    }
    // send request again
    sres = sendPLLRequest(svcurl, sreq);
}

ここまでがセッションサービスの概要です。細かいことはいろいろと省略していますが、簡単に説明すると以上のようになります。

■ リダイレクトループの原因

前述した通り、セッションリフレッシュの条件はOpenAMのセッションサービスからの応答がSessionBundle.getString(“appTokenInvalid”)の例外メッセージを含んでいるかどうかということになります。エージェントは多言語対応していない(amSession_ja.propertiesのような言語ファイルを持っていない)ので、 SessionBundle.getString(“appTokenInvalid”)の値は常に英語の“Application token passed in, is invalid.”になります。したがって、OpenAMのセッションサービスは例外メッセージを英語で返す必要があります。

OpenAMが例外メッセージを作成する部分の実装は次のようになっています。

String loc = SystemPropertiesManager.get("com.iplanet.am.locale", "en_US");
ResourceBundle sessionBundle = ResourceBundle.getBundle("amSession", getLocale(loc));
String exceptionMessage = sessionBundle.getString("appTokenInvalid");

一見、英語(en_US)のプロパティ値を取得しているので何も問題ないように見えます。実際に、OpenAM 11.0より前のバージョンでは、英語の例外メッセージをエージェントに返していました。

しかし、OpenAM 11.0では以下のように日本語の例外メッセージを返してしまいます。

rl03

このレスポンスを受信したエージェントは、前述した通り、以下の条件で自身のセッションが無効になっているか判定します。

if (exceptionMessage.indexOf(
    SessionBundle.getString("appTokenInvalid")) != -1)  {

exceptionMessageの値は、日本語の“期限切れのアプリケーショントークンは無効です。”になるので、この条件はfalseになり、再度OpenAMのセッションサービスにリクエストを送信します。その後も、OpenAMが返す応答には、日本語のメッセージが含まれているため、エージェントはセッションサービスへリクエストの送信を繰り返し、結果的にリダイレクトループが発生します。

・なぜOpenAM 11.0は日本語の例外メッセージを返してしまうのか?

“en_US”を指定して取得したプロパティ値が、OpenAM 11.0の場合に日本語になってしまう原因は、OpenAM 11.0からamSession_en.propertiesが無くなったことにあります。OpenAM 11.0の開発とともにビルド/プロジェクト管理ツールが、従来のAntからMavenに移行されました。この移行の過程で英語用の言語ファイル○○_en.propertiesを最終的なwarファイルに含めるプロセスが無くなってしまったのです。

amSession_en.propertiesの有無で動作が変わるかどうかは、実際にResourceBundle.getBundle(“amSession”, Locale.ENGLISH).getString(“appTokenInvalid”)の結果を確認してみれば分かります。

まずは、OpenAM 11より前のバージョンの場合(amSession_en.propertiesがある場合)は、

  • amSession.properties
  • amSession_en.properties
  • amSession_jp.properties

“Application token passed in, is invalid.” となります。

次に、OpenAM 11の場合(amSession_en.propertiesが無い場合)は、

  • amSession.properties
  • amSession_jp.properties

“期限切れのアプリケーショントークンは無効です。”となります。

この値は、OSやアプリケーションサーバーに設定されたロケール(正確に言うと、java.util.Locale.getDefault()が返す値)に依存します。このあたりの詳細な仕様は、java.util.Locale.LocaleのJavadocjava.util.ResourceBundleのJavadocを確認して下さい。

■ 回避策

この問題の回避策は、以下のいずれかにより、java.util.Locale.getDefault()の戻り値を変えることです。

  1. amSession_en.propertiesをWEB-INF/classes以下にデプロイする。
  2. OpenAMサーバのデフォルトロケールの設定を変更する(例えば、Tomcatの起動スクリプトにLANG=”en_US”を追加する)

■ 根本対策

根本対策は、これまで通り○○_en.properties を OpenAM のwarファイルに含めることになります。対策は他にもいつか考えられますが、後述するもう一つの問題の解決のためにも、○○_en.properties を含めた方がいいのではないかと思います。Mavenのビルドプロセスを改善して、○○_en.propertiesを複製するのが正しいのですが、現時点では対策できていません。
そもそも例外のIDではなくメッセージを分岐条件に使っているのがどうなんだという話もありますが、まあその辺は過去の経緯などもあるかもしれないので…

■ 関連する問題

○○_en.properties が無くなったことにより、発生する問題は他にもあります。ブラウザの言語設定が効かなくなるという問題です。11.0.0より前のバージョンでは、ブラウザの言語設定を英語に変更すると、OpenAMの管理コンソールの表示はすべて英語に変わりましたが、現在はそれが機能しなくなっています。前述した対策を実施することで、機能するようになります。

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中