GlassFish の JDBCレルム を利用する (ja)

前回、前々回の2回に渡ってGlassFishでBASIC認証を実現する方法を見てきました。
また、過去のエントリ「GlassFishのユーザ認証と認証レルム」(yumixさんの特別寄稿)でも触れられているように、GlassFishではいくつかの認証レルムが使用可能で、デフォルトのファイル以外にもJDBC、LDAP、Unix PAM認証機構、Solaris標準認証などを用いてユーザーを認証することができるようになっています。

今回はJDBCレルムを利用して、データベース内に格納されたユーザー情報をもとにBASIC認証を行ってみようと思います。

まず前提として、アプリケーションの要求は「GlassFishでBASIC認証を利用する(Servlet編)」と全く同じものとします。2回の連載でServlet版とJAX-RS版のサンプルを作成しました(JAX-RS版は改良版サンプルも作成しました)が、同じ動きをするものですのでどちらのサンプルをテストに使用しても構いません。

JDBCレルムを使用するには、以下の2段階の準備が必要です。
データベースにユーザー認証用のデータを作成する。
GlassFishにJDBCレルムを作成する(デフォルトでは作成されていないため)。

まず、データベースにユーザー認証用のデータを作成しましょう。今回はデータベースにOracle Database 11g R2を使用しました。SQLの違いに気を付ければ他のデータベースでも概ね同じ手順で作成できるかと思います。

-- ユーザー・テーブル
CREATE TABLE usertable (
  userid VARCHAR2(30) PRIMARY KEY,
  password CHAR(64) NOT NULL
);

-- グループ・テーブル
CREATE TABLE grouptable (
  userid VARCHAR2(30) PRIMARY KEY REFERENCES usertable (userid),
  groupid VARCHAR2(256) NOT NULL
);

-- ユーザー・テーブルの初期データ
-- サンプルのためパスワードはユーザー名と同じ値に設定している
INSERT INTO usertable VALUES ('vincent', '65c3f75641b22925c737ca657b126cd68c39e423349d43031cf9a3b9a18cee1f');
INSERT INTO usertable VALUES ('haruka', 'b2bf00ad2d766146ef0fea5f9e79113763c5364fae59bd60d3be93541601e397');
INSERT INTO usertable VALUES ('arthur', 'befa156f0283eb0062beb9b86e16a413e1cf8c5135e5518d5c4fa321ce0c7b6b');
COMMIT;

-- グループ・テーブルの初期データ
INSERT INTO grouptable VALUES ('vincent', 'sergeant');
INSERT INTO grouptable VALUES ('haruka', 'sergeant,leader');
INSERT INTO grouptable VALUES ('arthur', 'lieutenant,leader');
COMMIT;
ユーザー・テーブルとグループ・テーブルとで分けているのは正規化しているためです。重要なのはユーザーID、パスワード、グループIDを表すカラム名ですので、場合によっては1つのテーブルで実現しても構いません。
また、パスワードはSHA-256のハッシュ値(古いバージョンではMD5)を格納します。データ形式としてはHexまたはBase64のいずれかを用いることができますが、今回はデフォルトでもあるHexとしました。

パスワードのハッシュ値を自力で求めるのは骨が折れます。本格的なシステムではユーザー登録機能でハッシュ値を算出してデータベースに格納するようにすべきですが、今回は手間がかかりますので、Web上でハッシュ値を求めるサービスを利用しました。上記のデータのパスワードのハッシュ値は、このサービスで取得したものです。

ONLINE SHA1, SHA-256, SHA-384, SHA-512 HASH CALCULATOR

なお、SHA-256はデータ長が256ビット、すなわち64バイトですので、テーブルのカラムは CHAR(64) としました。

以上でデータベース側の準備は完了です。引き続き、GlassFish側の設定を行います。

GlassFish側の設定を手っ取り早く済ませるには、やはり管理コンソール(admin-gui)を利用するのが一番でしょう。管理コンソールでできることはasadminユーティリティーでもすべて実行できますし、ほとんどがREST管理チャネルを通じても行うことができます。

構成 → server-config → セキュリティ → レルム とメニューをたどり、レルムの構成画面を表示します。デフォルトではJDBCレルムは作成されていませんので、[新規...] ボタンをクリックしてレルムを作成します。設定項目は以下の通りです。


プロパティ設定値
レルム名任意 (例えば jdbc など)
クラス名com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm
JAASコンテキストjdbcRealm
JNDIjdbc/security
ユーザー・テーブルusertable
ユーザー名列userid
パスワード列password
グループ・テーブルgrouptable
グループ表ユーザー名列userid
グループ名列groupid
グループ割当て(空欄)
データベース・ユーザー(空欄)
データベース・パスワード(空欄)
ダイジェスト・アルゴリズムSHA-256
パスワード暗号化アルゴリズムdigest-algorithm
エンコーディングHex
文字セット(空欄)

JNDI以降は、今回の設定に合わせた値です。

JNDIには、ユーザー・テーブルとグループ・テーブルを読み込むために使うデータソースを指定します。必須項目ですが、デフォルトが jdbc/security とマニュアルにあります。ここはアプリケーションとは異なるデータソース(RDBMS)を認証に使用できるという理解で問題ないかと思います。

ユーザー・テーブルからグループ名列までの各項目で、ユーザー・テーブルとグループ・テーブルのデータ構造を指定します。参照するのはユーザー名列、パスワード列、グループ名列と、グループ名列をユーザー名列と別のテーブルにした場合にユーザー名(すなわち外部キー)となる列です。ユーザー・テーブルとグループ・テーブルには他の要求はありませんので、それぞれのシステムまたはアプリケーションで使いやすいように項目を自由に追加することができます。

ダイジェスト・アルゴリズムはデフォルトがSHA-256ですが、選択できる値はJava SE側のセキュリティ実装に依存します。この項目は過去のデフォルトがMD5であり、asadminからデフォルトを後方互換のMD5に変更することができます。また、過去のバージョンからのアップグレードでは、デフォルトがMD5のままになっている場合もあります。

パスワード暗号化アルゴリズムは、今回のようにSHA-256のハッシュ値を用いる場合には digest-algorithm となります。ここを空白にした上で他の項目を調整するとデータベースにパスワードを平文で格納できるのかもしれませんが、少し試した限りではうまくいかなかったのと、そもそもデータベースに平文のパスワードを格納するのは危険極まりないので、素直にSHAのハッシュ値を格納するようにしましょう。

エンコーディングの欄にはパスワードの円コーディング方法としてHexまたはBase64を入力します。デフォルトはHexで、今回の例もHexでエンコードしています。Base64の方が全体的に短くなりますが、データ次第では可変長になる場合があります。

これでJDBCレルムの設定ができますので、デフォルトレルムを作成したJDBCレルムに変更した上でリソースへのアクセスを試みてください。前回、前々回のファイルレルムと同じようにアクセス制御が行われたら成功です。