Keycloakの内部DBにアクセスするには

Keycloakの内部DBにアクセスするにはどうすればいいでしょうか?簡単なので、その方法を紹介します(※今回はKeycloakの超小ネタです)。

その前に、Keycloakの内部DBについて簡単に説明します。Keycloakには、デフォルトでH2というRDBMSが組み込まれています。Keycloakを起動すると、このDBの中にKeycloakの管理コンソールで編集可能な設定データやユーザーデータが登録されます。ユーザーデータは外部のLDAPやActive Directoryで管理することもできますが、デフォルトはここで管理されます。

内部DBへのアクセス手順

任意のSQLクライアントでアクセスできると思いますが、H2には管理コンソールが付属しているので、これを使うのが簡単です。以下のコマンドを実行すると、ブラウザ上で操作可能なH2の管理コンソールが起動します。

$ cd keycloak/modules/system/layers/base/com/h2database/h2/main/
$ java -cp h2-1.4.193.jar org.h2.tools.Console

※h2-1.4.193.jarのバージョン部分は環境に応じて、変更して下さい。

このような画面が表示されるので、

2018-03-01 20.35.51 からのスクリーンショット

以下の値を入力して、「接続」ボタンをクリックして下さい。

入力項目
保存済設定 Generic H2 (Embedded)
設定名 Generic H2 (Embedded)
ドライバクラス org.h2.Driver
JDBC URL jdbc:h2:/opt/keycloak/standalone/data/keycloak;AUTO_SERVER=TRUE
ユーザ名 sa
パスワード sa

※「JDBC URL」は、環境やKeycloak(を起動するWildFly)の起動モードにより異なります。

接続してみると、テーブルがたくさんあることが分かります。テーブル名を見て分かるように、Keycloakの管理コンソールで設定した値はこれらのテーブルで管理されることになります。

2018-02-28 22.06.10 からのスクリーンショット

ちなみにスタンドアローン・モードの場合、KeycloakのDBアクセスの定義は、standalone/configuration/standalone.xmlにあります。

広告

OpenAMはもはや「Open」ではないのか?

このブログでは、OpenAMについての記事を多く書いてきたのですが、ここ数ヶ月OpenAMの話題については触れていませんでした… というのも、OpenAMを開発しているForgeRock社が、昨年の春頃からOpenAMの公開を大幅に制限したことで、私のOpenAMに対するモチベーションが少し下がってしまったからです。

そのような状況のため、OpenAMはもはや「Open」ではないの?」と思われている方もいるかもしれませんが、そういうわけではありません。OpenAMはOSSです。このページからダウンロードして、利用することができます。CDDL 1.0ライセンスで、StashGItHubにソースコードも公開されています。

ただし、現在、ForgeRock社のサブスクリプションを購入せずに、ダウンロードサイトからダウンロードできるバージョンは、安定バージョンではないメジャーバジョンのみです(OpenAM 11.0.0/12.0.0/13.0.0、Web Agents 3.3.0/4.0.0/4.1.0、Java EE agents 3.1.0/3.3.0/3.5.0など)。また、これらのソースコードはStashに公開されていますが、一部の古いバージョンは公開されていません。安定バージョンはGitHubに公開されている11.0.3が最新です。

OpenAMの過去のメジャーバージョンのリリースは以下の通りでしたが、既に公開されていた13.5.0のソースコードも非公開となりました。

  • OpenAM 11.0.0 – 2013年11月
  • OpenAM 12.0.0 2014年12月
  • OpenAM 13.0.0 – 2016年1月
  • OpenAM 13.5.0 – 2016年7月

OpenAM 12.0.4のような安定バージョンや、新しいOpenAM 13.5.0を使用したい場合は、ForgeRock社のサブスクリプションを購入する必要があります(※私の理解が正しければ、サブスクリプションがなくても、以前ダウンロードした13.5.0のソースコードをビルドしていれば、それを利用することはできます、ただし、現在はMavenのリポジトリからOpenAM関連のライブラリが取得できないようになってしまっています…)。

OpenAM 14.0.0として開発されていたものは、「Access Management 5.0.0」という名称に変更され、2017年3月に非OSSとしてリリースされました。OpenではないAMということです。OpenAMの他にOpenDJなども同様で、以下のように「Open」が無くなり、バージョンは全て5.0.0に統一されています。

  • OpenAM 14.0.0 -> Access Manager 5.0.0
  • OpenDJ 4.0.0 -> Directory Services 5.0.0
  • OpenIDM 5.0.0 -> Identity Management 5.0.0
  • OpenIG 5.0.0 -> Identity Gateway 5.0.0

そして、このリリースは、ForgeRock社がビジネスモデルを変更したことも意味していました。もともとForgeRock社は、100%オープンソースを謳っていたんですが、100%オープンにすることのメリットよりもデメリットの方が大きいと判断したのではないかと想像しています。OpenAM(ForgeRock)が生き残るために必要な選択で、仕方なかったのかもしれません(実際のところは、私には分かりませんが)。

ForgeRock社のフォーラムに以下のようなコメントもありました。

Some ForgeRock sales reps gave me the heads up about this change, and they suggested it might have been due to integrators in Europe that create their own OpenAM releases based off the trunk which they sell themselves. I suppose this is similar to a RHEL/CentOS situation and that ForgeRock is trying to protect their investment as they are a 99% contributor of the source code, which is not the same for RHEL/CentOS.

莫大な費用をかけて、ForgeRock社がエンハンスするOpenAMを使って、何もコントリビュートしない外部の企業が利益を上げるという状況だったので、ForgeRock社とコミュニティはあまり良い関係性とは言えなかったと思います。2016年あたりから、ForgeRock社は徐々に非公開の範囲を増やしていきました。最初はマイナーバージョンのソースコードを非公開にし、ナイトリービルドのソースコードなども非公開にしていきました。そして、2017年の春には、外部のOpenAMユーザーがJIRAにバグを登録することすらできなくしました。

その当時の、OpenAMのユーザーの方とForgeRockのエンジニアであるPeterさんとの間で、以下のようなTwitterのやりとりがありました。

また、Stack Overflowでの「Is OpenAM free software?」という問いに対して、彼はこのような回答をしています。

これらの内容を要約すると、2017年4月3日以降は次のようなForgeRock版コミュニティ版に別れたことなります。

  • ForgeRock版
    • 前述の「Open」が付かない製品(Access Managerなど)
    • ソースコードは、オープンソースライセンスのもとでは提供されない
    • 使用するには、ForgeRock社のサブスクリプションを購入する必要がある
    • ForgeRockだけに属していないすべてのソースコード(例えば、Sunに属していたソースコード、またはオープンソースのコントリビューターが関わったソースコード)は、CDDLライセンスで継続して利用可能
    • 60日間のみ評価することができ
  • コミュニティ版
    • 「Open」が付く製品(OpenAMなど)
    • CDDL 1.0ライセンスのOSS
    • ソースコードはforgerock.github.ioに公開される
    • EOLとなったバージョンの最新メンテナンスリリースがForgeRock版の後にリリースされる予定
      • 今回は、AM5 -> OpenAM 11.0.3がリリースされた
      • 今後は、AM6 -> OpenAM 12.0.x、AM7 -> OpenAM 13.5.x、AM8 -> OpenAM 14.5とリリースされる予定(つまり、AMの最新バージョンがリリースされて約2年後にEOLとなってから、OpenAMとしてコミュニティ版がリリースされる)
    • 予定ではあるが、今後本当にそうなるかどうかは公言されているわけではない
    • メンテナンスリリースであるため、最初は安定しているが、その後のセキュリティパッチは提供されない

今後のOpenAMとのつきあい方

このブログを書いている際に次期バージョンがどうなるのか気になったので、Peterさんに聞いてみました。それによると、今年(2018年)の春に予定されている6.0.0リリースと同時に12.0.4もGitHubに公開される見込みだそうです(確約はできないようですが)。コミュニティ版のOpenAMが今後どのように公開されるのか不透明(というかForgeRock社次第)なので、未来のことについては明言は難しいですが、現状のOpenAMで事足りる場合は、継続してコミュニティ版を使ってもいいと考えます(脆弱性をどう対処するかによりますが)。何か困ったことがあれば、国内のOpenAMサポートをしている企業にサポートを依頼することもできます。私もサポートします。

Access Manager 5.0以降の新しい機能を使用したい場合や、脆弱性を早期に対策していきたいということであれば、ForgeRock社のサブスクリプションを購入する方がいいでしょう。ただし、結構高いです…

OpenAMのフォーク・プロジェクト

OpenAMがクローズな方向に進む中で、OpenAMをフォークしてOSSとして継続しようとする人たちも現れました。そして、このようなプロジェクトが立ち上がりました。そして、OpenAMは改名されて、GitHubに「WrenAM」という名前のOSSとして公開されました。

ただし、今のところ、このプロジェクトが軌道に乗っているようには見えません。状況をあまり把握できていないので、多くを語ることはできませんが、現時点では「うーん…」という印象です。

※注意:ライセンスなどに関して誤った理解があるかもしれません。正しい情報はForgeRock社にお問い合わせ下さい。

EasyBuggy Bootのトリセツ

「EasyBuggy Boot」は、バグだらけのWebアプリケーション「EasyBuggy」のSpring Bootベースのクローンで、JavaのWebアプリケーションで起こりうる様々な問題を、非常に手軽に体験できるWebアプリケーションです。EasyBuggyと機能的な差異はほとんどありませんが、起動方法等に若干異なる部分があります。EasyBuggyよりも新しい技術が使われており、開発やデバッグがしやすくなっています。

easybuggy

EasyBuggy Bootの特徴

基本的にはEasyBuggyと同等の機能を持っているので、用途などはこちらのページを参照下さい。「EasyBuggy」と「EasyBuggy Boot」の主な構成の相違点は以下の通りです。

相違点 EasyBuggy EasyBuggy Boot
ベースとなる技術 Servlet 3.0.1 Spring Boot 1.5.6 (Servlet 3.0.1)
プレゼンテーション層 未使用 (一部 JSP 2.2 + JSTL 1.2) Thymeleaf 2.1.5 (一部 JSP 2.3 + JSTL 1.2)
DBクライアント/サーバー JDBC / Derby 10.8.3.0 Spring JDBC 4.3.9 / Derby 10.12.1.1 (Java 7の場合)、または10.13.1.1 (Java 8の場合)
LDAPクライアント/サーバー Apache DS Client API 1.0.0 / Server 1.5.5 Spring LDAP 2.3.1 / unboundid-ldapsdk 3.2.1
メール JavaMail 1.5.1 JavaMail 1.5.1 (Spring Boot Mailで導入されるJavaMail 1.5.6をオーバーライド)
開発ツール 無し Spring Boot Developer Tools 1.5.6
Java Java 6以上をサポート Java 7以上をサポート

スクリーンショット

以下はメインページで、ブラウザの言語設定によって日本語と英語が切り替えられるようになっています。見ての通り、いろいろなバグを確認できます。

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f34333836392f34633864333931322d383736302d626363312d383834652d3465356131346536373131642e706e67

バグのリンクをクリックすると、そのバグが確認できます。

起動方法

EasyBuggyを起動して、http://localhost:8080にアクセスすると、メインページが表示されます。起動方法には次の3つがあります。

  • javaコマンドで起動
  • mvnコマンドで起動
  • warファイルをサーブレットコンテナにデプロイして起動

それぞれどのように使い分けるか説明します。

● javaコマンドで起動:

もっとも関単にEasyBuggyを起動する方法です。ROOT.warをダウンロードして、次のコマンドで起動します。

$ java -jar ROOT.war

この時、以下のようにJVMオプションを指定しておくと、問題が発生しやすく、またログを確認しやすくなります。

$ java -Xmx256m -XX:MaxMetaspaceSize=64m -XX:MaxDirectMemorySize=90m -XX:+UseSerialGC -Xloggc:logs/gc.log -Xloggc:logs/gc_%p_%t.log -XX:+PrintHeapAtGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=10M -XX:GCTimeLimit=15 -XX:GCHeapFreeLimit=50 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=logs/ -XX:ErrorFile=logs/hs_err_pid%p.log -XX:NativeMemoryTracking=summary -agentlib:jdwp=transport=dt_socket,server=y,address=9009,suspend=n -Dderby.stream.error.file=logs/derby.log -Dderby.infolog.append=true -Dderby.language.logStatementText=true -Dderby.locks.deadlockTrace=true -Dderby.locks.monitor=true -Dderby.storage.rowLocking=true -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=7900 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -ea -jar ROOT.war

● mvnコマンドで起動:

GitHubからEasyBuggy Bootをgit cloneして下さい。

$ git clone https://github.com/k-tamura/easybuggy4sb 
$ cd easybuggy4sb

その後、次のコマンドでビルドから、起動までが一気にできます。

$ mvn clean spring-boot:run

新しい機能を追加したり、ソースコードを変更して動作確認してみたい場合、このコマンドを実行すればビルドして、すぐに動作確認をすることができます。

● warファイルをサーブレットコンテナにデプロイして起動:

Tomcat以外のコンテナにもデプロイできます。ROOT.warをダウンロードして、PayaraやJettyなどにデプロイすれば、起動します。javaコマンドで起動したときと同様に、JVMオプションを指定することをお勧めします。

開発の方法

STS (Spring Tool Suite)を使用して、EasyBuggy Bootのソースコードを参照したり、開発、デバッグする方法についても載せておきます。STSはEclipseベースのIDEで、Springベースの アプリケーションの開発が簡単にできるようにカスタマイズされています。

  1. このページからSTSをダウンロードして下さい。
  2. GitHubからEasyBuggy Bootをgit cloneして下さい。
    $ git clone https://github.com/k-tamura/easybuggy4sb
    $ cd easybuggy4sb
    
  3. 以下のコマンドを実行します。このコマンドでSTSでの開発に必要なファイル(.projectファイルや.classpathファイル)が作成されます。また、依存するライブラリのソースコードも参照できます。
    $ mvn dependency:sources
    $ mvn eclipse:eclipse
    
  4. STSを起動します。
  5. パッケージエクスプローラからクローンしたプロジェクトをインポートします。「Existing Maven Projects」を選択して、「Next」をクリックして下さい。
    Screenshot-Import .png
    「Root Directory」にクローンしたプロジェクトへのパスを入力し、「Finish」をクリックします。
    Screenshot-Import Maven Projects .png
  6. パッケージエクスプローラのeasybuggy4sbプロジェクトを右クリックし、「Debug As」、「Spring Boot App」と選択すると、デバッグモードでEasyBuggy Bootが起動します。
    Screenshot-Spring - easybuggy4sb-src-main-java-org-t246osslab-easybuggy4sb-Easybuggy4sbApplication.java - Spring Tool Suite .png

ソースコードを修正すると、自動的にリロードされて、修正が反映されることも確認してみて下さい。

リモートデバッグする方法

リモートのEasyBuggy Bootをデバッグする場合は、次のデバッグ設定を追加することでデバッガーをアタッチできます。

  • Connection type: Standard (Socket Listen)
  • Host: localhost
  • Port: 9009

Screenshot-Debug Configurations

 ビルドの方法

以下のコマンドで、実行可能かつデプロイ可能なwarファイルを作成することができます。

$ mvn clean package

注意事項

OutOfMemoryError関連のリンク(特にネイティブメモリを操作するもの)をクリックすると、PCの動作が不安定になる可能性があります。CPUやメモリを制限したVM上で起動するなどしてから、自己責任でリンクをクリックして下さい。

OpenAM起動時のJVMオプションについて

OpenAMを稼働するJavaコンテナ(Tomcatなど)にJVMオプションを指定して起動していると、トラブルがあった場合でも解析ができ、原因を突き止められる可能性が高くなります。ということで、参考までにGitHubにOpenAM用のTomcat環境変数設定ファイルを公開しておきました。

k-tamura/setenv-for-openam

  • setenv.sh (Linux用)
  • setenv.bat (Windows用)

$CATALINA_HOME/bin/にコピーして、実行権限を付与しておけば、自動的に読み込まれます。

各オプションについて、簡単に説明しておきます。

JITコンパイラのタイプ

JITコンパイラはサーバーコンパイラを選択します。通常、長時間起動するアプリケーションにおいて、-clientよりも性能が高くなります。

-server

Javaヒープサイズ

OpenAM管理ガイドのチューニングのセクションに書いてある通り、組み込みOpenDJを使用する場合(デフォルト)は最低でも2GBに設定します。また、Tomcat Expertによると、この2つの値は同じにした方がいいようです。

-Xms2048m
-Xmx2048m

Permanent領域/Metaspaceのサイズ

JDK 7以前の場合はPermanent領域のサイズを、

-XX:PermSize=256m
-XX:MaxPermSize=256m

JDK 8以降の場合はMetaspaceのサイズを設定します。

-XX:MetaspaceSize=256m
-XX:MaxMetaspaceSize=256m

ForgeRock社の推奨値は、両方とも256MBです。

その他、OpenAM固有の推奨値

OpenAM管理ガイドのチューニングのセクションに書いてあったその他の推奨値を必要に応じて設定します。

-Dsun.net.client.defaultReadTimeout=60000
-Dsun.net.client.defaultConnectTimeout=30000
-Dhttps.protocols=TLSv1,TLSv1.1,TLSv1.2

GC(ガベージコレクション)

GCのアルゴリズムやログ出力について設定します。GCのアルゴリズムはいくつかありますが、OpenAM管理ガイドのチューニングのセクションに書いてある通り、CMS(Concurrent Mark Sweep)を指定します。性能面の影響は小さいので、GCログの詳細も出力するようにします。

-Xloggc:$CATALINA_HOME/logs/gc.log
-XX:+UseConcMarkSweepGC
-XX:+UseCMSCompactAtFullCollection
-XX:+CMSClassUnloadingEnabled
-XX:+PrintHeapAtGC
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=5
-XX:GCLogFileSize=10M

-XX:+PrintGCTimeStamps」を付加すると、JVMを起動してからの時間が「17.890」のようにGCログに出力されますが、見づらいので「-XX:+PrintGCDateStamps」を付加して「2017-01-13T18:34:16.743」のような日時が出力されるようにしています(後者の方がごくわずかなオーバーヘッドが発生します)。

ヒープダンプの出力

OutOfMemoryErrorが発生したときにヒープダンプを出力するようにします。

-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=$CATALINA_HOME/logs/

致命的なエラーの出力

JavaVMのクラッシュやJNIで呼び出したライブラリでのエラーなど、致命的なエラーがあった場合に、エラーファイルを出力します。この機能自体はデフォルトで有効ですが、出力先を変更したい場合は明示的に設定します。

-XX:ErrorFile=$CATALINA_HOME/logs/hs_err_pid%p.log

JFR(Java Flight Recorder)の有効化

商用利用のためにOracleのJava上でTomcatを動作させる場合は、Java Flight Recorder(JFR)も有効にします。JFRは、実行中のJavaアプリケーションに関する診断およびプロファイリングのためのデータを収集するツールです。記録中のオーバーヘッドはほとんどなく、性能面の影響は小さいので、常に有効化しておいていいと思います。

-XX:+UnlockCommercialFeatures
-XX:+FlightRecorder

JFRを有効にするには、-XX:+UnlockCommercialFeaturesオプションの追加も必要です。

 


参考

http://www.tomcatexpert.com/blog/2011/11/16/setting-measurement-garbage-collection-apache-tomcat

http://www.tomcatexpert.com/blog/2011/11/22/performance-tuning-jvm-running-tomcat

https://backstage.forgerock.com/#!/docs/openam/13/admin-guide/chap-tuning

Javaパフォーマンス Scott Oaks 著、Acroquest Technology株式会社 監訳、寺田 佳央 監訳、牧野 聡 訳


 

OpenAMの新しい監査ログについて (2)

前回は、OpenAM 13.0.0で刷新された監査ログの概要について説明しました。最新のOpenAMでは、監査ログをCSVファイルに出力したり、SyslogやElasticSearchなどへの転送ができるようになっています。詳細については以下のページを参照下さい。

OpenAMの新しい監査ログについて (1)

今回はそれらの機能の一つであるJDBC監査ロギングについて書きます。JDBC監査ロギングは、OracleやMySQLなどのRDBMSに、OpenAMの監査ログを登録(INSERT)する機能です。

まず最初に言っておくと、このJDBC監査ロギングはOpenAM 13.0.0ではまともに動作しません…(新規に開発した機能は、最初のリリースでの動作が安定しないことがありますが、この機能はちょっと酷過ぎました…)。したがって、JDBC監査ロギングを利用する場合は、13.5.0以降(14.0.0のナイトリービルド)を使うか、いくつかのバグのパッチ(以下)を適用する必要があります。

設定手順

ここでは、MySQLに監査ログを登録する設定をします。おおまかな設定手順は、以下の通りです。

  1. JDBCドライバーをlibディレクトリにコピーする
  2. MySQLに、OpenAMの監査ログ用のテーブルを作成する
  3. OpenAMの管理コンソールで監査ログの設定を追加する

もう少し詳しく説明します。

※なお、MySQLのインストールや初期設定はしてあるものとします(省略します)。

手順1. JDBCドライバーをlibディレクトリにコピーする

JDBCドライバーを次のページからダウンロードしてきます。

https://dev.mysql.com/downloads/connector/j/

ダウンロードしたら、TomcatかOpenAMのlibディレクトリにコピーして下さい。

$ cp mysql-connector-java-5.1.38-bin.jar /usr/share/tomcat7/lib/

手順2. MySQLに、OpenAMの監査ログ用のテーブルを作成する

次に、MySQLにOpenAMの監査ログ用のデータベースを作成し、適当なユーザーでOpenAMからアクセスできるようにします。

$ mysql -u root -p 
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 5.1.73 Source distribution

Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> CREATE DATABASE audit;
Query OK, 1 row affected (0.22 sec)

mysql> GRANT ALL PRIVILEGES ON audit.* TO root@'192.168.1.0/255.255.255.0' IDENTIFIED BY 'password';
Query OK, 0 rows affected (0.04 sec)

mysql> select user,host,password from mysql.user; 
+------+---------------------------+-------------------------------------------+
| user | host                      | password                                  |
+------+---------------------------+-------------------------------------------+
| root | localhost                 | *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 |
| root | openam02.example.co.jp    | *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 |
| root | 127.0.0.1                 | *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 |
| root | 192.168.1.0/255.255.255.0 | *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 |
+------+---------------------------+-------------------------------------------+
4 rows in set (0.03 sec)

完了したら、OpenAMのwarファイルの中にあるaudit.sqlを実行して、監査ログ用のテーブルを作成します。

mysql> source /var/lib/tomcat7/webapps/openam/WEB-INF/template/sql/mysql/audit.sql
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 1 row affected, 1 warning (0.00 sec)
Database changed
Query OK, 0 rows affected (0.09 sec)
Query OK, 0 rows affected (0.01 sec)
Query OK, 0 rows affected (0.01 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)

mysql> exit

手順3. OpenAMの管理コンソールで監査ログの設定を追加する

管理コンソールの 設定 > グローバル > 監査ロギング で、監査イベントハンドラのセクションの「新規」ボタンをクリックし「JDBC」を選択すると、JDBC用の監査ログを制御するハンドラが追加されます。

auditjdbcsettings1

「データベースの種類」はMySQLを選択し、「JDBCドライバー URL」から「データべースパスワード(確認)」までの項目に適切な値を入力して下さい。

auditjdbcsettings2

設定に問題がなければ、以下のように監査ログが4つのテーブルに登録されます。

audittables

大量の監査ログを捌くための仕組み

監査ログの設定後、OpenAMのログインや設定変更、ログアウトなどを行ってみると、あっという間にたくさんの監査ログレコードが登録されているのが分かります。実際の運用となり、ユーザー数が多くなると、さらに大量に登録されることになります。大量なログの高速な登録を実現するために、OpenAMは以下のような仕組みを実装しています。

afw4

ポイントとなるのは、以下の技術です。

  • 監査イベントバッファリング
  • ライタースレッド
  • ExecuteBatch()
  • HikariCP

ユーザーがOpenAMにログインしたり、自身の情報を更新すると、監査イベント(ログデータ)は、バッファ変数に一時的に保存されます(監査イベントバッファリング)。このログデータは監査ログINSERT用のSQLのプリペアドステートメントに結びつけられて、ライタースレッドによりexecuteBatch()メソッドで複数件まとめてデータベースに登録されます。

この時、データベースへのアクセスに使用しているコネクションプールのライブラリには、Commons DBCPやC3P0ではなく、HikariCPというものが使用されています。HikariCPは、軽量なJDBCコネクションプールのライブラリで、高速な処理性能を持っていることが特徴です。ただし、それだけではなく、シンプルな実装であるがゆえに信頼性や安定性も高いようです。

hikaricp-bench-2-4-0

HikariCPについて興味がある方は、以下を参照してみて下さい。

https://github.com/brettwooldridge/HikariCP

Java EEエージェントのビルド

Java EEエージェントのビルドもOpenAMサーバーと同様にmvnコマンドを実行するだけで完了します。

ビルド環境の整備

ビルドに必要なソフトウェアは、JDKとMavenです。前提ソフトウェアのバージョンについて、公式な情報は公開されていませんが、OpenAMのビルドができるバージョンを使えば問題はないはずです。

Java JDK Maven
1.7 以上 3.1.0 以上

ただし、1つ注意すべき点があります。WebSphere ASとWebLogic Server用のエージェントのビルドには、サーバーベンダーが提供する非公開のライブラリが必要です。これらの依存関係を解決するには、各サーバーソフ トウェアに含まれるライブラリを取得し、mvnコマンド実行時に参照できるようにしておく必要があります。詳細に関しては、Java EEエージェントのソースコードに添付されているreadme.mdファイルを参照してください。

手順. Java EEエージェントのビルド

まずは、ビルド用のディレクトリを作成し、そこに移動します。

$ mkdir jeeagent_build
$ cd jeeagent_build/

ソースコードはForgeRock社のBitbucketサーバー上で公開されています。ここでは、バージョン3.5.0のソースコードを圧縮したファイルをダウンロードします。

https://stash.forgerock.org/projects/OPENAM/repos/jee-agents/browse?at=refs%2Ftags%2F3.5.0

ダウンロードが完了したら、圧縮ファイルを解凍してください。

$ unzip jee-agents-master\@36016b991ff.zip 
Archive:  jee-agents-master@36016b991ff.zip
36016b991ff2aeb694a5d09e062591704f9eec45
 extracting: .gitignore              
   creating: jee-agents-agentapp/
  inflating: jee-agents-agentapp/pom.xml  

  .......

  inflating: pom.xml                 
  inflating: readme.md

解凍したら圧縮ファイルは削除します。

$ rm jee-agents-master\@36016b991ff.zip 
rm: remove 通常ファイル `jee-agents-master@36016b991ff.zip'? yes

ディレクトリ構成は、以下のようになっています。各サーバー毎のエージェントモジュールやサンプルアプリケーション(sampleapp)用のモジュールが、ディレクトリ毎に分かれて配置されています。

$ ll
合計 1828
drwxr-xr-x  3 root root    4096  9月 16 23:26 2016 jee-agents-agentapp
drwxr-xr-x  4 root root    4096  9月 16 23:26 2016 jee-agents-appserver
drwxr-xr-x 12 root root    4096  9月 16 23:26 2016 jee-agents-distribution
drwxr-xr-x  5 root root    4096  9月 16 23:26 2016 jee-agents-jboss
drwxr-xr-x  4 root root    4096  9月 16 23:26 2016 jee-agents-jetty
drwxr-xr-x  3 root root    4096  9月 16 23:26 2016 jee-agents-jsr196
drwxr-xr-x  3 root root    4096  9月 16 23:26 2016 jee-agents-library
drwxr-xr-x 15 root root    4096  9月 16 23:26 2016 jee-agents-sampleapp
drwxr-xr-x  3 root root    4096  9月 16 23:26 2016 jee-agents-sdk
drwxr-xr-x  3 root root    4096  9月 16 23:26 2016 jee-agents-tomcat
drwxr-xr-x  3 root root    4096  9月 16 23:26 2016 jee-agents-weblogic
drwxr-xr-x  4 root root    4096  9月 16 23:26 2016 jee-agents-websphere
drwxr-xr-x  2 root root    4096  9月 16 23:26 2016 legal
-rwxr-xr-x  1 root root   33221  9月 16 23:26 2016 pom.xml
-rw-r--r--  1 root root    2097  9月 16 23:26 2016 readme.md
$

全体のpom.xmlがあるので、ここでmvnコマンドを実行すれば、ビルドが開始されますが、前述した商用のサーバーのライブラリが存在しないの で、ビルドエラーとなってしまいます。Tomcatエージェントだけをビルドしたいということでれば、以下のようにpom.xmlを編集し、Tomcat以外のサーバー用のmoduleタグをコメントアウトすればビルドできるようになります。

    <modules>
        <module>jee-agents-sdk</module>
        <module>jee-agents-library</module>
        <module>jee-agents-agentapp</module>
        <module>jee-agents-tomcat</module>
<!-- ここから
        <module>jee-agents-jboss</module>
        <module>jee-agents-jetty</module>
        <module>jee-agents-appserver</module>
        <module>jee-agents-weblogic</module>
        <module>jee-agents-websphere</module>
        <module>jee-agents-jsr196</module>
ここまでコメントアウト -->
        <module>jee-agents-sampleapp</module>
        <module>jee-agents-distribution</module>
    </modules>

mvn clean installコマンドでビルドを実行します。テストを省略する場合は、-DskipTests=trueオプションを付加してください。

$ mvn -DskipTests=true clean install
[INFO] Scanning for projects...
[WARNING] 

  .......

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1:00.510s
[INFO] Finished at: Sun Sep 25 09:42:15 JST 2016
[INFO] Final Memory: 64M/349M
[INFO] ------------------------------------------------------------------------

数分で、ビルドは完了します。jee-agents-distribution/jee-agents-distribution-tomcat- v6/target/以下に、Tomcatエージェントの圧縮ファイル(tomcat_v6_agent_4.0.0-SNAPSHOT.zip)が作成 されているはずです。

$ ll jee-agents-distribution/jee-agents-distribution-tomcat-v6/target/
合計 33888
drwxr-xr-x 2 root root     4096  9月 25 09:41 2016 archive-tmp
-rw-r--r-- 1 root root       27  9月 25 09:41 2016 build_date.js
-rw-r--r-- 1 root root 34692736  9月 25 09:41 2016 tomcat_v6_agent_4.0.0-SNAPSHOT.zip

OpenAMをRESTでセットアップする

OpenAMのJIRAを眺めていたら、RESTでOpenAMの初期設定(セットアップ)をすることができることに気付きました。OpenAMのwarファイルをサーブレットコンテナにデプロイして、以下のようにURL エンコードした各種パラメータを/openam/config/configuratorエンドポイントにPOSTすると、数秒後に初期設定が完了します。

# curl --request POST "http://openam.example.com:8080/openam/config/configurator" \
 --header "Content-Type:application/x-www-form-urlencoded" \
 --data-urlencode "SERVER_URL=http://openam.example.com:8080" \
 --data-urlencode "DEPLOYMENT_URI=openam" \
 --data-urlencode "BASE_DIR=/opt/tomcat7/openam" \
 --data-urlencode "locale=en_US" \
 --data-urlencode "PLATFORM_LOCALE=en_US" \
 --data-urlencode "ADMIN_PWD=p@s2word" \
 --data-urlencode "ADMIN_CONFIRM_PWD=p@s2word" \
 --data-urlencode "AMLDAPUSERPASSWD=Passw0rd" \
 --data-urlencode "AMLDAPUSERPASSWD_CONFIRM=Passw0rd" \
 --data-urlencode "COOKIE_DOMAIN=.example.co.jp" \
 --data-urlencode "DATA_STORE=embedded" \
 --data-urlencode "DIRECTORY_SSL=SIMPLE" \
 --data-urlencode "DIRECTORY_SERVER=localhost" \
 --data-urlencode "DIRECTORY_PORT=50389" \
 --data-urlencode "DIRECTORY_ADMIN_PORT=4444" \
 --data-urlencode "DIRECTORY_JMX_PORT=1689" \
 --data-urlencode "ROOT_SUFFIX=dc=openam,dc=forgerock,dc=org" \
 --data-urlencode "DS_DIRMGRDN=cn=Directory Manager" \
 --data-urlencode "DS_DIRMGRPASSWD=p@s2word" \
 --data-urlencode "acceptLicense=true"

Configuration complete!

GUIを使うと入力の手間やミスがあるので、動作検証などで何回もセットアップするような場合にこの方法は便利です。設定ツール(openam-configurator-tool.jar)を使って、同様にサイレントインストールをすることもできますが、設定ツールはダウンロードとインストールをしないといけないので、RESTの方が少しだけ簡単にできます。

ただし、この方法は今のことろOpenAMのインストールガイドにも載っていない、非公式なもののようです。初期化処理の途中経過が分からない点や例外処理が弱い点も考慮して、非公式のままにしているのだと思います。エラーレスポンスもスタックトレース付きのHTML形式で返ってきていました…

# curl --verbose --request POST "http://openam.example.com:8080/openam/config/configurator" \
 --header "Content-Type:application/x-www-form-urlencoded" \
 --data-urlencode "SERVER_URL=http://openam.example.com:8080" \
 --data-urlencode "DEPLOYMENT_URI=openam" \
 --data-urlencode "BASE_DIR=/opt/tomcat7/openam" \
 --data-urlencode "locale=en_US" \
 --data-urlencode "PLATFORM_LOCALE=en_US" \
 --data-urlencode "ADMIN_PWD=p@s2word" \
 --data-urlencode "ADMIN_CONFIRM_PWD=p@s2word" \
 --data-urlencode "AMLDAPUSERPASSWD=p@s2word" \
 --data-urlencode "AMLDAPUSERPASSWD_CONFIRM=p@s2word" \
 --data-urlencode "COOKIE_DOMAIN=.example.co.jp" \
 --data-urlencode "DATA_STORE=embedded" \
 --data-urlencode "DIRECTORY_SSL=SIMPLE" \
 --data-urlencode "DIRECTORY_SERVER=localhost" \
 --data-urlencode "DIRECTORY_PORT=50389" \
 --data-urlencode "DIRECTORY_ADMIN_PORT=4444" \
 --data-urlencode "DIRECTORY_JMX_PORT=1689" \
 --data-urlencode "ROOT_SUFFIX=dc=openam,dc=forgerock,dc=org" \
 --data-urlencode "DS_DIRMGRDN=cn=Directory Manager" \
 --data-urlencode "DS_DIRMGRPASSWD=p@s2word" \
 --data-urlencode "acceptLicense=true"

* About to connect() to openam.example.com port 8080 (#0)
* Trying 172.105.126.221... connected
* Connected to openam.example.com (172.105.126.221) port 8080 (#0)
> POST /openam/config/configurator HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.13.1.0 zlib/1.2.3 libidn/1.18 libssh2/1.2.2
> Host: openam.example.com:8080
> Accept: */*
> Content-Type:application/x-www-form-urlencoded
> Content-Length: 572
>
< HTTP/1.1 500 Internal Server Error
< Server: Apache-Coyote/1.1
< Content-Type: text/html;charset=utf-8
< Content-Language: en
< Content-Length: 2474
< Date: Thu, 25 Aug 2016 05:58:34 GMT
< Connection: close
<
<html><head><title>Apache Tomcat/7.0.57 - Error report</title><style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style> </head><body><h1>HTTP Status 500 - AMSetupFilter.doFilter</h1><HR size="1" noshade="noshade"><p><b>type</b> Exception report</p><p><b>message</b> <u>AMSetupFilter.doFilter</u></p><p><b>description</b> <u>The server encountered an internal error that prevented it from fulfilling this request.</u></p><p><b>exception</b> <pre>javax.servlet.ServletException: AMSetupFilter.doFilter
com.sun.identity.setup.AMSetupFilter.doFilter(AMSetupFilter.java:141)
org.forgerock.openam.audit.context.AuditContextFilter.doFilter(AuditContextFilter.java:51)
</pre></p><p><b>root cause</b> <pre>com.sun.identity.setup.ConfiguratorException: Default Agent Password cannot be the same as Administrator password.
com.sun.identity.setup.ServicesDefaultValues.validateURLAccessAgentPassword(ServicesDefaultValues.java:443)
com.sun.identity.setup.ServicesDefaultValues.validatePassword(ServicesDefaultValues.java:353)
com.sun.identity.setup.ServicesDefaultValues.setServiceConfigValues(ServicesDefaultValues.java:125)
com.sun.identity.setup.AMSetupServlet.processRequest(AMSetupServlet.java:466)
com.sun.identity.setup.AMSetupServlet.doPost(AMSetupServlet.java:439)
javax.servlet.http.HttpServlet.service(HttpServlet.java:646)
javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.forgerock.openam.validation.ResponseValidationFilter.doFilter(ResponseValidationFilter.java:44)
com.sun.identity.setup.AMSetupFilter.doFilter(AMSetupFilter.java:125)
org.forgerock.openam.audit.context.AuditContextFilter.doFilter(AuditContextFilter.java:51)
* Closing connection #0
</pre></p><p><b>note</b> <u>The full stack trace of the root cause is available in the Apache Tomcat/7.0.57 logs.</u></p><HR size="1" noshade="noshade"><h3>Apache Tomcat/7.0.57</h3></body></html>