OpenAMでリバースプロキシ方式SSO

こんにちは、白川です。

これはTECHSCORE Advent Calendar 2016の21日目の記事です。

今回はOpenAMを使ったシングルサインオン(以下SSO)について紹介します。

OpenAMについて

OpenAMの概要

WebアプリケーションにおけるSSOを
実現するためのプラットフォームとなるオープンソースのソフトウェアです。
SAML、OAuth2、OpenID Connect、など認証、認可に関連した複数のプロトコルをサポートしています。

SSOの実現方式

■ エージェント方式
 SSO対象のWebサーバ/アプリケーションサーバにOpenAMのPolicy Agentをインストールして、Policy AgentがブラウザとWebサーバ/アプリケーションサーバの通信の中で、OpenAMサーバに認証状態を確認することでSSOを実現します。
 Policy AgentはWebサーバ(Apache、IIS)用と、Java EEアプリケーションサーバ(Tomcat、WebLogic)用があります。

■ リバースプロキシ方式
 ブラウザとWebサーバ/アプリケーションサーバの間にリバースプロキシサーバを設置して、リバースプロキシサーバにPolicy Agentをインストールすることで、SSOを実現します。
 この方式ではリバースプロキシサーバにのみPolicy Agentをインストールするのみで済みますので、複数のSSO対象のWebサーバ/アプリケーションサーバが存在する場合、展開しやすいです。

■ 代理認証方式
 SSO対象アプリケーションのログインページに対して、IDとパスワードを送信し、ログインすることで、SSOを実現します。
 パッケージソフトを利用している場合など、SSOを実現するための修正対応が難しい場合に使われます。
 また、この方式では、SSO対象アプリケーションのID/パスワードを何らかの方式で同期させておく必要があります。

■ フェデレーション方式
異なるドメイン間で、パスワード等の情報を渡すことなく、安全に認証されたユーザーの情報を連携することで、シングルサインオン(SSO)を実現します。

今回はリバースプロキシ方式のSSOをOpenAMで実現するフローについて紹介します。
下記が今回紹介するフローの概要図です。


 
 

  1. ユーザがOpenAMで認証されていない状態で、リバースプロキシ経由でSSO対象のアプリケーションにアクセスします。
  2. OpenAMのPolicy Agent(リクエストを監視するソフトウェア)によって、認証されていないと判断し、OpenAMのログインページにリダイレクトします。
  3. ユーザは正しいIDとパスワードを入力して、ログインします。
  4. OpenAMによって認証され、ユーザ情報をHTTPヘッダにセットして、SSO対象アプリケーションにリダイレクトします。

環境

以下、実際に試してみた際のバージョン情報です。

■ OpenAMサーバ
・OS:CentOS 7.2
・Apache HTTP Server:2.4.6
・Tomcat:7.0.73
・Java:openjdk-1.8.0.111
・OpenAM:13.0.0

■ SSO対象アプリケーションサーバ
・OS:CentOS 7.2
・Apache HTTP Server:2.4.6
・PHP: 5.4.16
・OpenAM Web Policy Agent: 4.0.0 for Apache 2.4

OpenAMサーバのセットアップ

それでは、OpenAMサーバのセットアップから始めます。
下記の手順は全てrootユーザで実施します。

OpenAMをセットアップする際、OpenAMサーバのホスト名をFQDNで名前解決できるようにしておく必要があります。
また.(ドット)が2つ以上あるFQDNとしてください。
今回は、OpenAMサーバのFQDNを「openam-test.example.com」とします。

/etc/hostsで名前解決するために以下を追記します。

/etc/hostnameを以下のように変更します。

1. Java、Tomcatのインストール

Javaのインストールを行います。

次にTomcatのインストールを行います。

インストールが完了したら、環境変数JAVA_HOMEとJAVA_OPTSがセットされるように、/etc/profileに追記します。
OpenAMの起動には、1GBのJavaヒープと256MBのPermanent領域(Java8からはMetaspace領域)が必要です。
追記する内容は下記の通りです。

※ JAVA_HOME は bin/java 実行可能ファイルを含むディレクトリーを参照する必要があります。
不明な場合は下記コマンドで確認できます。

/etc/profileに追記した内容を反映させます。

Tomcatが起動することを確認します。

http://openam-test.example.com:8080に
ブラウザからアクセスしてTomcatのTop画面が表示されればここまではOKです。
※ アクセスする端末のhostsファイルにも以下を設定しておいてください。

2. OpenAMのインストール

こちらからダウンロードします。

ダウンロードするためには、forgerock社へのアカウント登録・サインインが必要です。

また、OpenAMのライセンスはCDDLとしてソースコードが公開されていますが、
いつからそうなったかは不明ですが、メジャーバージョンのみ無償でダウンロード可能となったようです。
マイナーバージョンのダウンロードはサブスクリプションの購入が必要です。

今回はOpenAM-13.0.0.zipをダウンロードしました。

ダウンロードしたzipファイルを解凍した中に、
OpenAM-13.0.0.warがありますので、
Tomcatのwebappsフォルダにコピーして、Tomcatを再起動してください。

3. OpenAMの初期セットアップ

http://openam-example.com:8080/loginに
ブラウザからアクセスして初期セットアップを行います。

アクセスすると下記の画面が現れます。


 
ここでは必ず「カスタム設定」を選択してください。
「デフォルト設定」には不具合があり、後に問題が起きる可能性があるためです。

ライセンスに同意した後に、amAdminユーザのパスワードを設定する画面が表示されます。
amAdminユーザはopenamの管理者権限を持つユーザでパスワードを忘れてしまうと、openamの一切の設定ができなくなってしまうため、忘れないように注意が必要です。
ここではopenam01としました。

OpenAM admin パスワード設定
 
 
次に「サーバー設定」画面に遷移します。
ここでは、設定ディレクトリのみ「/usr/local/openam」としました。
その他はデフォルトで設定される内容のまま次に進みます。

サーバー設定画面
 
 
次に「設定データストア」画面に遷移します。
ここは「OpenAM」が初期で選択されており、設定内容は変更せずに次に進みます。

設定データストア画面
 
 
次に「ユーザデータストア」画面に遷移します。
ここは「OpenAMのユーザストア」を選択して、次に進みます。

ユーザデータストア画面
 
 
次に「サイト設定」画面に遷移します。
ロードバランサの下に配置されるOpenAMサーバかどうかを問われます。
OpenAMを冗長化する場合にYESにするようですが、今回はNOで次に進みます。

サイト設定画面
 
 
次にPolicy Agentで使用するパスワードを設定します。
後の手順で必要となりますので、忘れないように注意が必要です。ここではopenam02としました。

Policy Agent パスワード設定
 
 
最終確認画面が表示されますので、
「設定の作成」ボタンをクリックします。

最終確認画面
 
 
以下のように画面表示されれば、完了です。

完了画面
 
 
もしここで失敗した場合は、OpenAMの設定ディレクトリ(今回では/usr/local/openam)直下にあるinstall.logに、
エラー内容が出力されています。
エラー内容確認の上、再度初期設定から行う場合は、OpenPMの設定ディレクトリ、Tomcatの配備ディレクトリを削除して、
Tomcatを再起動します。


4. 独自認証モジュール作成

OpenAMでは標準でActive DirectoryやLDAP、JDBCなど様々なログイン認証のモジュールが用意されていますが、
独自の認証モジュールを作成することが可能です。
OpenAMのDevelopers Guideに方法が記載されていますので、
こちらを参考に作成してみます。

今回は以下の仕様で認証モジュールを作成します。

  • sampleというrealm(レルムと言います。OpenAMで一連の設定を管理する単位のこと)で使用する
  • ログイン可能となる固定のユーザ名とパスワードをOpenAMの管理画面で設定可能とする
  • 認証OKであれば、セッションにユーザ情報をセットする

認証モジュールは下記のディレクトリ構成で作成します。
★をつけたものを用意していきます。

4-1. pom.xmlの準備

以下の内容で作成します。

4-2. src/main/java/org/forgerock/openam/examples/SampleAuth.java

com.sun.identity.authentication.spi.AMLoginModuleを継承したクラスを作成します。
processというメソッドのcase文のSTATE_AUTHの部分にログインボタン押下時のロジックを記述します。
今回は、こちらを参考に、以下の内容で作成しました。

4-3. src/main/java/org/forgerock/openam/examples/SampleAuthPrincipal.java

java.security.Principalを実装したクラスです。
ここではこちらの内容をそのまま利用します。(内容は割愛します。)

4-4. src/main/resources/amAuthSampleAuth.properties

ログイン画面で差し替えに必要となる文字列などを定義したプロパティファイルです。
こちらを参考に以下のように作成しました。
※ native2asciiでUnicodeに変換する前の内容です。

4-5. src/main/resources/amAuthSampleAuth.xml

作成する認証モジュールをOpenAMにサービスとして読み込ませるための設定ファイルです。
サービス名はiPlanetAMAuth か sunAMAuth で開始する必要があります。
AttributeSchemaでOpenAMの管理画面で認証モジュールが使う設定内容を定義します。
こちらを参考に以下の内容で作成しました。

4-6. src/main/resources/config/auth/default/openam/services/sample/SampleAuth.xml

ログイン画面のUI表示に使用するxmlファイルです。
通常はsrc/main/resources/config/auth/default/SampleAuth.xmlとして作成しますが、
今回はsampleというrealmで作成しますので、
こちらに従い、
src/main/resources/config/auth/default/openam/services/sample/SampleAuth.xml として作成します。

内容はこちらと同内容で作成します。

ここまで用意できればビルドを行います。

targetの下に、sample-auth-module-1.0.0.jarが作成されますので、
OpenAMが配備されたディレクトリのWEB-INF/lib配下にコピーします。

5. 独自認証モジュールをOpenAMに登録

作成した認証モジュールをOpenAMに登録するために、
ssoadmというツールをインストールする必要があります。

最初にダウンロードしたOpenAM-13.0.0.zipの中の、
SSOAdminTools-13.0.0.zipがssoadmです。

これをOpenAMサーバにアップロードして、
下記コマンドでインストールします。

インストールしたssoadmで作成した認証モジュールをOpenAMに登録します。

登録完了後、Tomcatを再起動してください。


6. OpenAMの設定

http://openam-test.example:8080/loginにアクセスして、
amAdminユーザでログインします。

まず、認証を行うレルム(一連の認証設定を管理する単位)を作成していきます。
ログインすると、OpenAMに作成されたレルム一覧が表示されます。
初期状態ではTop Level Realmが登録されています。

「New Realm」ボタンをクリックすると、
レルムの新規登録画面が表示されますので、
先ほど登録した認証モジュールはレルム名をsampleとして使う想定でしたので、
レルム名をsampleとして登録します。


 
 

6-1. sampleレルムの認証設定

sampleレルムに対して認証設定を行っていきます。

sampleレルムをAuthentication > Settingsを選択します。

まず、ユーザプロファイルタブで、
「ユーザプロファイル」を「必須」→「動的」に変更します。
ユーザプロファイル設定
 
 
OpenAMの認証フローでは、
認証後に「ユーザがOpenAMが管理するユーザデータストアに存在しているか」を必ずチェックして、存在しない場合はログイン画面にリダイレクトされてしまいます。(詳しくはこちらを参照ください。)
ID/パスワードを予めOpenAMの管理するユーザデータストアに登録しておく必要があるのですが、
上記の設定を施すことで、認証後に該当のユーザがOpenAMが管理するデータストアに存在しない場合、
OpenAMの方でユーザを作成してくれますので、認証成功したにもかかわらずログイン画面にリダイレクトされるようなことはなくなります。
外部サーバとやりとりして認証を行なうようなモジュールの場合は、ID/パスワードの事前の同期が不要になりますので、この設定が使えるのではないかと考えます。

次にセキュリティタブで、
モジュールベースの認証を無効化します。

モジュールベース認証の無効化
 
 
ポスト認証プロセスタブで、ログイン成功時に返すデフォルトの URL を「/sample/?realm=sample」に変更します。
「?realm=sample」というパラメータは、
sampleレルムに設定した認証設定でログインします、またはしたよ、という意味です。
また、ユーザーID生成モードのチェックを外します。

ポスト認証プロセス設定
 
 
次にAuthentication > Modulesから、自作した認証モジュールを追加します。

「Add Module」をクリックすると、モジュール追加画面が表示されます。
Module Nameに「SampleAuthModule」を入力、
Typeのプルダウンに先ほど作成したモジュールが「サンプル認証モジュール」として選択可能となっていますので、
それを選択します。

新モジュール追加
 
 
モジュールを追加すると、そのモジュールの設定画面に進みます。
amAuthSampleAuth.xmlで定義した設定項目が表示されます。
今回はログインユーザ名、ログインパスワードを設定できるようにしましたので、
それぞれSynergy、changeitに設定します。

モジュール設定
 
 
次に、追加した認証モジュールを必須とする新規認証連鎖を作成します。

Authentication > Chains > 「Add Chain」をクリックすると、新規認証連鎖登録画面が表示されます。
Chain Nameは「SampleAuthChain」とします。

新規認証連鎖画面
 
 
作成した認証連鎖にモジュールを追加します。
「SampleAuthModule」を選択し、条件は「Required」とします。

認証連鎖設定1
 
 
ログイン後に返すURLに「http://openam-test.example.com/sample/?realm=sample」を設定します。

認証連鎖設定2
 
 
次にさっき追加した認証連鎖を認証で使用するように設定します。

Authentication > Settings > Coreタブを選択し、
管理者認証設定、組織認証設定ともに「SampleAuthChain」を選択します。

認証コア設定
 
 


6-2. sampleレルムのエージェントの設定

次に「エージェント」の設定を行ないます。
Policy Agentにどのような振る舞いを行わせるかの設定をしていきます。

sampleレルム > Agents をクリックすると、下記画面が表示されます。
今回はApacheにPolicy Agentを組み込みますので、
Webタブを選択して、エージェントの新規ボタンをクリックします。

エージェント設定TOP

 
 
エージェント新規登録画面で、下記内容を入力して登録します。

  • 名前:openam-reverse-proxy
  • パスワード:openam02
  • サーバー URL:http://openam-test.example.com:8080/login
  • エージェント URL:http://openam-test.example.com:80

エージェント登録画面

 
 
作成したエージェントを選択して詳細設定を行っていきます。

エージェント選択

 

 
■ グローバルタブ
「SSOのみモード」の「有効」にチェックを入れます。
「SSOのみモード」というのは、Policy Agentで認証のみを行ない認可は行わない、という意味です。
どのユーザがどのリソースにアクセスできるかを制御しません。
(認可を行なう場合はポリシーの設定が必要となります。設定方法はこちらをご覧ください。)

ssoonlymode
 
 
■ アプリケーションタブ
OpenAMのセッションで管理している情報を、SSO対象アプリケーションに対するリクエストのHTTPヘッダにPolicy Agentが付与する設定をします。

セッション属性フェッチモードは「HTTP HEADER」を選択し、
セッション属性マップの設定箇所で下記内容を設定します。
左側がセッションで管理しているキー、右側がHTTPヘッダに付与するキーです。

  • [sample-username]=CUSTOM-sample-username
  • [sample-organization]=CUSTOM-sample-organization

セッション属性処理
 
 
■ OpenAMサービスタブ
ログインのURLに「?realm=sample」を付与します。

ログインURL変更

 

 
ログアウトのURLにも「?realm=sample」を付与します。
ログアウトURL変更

 

 


7. Policy Agentのインストール

Apacheに組み込むPolicy Agentをこちらからダウンロードします。

ダウンロードするためには、forgerock社へのアカウント登録・サインインが必要です。

無償ダウンロードできる最新のPolicy Agentのバージョンが4.0.0ですが、
セッション属性をHTTPヘッダにセットしてくれない不具合があるようなので、
今回はバージョン3.3.0(Apache-v2.4-Linux-64-Agent-3.3.0.zip)をダウンロードしました。

今回はリバースプロキシ方式ですので、OpenAMサーバのApache 2.4にPolicy Agentを組み込みます。
(エージェント方式であれば、SSO対象アプリケーションサーバ側にPolicy Agentを組み込む形となります。)

Apacheがインストールされていない場合は、yumでインストールします。

ダウンロードしたPolicy Agentを解凍します。

インストール前にApacheを停止しておきます。

それではPolicy Agentをインストールしていきます。

これでPolicy Agentのインストールは完了しましたが、
Policy Agentがデフォルトでトップレベルのレルムを参照する設定になっていますので、
OpenSSOAgentBootstrap.properties(私の環境では/etc/httpd/web_agents/apache24_agent/Agent_001/config/OpenSSOAgentBootstrap.properties)の下記の行を編集して、
作成したsampleというレルムを参照するように変更します。


8. リバースプロキシ設定

SSO対象のアプリケーションへのリバースプロキシの設定を行います。
OpenAMサーバのhttpd.confに以下の設定を追加します。

※ SSO対象のアプリケーションを増やす場合は、上記のLocationの設定を追加します。

ここまで完了したら、OpenAMサーバのApacheを起動します。

動作確認

実際に動作確認してみます。

まず、HTTPヘッダの内容を出力するPHPファイルを作成します。
下記内容をSSO対象アプリケーションサーバ側のApacheのドキュメントルートにindex.phpとして保存します。

では、ブラウザからhttp://openam-test.example.com/sampleにアクセスします。
Policy Agentがリクエストを検知して、OpenAMに認証されているかどうかチェックし、
認証されていないため、OpenAMのログインページにリダイレクトされます。

ログイン画面

 

※上記のログイン画面のデザインはカスタマイズ可能です。方法はこちらを参照ください。

 

OpenAMの設定画面で設定したログインユーザ名とログインパスワードを入力してログインすると、
OpenAMによって認証後、リバースプロキシ先のSSO対象アプリケーションにリダイレクトされます。

ログイン成功

 

 
HTTPヘッダの一覧が出力されており、
CUSTOM-sample-usernameとCUSTOM-sample-organizationがPolicy Agentによって付与されていることが分かります。
iPlanetDirectoryPro=xxxxというのが認証Cookieキーで、
Policy Agentはこれの有無をチェックし、有ればOpenAMに問い合わせして有効な値であるかどうかをチェックしているようです。

終わりに

長文となってしまいましたが、最後までお読みいただきありがとうございました。

OpenAMでリバースプロキシ方式のSSOを実現するための手順をざっと紹介させていただきましたが、
OpenAMは、リバースプロキシ方式以外にもSAML(Security Assertion Markup Language)やOpenID Connectに対応しており、また要件に合わせたカスタマイズも可能です。
個人的には時間があればOpenID Connectの設定も試してみたいなと思っています。

Comments are closed, but you can leave a trackback: Trackback URL.