Eclipseのショートカットが効かなくなったら

EclipseやSTSのショートカットが効かなくなったら、どのように対処すればいいでしょうか?ご存知では無い人のために、ここに記しておきます。

例えば、STSのインポートの編成(Ctrl+Shift+O)が効かなくなったとします(実際に私がそうだった…)。

そんなときは、Window > Preferences > General > keys で「Ctrl+Shift+O」で検索してみます。

1.png

ここに存在しなければ、もちろん機能しません。その場合は、「Restore Defaults」ボタンをクリックして元に戻しましょう。ここにあっても機能しない場合は、競合する別のコマンドが優先して機能してしまっています。なので、それらのコマンドに別のキーバインディングを割り当てるか、アンバインドします。

この変更を適用した後でもショートカットが効かない場合は、「Filters…」をクリックして、

2.png

「Filter uncategorized commands」などのチェックを外します。

3

こうすると、見えていなかった競合するキーバインディングが見つかるので、これも別のキーバインディングに変えましょう。

5

これでショートカットが機能するようになるはずです。

 

OpenIGのCaptureFilter利用時の注意点

OpenIG 2.1.0を利用しているシステムでCLOSE_WAITのコネクションが溜まって、応答が返らなくなるという現象があり、調査しました。

HTTPコネクションのリークの問題だろうと思い、外部システムにHTTPで通信しているClientHandlerというクラスのソースコードを見てみたところ、確かにコネクションを生成して、クローズしていません。その上、コネクションの最大数のデフォルトは64で、この値に達するとコネクションが生成できなくなり、応答が返らなくなるようでした…

/** Default maximum number of collections through HTTP client. */
private static final int DEFAULT_CONNECTIONS = 64;

ということで対策が必要です。ClientHandlerで生成してるコネクションなので、このクラスでクローズするのが適切かと思ったのですが、実際にやってみると、うまくいきません。どうもClientHandlerの後で呼ばれるFilterクラスでもコネクションを使いまわしているようで、ClientHandlerでクローズすると、Filterクラスで例外がスローされてしまいます。

さらに調べてみると、このコネクションをクローズしているのは、次の5つのFilterクラスであることが分かりました。

  • CaptureFilter
  • EntityExtractFilter
  • ExceptionFilter
  • HttpBasicAuthFilter
  • ReplaceFilter

したがって、ClientHandlerでコネクションを生成したら、これらのFilterクラスのいずれかを呼び出さないと、コネクションがリークするということになります。今回問題になっていた機能も、ClientHandlerを読んだ後に、これらのいずれも呼び出していませんでした。

この問題がなぜテスト環境では見つからなかったかというと、本番環境移行時にCaptureFilterを取り除いたことに理由があります。CaptureFilterはデバッグ目的でリクエストやレスポンスの中身を出力することができます。デバッグ時には便利なのですが、本番環境では性能面やセキュリティ面を考慮して、外すのが一般的です。このシステムでも本番環境移行時にCaptureFilterを外したところ、次の図のようにコネクションがリークしてしまったということです。

IGConnLeaks

そもそも、CaptureFilterはその名前と機能から判断すれば、ログ出力以外のことをすべきではないと考えるのが普通です(つまりCaptureFilterのバグと考えられます)。ガイドには、「Captures request and response messages for further analysis.」と書いてありますし。

ちなみにOpenIG 3.1.0から、CaptureFilterはDeprecatedになっており、代わりにCaptureDecoratorというクラスを使うことが推奨されているようです。おそらく、この問題は解決しているのではないかと思います。

TomcatのsafeToDelete.tmpの謎を追う

「TomcatのtempディレクトリにあるsafeToDelete.tmpというファイルは何ですか?」

こんな質問をされたので、少し調べてみました。

※大げさなタイトルですが、超小ネタです。

ぱっと手元にあるTomcatを確認したところ、確かに、tempディレクトリの下にはsafeToDelete.tmpという空のファイルができています。バージョン6.0でも7.0でも8.0でもこの空のファイルがあります。保存されているディレクトリ名とファイル名から判断すると、削除したところで問題が無いことは推測できるのですが、これは一体??

ということで、まずは”safeToDelete.tmp”でググってみました。が、イマイチそれらしい答えが見つからず。

まあ、Tomcatのガイドに書いてあるだろうと、今後は「safeToDelete.tmp site:tomcat.apache.org」とサイト内検索でググってみましたが、結果はゼロ。

こうなると、ソースコードを調べた方が速そうなので、「safeToDelete」でソースコード全体をgrep。すると、ヒットはしたのですが、dist.xmlに以下の1行があるだけ…

<touch file="${tomcat.dist}/temp/safeToDelete.tmp" />

dist.xmlはantでTomcatをビルドする際に読み込まれるファイルで、これをもとにantは空のファイル(safeToDelete.tmp)を作成(touch)しているだけです。作成しているものの、どこからも参照されていないこのファイルに何の意味があるのでしょうか。このファイルが作成されるようになった過去の経緯を知らないと、存在意義は分からなそうです。

ということで、いつからのこのファイルがあるのか調べてみると、Tomcat 5.0.28には入っていませんでした。Tomcat 5.5.36を調べてみると、bugzilla37035-safeToDelete.tmpというファイルがありました…あ、そゆこと…

ということで、bugzillaでid=37035を検索すると、ありました。
https://bz.apache.org/bugzilla/show_bug.cgi?id=37035

Windowsの解凍ツールWinZIPでTomcatのtar.zpファイルを解凍したときに、もともとあった空のtempディレクトリが消えてしまう、というバグ(?)でした…

WinZIPの問題であって、対策すべきではないのでは?対策の仕方も…

そして、次の疑問が。logsやworkなどの空ディレクトリはなぜ、この対策をしなかったのか?tempディレクトリはサーブレットの仕様で規定されているから?深追いするような問題では無いので、この辺りで調査は切り上げます。

EasyBuggy のトリセツ

EasyBuggyは、JavaのWebアプリケーションで起こりうる様々な問題を、非常に手軽に体験できるWebアプリケーションです。ここでいう問題とは、メモリリークやデッドロックなどの障害、SQLインジェクションやオープンリダイレクトなどの脆弱性、OutOfMemoryErrorなどのエラー、算術オーバーフロー、性能上の問題などいろいろなものが含まれます。

なぜそのようなものをつくったかというと、教育や実験に活用できると考えたからです。問題を再現させて事象を解析してみると、トラブルシューティングの方法やバグ修正の仕方を学ぶことができます。実践的に学習すると予想外な結果が出ることもあり、理由を調査して理解を深めることができます。そして、その経験があることで、実際に本番環境で問題が発生した時でも冷静に対応できるのではないかと考えます。

EasyBuggyの特徴

以下のような点にこだわって開発しました。

  • 簡単、手軽である
  • 多くの技術を使わず、基本的な技術のみを使う
  • IDE、ビルドツールと連携し、開発からデプロイまでが短時間にできる
  • サーブレットコンテナ、DB、LDAPなどを組み込み、インストールや初期設定が不要
  • 単純なパッケージ・クラス構成 (基本的に1機能 – 1サーブレットの関係)
  • デザインは最小限に (本当はこだわりたいんですが…)

スクリーンショット

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

main

バグのリンクをクリックすると、そのバグが確認できます。以下はOSコマンドインジェクションを確認できるページです。

math

java.lang.Mathを使用した数式を入力すると、計算結果が表示されるという単純な機能の中に、OSコマンドインジェクションの脆弱性があります。(i)マークで始まる説明の通り、特定の文字列を入力すると、致命的な問題が発生します。

起動方法

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

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

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

● javaコマンドで起動:

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

$ java -jar easybuggy.jar

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

$ java -Xmx256m -XX:MaxPermSize=64m -XX:MaxDirectMemorySize=90m -XX:+UseSerialGC -Xloggc:logs/gc.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 -jar easybuggy.jar

easybuggy.jarはPayara Microを組み込んでいるので、Tomcatなどのサーブレットコンテナが無くても、起動することができます。easybuggy.jarはTomcatを組み込んでいるので、サーブレットコンテナが無くても、起動することができます(バージョン1.3.0から変更しました)。

● mvnコマンドで起動:

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

$ mvn clean install exec:exec

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

mvnコマンドを実行する場合は、Payara Microではなく、組み込みのJettyサーバーが起動します。mvnコマンドを実行する場合も、組み込みのTomcatサーバーが起動します(バージョン1.3.0から変更しました)。

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

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

開発する方法

EasyBuggyはMavenのプロジェクトとして開発しているので、Eclipseで開発するためには、次のコマンドを実行します。

> mvn eclipse:eclipse

このコマンドを実行すると、Eclipseのプロジェクトに必要な .classpath や .project ファイルが作成されます。このプロジェクトをインポートすれば、Eclipseでソースコードを参照したり、改造したりすることができます。

デバッグする方法

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

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

Screenshot-Debug Configurations

注意事項

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

既知の問題と対策の方法

Javaやサーブレットコンテナのバージョンにも依存しますが、Windows上での動作で問題が出る場合があります。

● メインページにアクセスすると、内部サーバーエラーが発生する(v 1.3.0より前のバージョンでの問題):

easybuggy.jarで起動した場合、Javaのバージョンによっては、メインページにアクセスすると次のエラーが発生する場合があります。

HTTP Status 500 – Internal Server Error

org.apache.jasper.JasperException: PWC6345: There is an error in invoking javac.  A full JDK (not just JRE) is required

この場合は、JDK/binを環境変数「path」に追加し、JRE/bin/javaを実行して下さい。

> set path=%path%;C:\Program Files\Java\jdk1.8.0_121\bin
> "C:\Program Files\Java\jdk1.8.0_121\jre\bin\java" -jar easybuggy.jar

● 「Failed to delete ○○.jar」のエラーが出力されて起動できない:

mvnコマンドで起動した場合、JavaのバージョンによってはCtrl+CでもEasyBuggyのプロセスが停止しない場合があります。この場合は、起動時に次のようなエラーが出力されます。

> mvn clean install exec:exec
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building easybuggy 1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ easybuggy ---
[INFO] Deleting C:\Users\ktamura\git\easybuggy\target
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.681 s
[INFO] Finished at: 2017-03-14T09:45:18+09:00
[INFO] Final Memory: 7M/155M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-clean-plugin:2.5:clean (default-clean) on project easybuggy: Failed to clean project: Failed to delete C:\easybuggy\target\easybuggy-1-SNAPSHOT\WEB-INF\lib\xom-1.2.5.jar -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

この場合は、「JVMクラッシュ」や「コードインジェクション」のページにアクセスして、EasyBuggyのプロセスを強制的に停止させてしまうのが、手っ取り早いです 🙂 。「JVMクラッシュ」で停止させる場合は、logsディレクトリにコアダンプが出力されるので、増えてきたら削除して下さい。

V4エージェントを使うべきか

2016年の4月にバージョン4.0.0のWebエージェントがリリースされました。以前のバージョンにあったいくつかの問題に対応するため、一から実装し直しています。

リリースノートにかかれている主な新機能は以下の通りです:

  • IISのマルチサイト構成のサポート
    IISエージェントV4は、IISのマルチサイト構成に対応し、サイト毎に独自のエージェント設定が可能になっています。
  • Apacheのバーチャルホストのサポート
    ApacheエージェントV4は、Apache Webサーバー上の複数のバーチャルホストにエージェントをインストールすることができ、仮想ホスト毎に独自のエージェントの設定が可能です。
  • 権限の自動付与
    Webサーバーの実行ユーザーが書き込む必要のあるフォルダに、権限を自動的に付与することができます。
  • カスタマイズ可能な暗号化設定
    エージェントとOpenAM間の通信の暗号化の方式を詳細に設定できます。

この他に地味にうれしいのが、Javaのインストールが必要無くなったということです。以前のバージョンは、なぜかエージェントのセットアップツールがJavaで実装されていて、それだけのためのJavaをインストールしなければいけなかったのですが、これが不要になっています。

また、–s オプションでサイレントインストールがより簡単にできるようになっています。

$ ./agentadmin --acceptLicence --changeOwner --s \
  /etc/httpd/conf/httpd.conf \
  http://openam.example.co.jp:8080/openam \
  http://app.example.co.jp:80/ \
  webagent1 \
  pwd.txt

・・・

Installation complete.

ということで、今すぐアップグレードしてバージョン4.0.0のWebエージェントを使うべきか、というとまだ現時点ではお勧めはできません(ForgeRock社のサブスクリプションを購入していない場合は)。実際に動かしてみたのですが、いくつかの(致命的とも言えそうな)問題が見つかりました。JIRAを見る限り、バグも多く上がっています。動作が安定するまでまだ時間がかかるのかなぁと思っています。

 

(…とまで書いて、このブログ記事を公開するのを忘れていました…そして数ヶ月後…)2016年の12月にWebエージェント 4.1.0がリリースされました。

Webエージェント 4.1.0リリース

新しい4.1.0はどのような変更があったかというと、ここに書かれている通りです。いくつかのエンハンスがされていますが、それほど大きなものではないように思います。ただし、このバージョンで修正したバグは、リリースノートに載っているだけでも78件あります。これらの中には「メモリリーク」、「リダイレクトループ」、「クラッシュ」などの用語が見られるので、やはり4.0.0は本番環境で使用するのは避けるべきという判断は正しかったと思います。4.1.0になり、バグが大量に修正され動作は大分安定するようになったと予想しますが、まだ3.3.xなどのバージョンの方が安定しているかもしれません。

 

SonnarQubeでソースコードの品質を解析する

SonarQubeというソースコードの静的解析ツールで、OpenAMのソースコードの品質を解析してみました。セットアップは非常に簡単なので、興味のあるOSSの品質を調査してみると面白いと思います。

SonarQubeとは

SonarQubeは、ソースコードの品質を管理するオープンソースソフトウェアで、以前はSonarと呼ばれていました。以下の7つの観点でソースコードの品質を分析します:

現時点で、Java、C#、C/C++、PL/SQL、Cobol、ABAPなど20種類以上のプログラミング言語の解析が可能で、拡張メカニズムによって、新しい言語に対応することや解析ルールを追加すること、高度な統計情報を計算することもできるようです。Jenkinsと連携させて自動化するのが、一般的な利用方法だと思いますが、今回は単独で動作させます。

手順. SonarQubeをセットアップする

公式サイト(以下)に、2分間でセットアップするためのガイドがあるので、基本的にはこの通りに実施します。

Get Started in Two Minutes

なお、今回はOSにWindows 10(64bit)を使用しています。

(1) このページ内のリンクからSonarQubeをダウンロード。

以下の2つが必要です。

  • SonarQube Server: ソースコードの解析結果を表示するサーバーソフトウェア
  • SonarQube Scanner: ソースコードの解析を行うツール

(2) ダウンロードしたら、適当な場所に解凍する。

ここでは、C:\配下にsonarqubeというディレクトリを作成して、その下に解凍しています。

  • C:\sonarqube\sonarqube-6.1
  • C:\sonarqube\sonar-scanner-2.8

(3) SonarQube Serverを起動。

Windows 10(64bit)の場合は、sonarqube-6.1\bin\windows-x86-64にあるStartSonar.batを実行するだけです。が、…

C:\WINDOWS\system32>cd C:\sonarqube\sonarqube-6.1\bin\windows-x86-64

C:\sonarqube\sonarqube-6.1\bin\windows-x86-64>StartSonar.bat
wrapper  | --> Wrapper Started as Console
wrapper  | Launching a JVM...
jvm 1    | Wrapper (Version 3.2.3) http://wrapper.tanukisoftware.org
jvm 1    |   Copyright 1999-2006 Tanuki Software, Inc.  All Rights Reserved.
jvm 1    |
jvm 1    | WrapperSimpleApp: Unable to locate the class org.sonar.application.App: java.lang.UnsupportedClassVersionError: org/sonar/application/App : Unsupported major.minor version 52.0
jvm 1    |
jvm 1    | WrapperSimpleApp Usage:
jvm 1    |   java org.tanukisoftware.wrapper.WrapperSimpleApp {app_class} [app_arguments]
jvm 1    |
jvm 1    | Where:
jvm 1    |   app_class:      The fully qualified class name of the application to run.
jvm 1    |   app_arguments:  The arguments that would normally be passed to the
jvm 1    |                   application.
wrapper  |

このように、「Unsupported major.minor version 52.0」のエラーが出たら、Javaのバージョンが古いので、Java 8をインストールしましょう。OpenJDK 8のWindowsインストーラは、以下からダウンロードできます。

OpenJDK | ‘Red Hat Developers’

インストールしたら、環境変数なども設定して、javaコマンドでOpenJDK 8のjavaコマンドが実行されるようにして下さい。もしくは、以下のようにC:\sonarqube\sonarqube-6.1\confの下にあるwrapper.confを編集して下さい。

wrapper.java.command=java
  ↓
wrapper.java.command=C:\Program Files\RedHat\java-1.8.0-openjdk-1.8.0.111-1\bin\java

完了したら、再度StartSonar.batを実行します。「Process[ce] is up」が表示されたら、SonarQube Serverの起動完了です。

C:\sonarqube\sonarqube-6.1\bin\windows-x86-64>StartSonar.bat
wrapper  | --> Wrapper Started as Console
wrapper  | Launching a JVM...
jvm 1    | Wrapper (Version 3.2.3) http://wrapper.tanukisoftware.org
jvm 1    |   Copyright 1999-2006 Tanuki Software, Inc.  All Rights Reserved.
jvm 1    |
jvm 1    | 2016.11.10 21:35:47 INFO  app[][o.s.a.AppFileSystem] Cleaning or creating temp directory C:\sonarqube\sonarqube-6.1\temp
jvm 1    | 2016.11.10 21:35:47 INFO  app[][o.s.p.m.JavaProcessLauncher] Launch process[es]: C:\Program Files\RedHat\java-1.8.0-openjdk-1.8.0.111-1\jre\bin\java -Djava.awt.headless=true -Xmx1G -Xms256m -Xss256k -Djna.nosys=true -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly -XX:+HeapDumpOnOutOfMemoryError -Djava.io.tmpdir=C:\sonarqube\sonarqube-6.1\temp -javaagent:C:\Program Files\RedHat\java-1.8.0-openjdk-1.8.0.111-1\jre\lib\management-agent.jar -cp ./lib/common/*;./lib/search/* org.sonar.search.SearchServer C:\sonarqube\sonarqube-6.1\temp\sq-process3894559107684097525properties
jvm 1    | 2016.11.10 21:36:01 INFO  app[][o.s.p.m.Monitor] Process[es] is up
jvm 1    | 2016.11.10 21:36:01 INFO  app[][o.s.p.m.JavaProcessLauncher] Launch process[web]: C:\Program Files\RedHat\java-1.8.0-openjdk-1.8.0.111-1\jre\bin\java -Djava.awt.headless=true -Dfile.encoding=UTF-8 -Djruby.management.enabled=false -Djruby.compile.invokedynamic=false -Xmx512m -Xms128m -XX:+HeapDumpOnOutOfMemoryError -Djava.io.tmpdir=C:\sonarqube\sonarqube-6.1\temp -javaagent:C:\Program Files\RedHat\java-1.8.0-openjdk-1.8.0.111-1\jre\lib\management-agent.jar -cp ./lib/common/*;./lib/server/*;C:\sonarqube\sonarqube-6.1\lib\jdbc\h2\h2-1.3.176.jar org.sonar.server.app.WebServer C:\sonarqube\sonarqube-6.1\temp\sq-process4898450156161102220properties
jvm 1    | 2016.11.10 21:37:06 INFO  app[][o.s.p.m.Monitor] Process[web] is up
jvm 1    | 2016.11.10 21:37:06 INFO  app[][o.s.p.m.JavaProcessLauncher] Launch process[ce]: C:\Program Files\RedHat\java-1.8.0-openjdk-1.8.0.111-1\jre\bin\java -Djava.awt.headless=true -Dfile.encoding=UTF-8 -Xmx512m -Xms128m -XX:+HeapDumpOnOutOfMemoryError -Djava.io.tmpdir=C:\sonarqube\sonarqube-6.1\temp -javaagent:C:\Program Files\RedHat\java-1.8.0-openjdk-1.8.0.111-1\jre\lib\management-agent.jar -cp ./lib/common/*;./lib/server/*;./lib/ce/*;C:\sonarqube\sonarqube-6.1\lib\jdbc\h2\h2-1.3.176.jar org.sonar.ce.app.CeServer C:\sonarqube\sonarqube-6.1\temp\sq-process1341352410018877544properties
jvm 1    | 2016.11.10 21:37:20 INFO  app[][o.s.p.m.Monitor] Process[ce] is up

http://localhost:9000/ にアクセスすると、SonarQube Serverの画面が表示されます。

sq11

この段階では、まだ解析していないので、プロジェクトはありません。

(4) SonarQube Scannerを実行

SonarQube Serverが起動したら、SonarQube Scannerを実行してソースコードの解析を行います。解析するのは、OpenAMのソースコードにします。https://github.com/ForgeRock/openamからナイトリービルドをダウンロードして、適当なディレクトリに解凍します。今回は、C:\sonarqube以下に解凍しました。

解析を行う前に以下のページを確認して、sonar-scanner.propertiesを編集します。

http://docs.sonarqube.org/display/SONAR/Analysis+Parameters

ここでは、以下のプロパティを追加しました。

sonar.host.url=http://localhost:9000
sonar.projectKey=OpenAM14
sonar.sources=C:/sonarqube/openam-master
sonar.projectName=OpenAM14Nightly
sonar.projectVersion=14.0.0

それでは、SonarQube Scannerを実行してみましょう。ソースコードのルートディレクトリに移動して、sonar-scanner.batを実行します。

C:\sonarqube\sonar-scanner-2.8\bin>cd C:\sonarqube\openam-master

C:\sonarqube\openam-master>C:\sonarqube\sonar-scanner-2.8\bin\sonar-scanner.bat
C:\sonarqube\sonar-scanner-2.8\bin\..
INFO: Scanner configuration file: C:\sonarqube\sonar-scanner-2.8\bin\..\conf\sonar-scanner.properties
INFO: Project root configuration file: NONE
INFO: SonarQube Scanner 2.8
INFO: Java 1.8.0_111-1-redhat Oracle Corporation (64-bit)
INFO: Windows 10 10.0 amd64

  ・・・(省略)・・・

INFO: Calculating CPD for 2068 files
INFO: CPD calculation finished
INFO: Analysis report generated in 219437ms, dir size=41 MB
INFO: Analysis reports compressed in 72981ms, zip size=15 MB
INFO: Analysis report uploaded in 12057ms
INFO: ANALYSIS SUCCESSFUL, you can browse http://localhost:9000/dashboard/index/OpenAM13
INFO: Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report
INFO: More about the report processing at http://localhost:9000/api/ce/task?id=AVhOak-bSYyq1GnEMWBa
INFO: Task total time: 24:00.621 s
INFO: ------------------------------------------------------------------------
INFO: EXECUTION SUCCESS
INFO: ------------------------------------------------------------------------
INFO: Total time: 24:03.301s
INFO: Final Memory: 48M/306M
INFO: ------------------------------------------------------------------------

成功したら、再度 http://localhost:9000/  にアクセスします。画面右上の円形のマークが回転している間はSonarQubeが解析中なので、しばらく待ちましょう。

完了してからアクセスすると、解析結果が表示されます。

sq2

「ん?バグが3,800件で…脆弱性が670件?」とびっくりしてしまいますが、解析結果の詳細を見ると、Severity(重大性)が最高ランクのBlockerでも「NullPointerExceptionがスローされる可能性がある」といったもので、実際に直す必要があるかどうかはソースコードを見てみないと判断できません。

sq16

例えば、以下のようにメソッドの呼び元から渡ってくる値がnullになりえない個所での指摘だったりするので、全てが問題というわけではありません。

sq18

警告メッセージの右側の「…」となっている箇所をクリックすると、画面下部に何が問題でどのような修正すべきかも表示されます。

sq15

ちなみにEclipseやIntelliJのプラグインもあります。

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