hatenob

プログラムって分からないことだらけ

Wildfly 8でJAAS

Wildfly8でJAASの動きを確認した時のメモ。

JAAS

Java Authentication and Authorization ServiceはJavaの認証認可機構のこと。
ユーザとロールを紐づけ、そのロールでアクセスできるURLやらEJBやらを制御することができるもの。
認証方式はいくつか取れるが、一番一般的と思われるFORM認証(ログイン画面で認証するパターン)でやってみる。
ユーザ情報とロール情報はDBに入れておくことにする。
で、内容はほぼほぼ下記のコードを参考にさせてもらいました。

yoshioterada/JDBC-Realm-Sample · GitHub

Wildflyでやるときは

standalone.xml

standalone.xmlに下記の定義を入れてやります。

<subsystem xmlns="urn:jboss:domain:security:1.2">
  <security-domains>
  (....)
    <security-domain name="jdbc-realm" cache-type="default">
      <authentication>
        <login-module code="Database" flag="required">
          <module-option name="dsJndiName" value="java:jboss/mydatasource"/>
          <module-option name="principalsQuery" value="select password from Usertable where username = ?"/>
          <module-option name="rolesQuery" value="select groupid, 'Roles' from Grouptable where username = ?"/>
          <module-option name="hashAlgorithm" value="SHA-256"/>
          <module-option name="hashEncoding" value="HEX"/>
        </login-module>
      </authentication>
    </security-domain>
  </security-domains>
</subsystem>

オプションは見たままです。

dsJndiName パスワードとロールを取得する際に使うデータソースのJNDI名。
principalsQuery ユーザのパスワードを取得するSQL
rolesQuery ユーザのロールを取得するSQL複数可。
hashAlgorithm パスワードのハッシュ値を得るアルゴリズム
hashEncoding パスワードのハッシュ値エンコーディング

jboss-web.xml

これを入れただけではダメなので、jboss-web.xmlに下記を書きます。

<jboss-web>
  <security-domain>jdbc-realm</security-domain>
</jboss-web>

security-domainに指定しているのは、先のstandalone.xmlで定義した際のsecurity-domainのnameのところです。
Webで調べていると、「jboss:jaas//」という書き方が出てきますが、Wildfly8ではこの書き方をすると起動時にエラーになりました。なので上の通り、プリフィックスがない状態で大丈夫なようです。

動作確認

あとは参考のコードをほぼそのままでいけると思います。
ただし、web.xmlの記述部分は少し変えまして、ログイン画面事態は認証不要にしました。

  <security-constraint>
    <display-name>Authorized Resource</display-name>
    <web-resource-collection>
      <web-resource-name>protected-page</web-resource-name>
      <description>Display after logged in</description>
      <url-pattern>/faces/home/*</url-pattern>
      <http-method>GET</http-method>
      <http-method>POST</http-method>
    </web-resource-collection>
  (....)

具体的には、url-patternのところ、元のは「/faces/login/*」となっていたのを、ログイン画面「/faces/login/*」と、ログイン後画面「/faces/home/*」とを別々にして、ログイン後画面にだけ認証が必要にしたということです。
元のままだと、なぜかログイン画面にあるログインボタンが効かなかった(loginメソッドが呼ばれなかった)からでして、一度押した後にブラウザの戻るボタンで戻るとその時にloginメソッドが呼ばれるというなんとも不思議な挙動をしました。
最初、commandButtonが効かないのかな?JSFのコードに間違いがあるのかな?と色々と試していましたが、ひとまずこれで回避できたのでよしとしました。

所感

URLやEJBレベルの認証認可に関する処理をわざわざ書かなくてもよいのはよいなぁと思いつつ、ロールの定義をweb.xmlに書かないといけないところを考えると、サンプルのような「ログインしたかどうか」程度や単体のアプリケーションのちょっとした権限制御には使えるにしても、細かな権限制御は難しそうな印象。それなら権限マスタを外だしして全アプリケーションから参照できるような仕組みにしたほうがよいだろうなぁと思いました。