Java EE  Detail of JDBC-Realm
 

Java EE Detail of JDBC-Realm

on

  • 7,770 views

This contents explains the detail of JDBC realm.

This contents explains the detail of JDBC realm.

Statistics

Views

Total Views
7,770
Views on SlideShare
2,084
Embed Views
5,686

Actions

Likes
2
Downloads
90
Comments
2

13 Embeds 5,686

http://yoshio3.com 5575
http://www.feedspot.com 33
http://feedly.com 29
http://yoshio3.com.preview.shareboost.com 13
http://translate.googleusercontent.com 12
https://yoshio3.com 6
http://webcache.googleusercontent.com 5
http://yoshioterada.wordpress.com 4
http://s.deeeki.com 3
http://www.tumblr.com 2
https://twitter.com 2
http://reader.aol.com 1
https://reader.aol.com 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
  • @kawaba ありがとうございます。その通りでございます。
    Are you sure you want to
    Your message goes here
    Processing…
  • 18ページ目の「JavaEE7のデフォルト設定(annotated)は、@Namedのアノテーションが付加されたCD(のみがインジェクション可能で」の部分について、これまで@Namedだけでなく、スコープアノテーション(Bean定義アノテーション)のどれかを付ければよい、と理解していたのですがどうでしょう。
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Java EE  Detail of JDBC-Realm Java EE Detail of JDBC-Realm Document Transcript

  • GlassFish v4 ではじめる Java EE JDBC レルム ハンズオン・ラボ Version 1.0 Yoshio Terada, Java Evangelist http://yoshio3.com, @yoshioterada
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   Table of Contents 1.0 はじめに  .............................................................................................................  3   2.0 NetBeans と GlassFish の動作確認  ............................................................  6   3.0 アプリケーションの設定  ................................................................................  11   3.1 : Maven プロジェクトの設定  ..............................................................................................  11   3.2 : JavaServer Faces の有効化  ............................................................................................  15   3.3 : Contexts and Dependency Injection の設定  ....................................................  18   3.4 : GlassFish のリクエスト・エンコーディングの修正  ............................................  21   4.0 ユーザ・グループの登録・削除画面の作成  ...................................................  25   4.1 データベースにテーブルを作成  ..........................................................................................  26   4.2 JPA のエンティティを作成  ...................................................................................................  28   4.3 ユーザ管理用の Enterprise JavaBeans の作成  .......................................................  36   4.4 CDI (JSF 管理対象 Bean)の作成  .......................................................................................  42   4.5 ユーザ管理用 Web ページ(JSF Facelets)の作成  .....................................................  49   4.6 ユーザ登録・削除アプリケーションの実行  ..................................................................  55   5. アプリケーションに対するアクセス制限:認証・認可  ..................................  60   5.1 ログイン用の JSF ページと JSF 管理対象 Bean の作成  .......................................  62   5.2 GlassFish における JDBC レルムの設定と実装  .......................................................  72   5.3 認証設定、認証コードの実装、動作確認  .......................................................................  78   5.4 細かいカスタマイズ  ...................................................................................................................  88   5.5 処理単位でのアクセス制限方法  ..........................................................................................  97   Appendix.1  .........................................................................................................  105   pom.xml  の設定内容  .........................................................................................................................  105     2  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   1.0 はじめに Java EE では標準で認証・認可を扱うための機能が標準で備わっています。 Java EE の各コンポーネントに対するセキュリティはコンテナ(Web コンテナ、 EJB コンテナなど)で提供され、XML やアノテーションによる宣言的なセキュリ ティの他、プログラム上でセキュリティを実装することもできます。このハンズ オン・ラボでは Java EE 6 の Servlet 3.0 で新しく追加された login, logout メ ソッドを JavaServer Faces 内で使用し、データベースのユーザ・テーブルに 存在するユーザとの認証、グループ・テーブルに設定されたユーザの役割(ロー ル)に応じてアクセス権限を与える認可処理のそれぞれを実装します。   図  1: 認証 アプ リケ ー ショ ンの 完成 イ メー ジ   本ハンズオン・ラボは Java EE 7 環境上で実装しますが、Java EE 6 の環境 (GlasFish v3.x)でも同様に実施することが可能です。 • • • • • Servlet 3.0 以上 JavaServer Faces 2.0 以上 Contexts and Dependency Injection 1.0 以上 Java Persistence API 2.0 以上 Enterprise JavaBeans 3.1 以上 本ハンズオン・ラボで作成する全ソースコードは下記より参照可能です。 https://github.com/yoshioterada/JDBC-Realm-Sample   3  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   必須ソフトウェア l                                                                                       最新の JDK 7 を入手してください。 http://www.oracle.com/technetwork/java/javase/downloads/in dex.html 図  2:JDK の ダウ ンロ ード 4  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   l NetBeans 7.4 以降を入手してください。NetBeans のダウンロード サイトより「Java EE」もしくは「すべて」のパッケージを選択し 「ダウンロード」ボタンを押下してください。「Java EE」、「すべ て」を選択した場合、本ハンズ・オンの動作に必要な GlassFish v4 がバンドルされています。 http://netbeans.org/downloads/ 図  3:NetBeans  の ダウ ンロ ード 画 面     5  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   2.0 NetBeans と GlassFish の動作確認 NetBeans をインストールしたのち、アイコンをダブル・クリックして NetBeans を起動してください。起動すると下記の画面が表示されます。 図  4: NetBeans  の 起動 画面   ここで、NetBeans と GlassFish が正しく連携できているかを確認するため、 新しくプロジェクトを作成してください。メニューから「ファイル (F)」→ 「新規プロジェクト(W)...」を選択してください。 図  5: 新規 プロ ジェ ク トの 作成   6  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   「新規プロジェクト(W)...」を選択すると下記のウィンドウが表示されます。 「カテゴリ(C) :」より「Maven」を選択し、「プロジェクト(P):」より 「Web アプリケーション」を選択し「次へ >」ボタンを押下してください。 図  6: 新規  Maven  プ ロジ ェク ト作 成     ボタンを押下すると下記のウィンドウが表示されます。ここで「プロジェク ト名(N) :」に「WebSocket-Mailer」と入力し、「グループ ID(G):」に 「jp.co.oracle」と入力し「次 >」ボタンを押下してください。 図  7: 新規  Web  ア プリ ケー ショ ン   7  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   「次 >」ボタンを押下すると下記のウィンドウが表示されます。「終了(F)」 ボタンを押下してください。 図  8: 新規  Web  ア プリ ケー ショ ン 終了ボタンを押下すると下記のウィンドウが表示されます。   図  9: 新規 プ ロ ジェ クト の作 成   8  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   ここで、プロジェクトを実行してください。「WebSocket-Mailder」プロ ジェクトを右クリックし、「実行」を選択してください。 図  10: プロ ジェ クト の 実行 もしくは、NetBeans のメニューより「実行ボタン」を押下してください。   図  11: プロ ジェ クト の 実行 プロジェクトを実行すると、ブラウザが自動的に起動され下記の画面が表示 されます。下記の画面がブラウザ上で表示されている場合、アプリケーショ ン開発環境が正しく構築されています。   9  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4     開発環境の動作確認ができましたので、次章より実際にアプリケーションの 開発を始めていきます。 図  12: アプ リケ ーシ ョ ンの 動作 確認   10  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   3.0 アプリケーションの設定   本章では、アプリケーションの各種設定を行います。 3.1 : Maven プロジェクトの設定 本プロジェクトは Apache Maven のプロジェクトとして作成しました。 Maven は Apache Ant に代わる、プロジェクト管理ツールとして幅広く採 用されており、今回開発に使用する NetBeans をはじめ、他のメジャーな統 合開発環境で利用できるようになっています。Maven プロジェクト1の構成 を管理するためには、POM(Project Object Model)ファイルを編集して 行います。 左ペインの「プロジェクト」より、「WebSocket-Mailer」→「プロジェク ト・ファイル」→「pom.xml」を選択しダブルクリックしてください。 図  13:pom.xml  の 選択 ファイルをダブル・クリックし選択すると、右ペインに下記のウィンドウが 表示されます。                                                                                                                 1  本ハンズオンでは Apache Maven に関する説明は省略します。Maven に関する詳細を把 握したい場合、別途 http://maven.apache.org/ より情報を入手してください。   2  ここでご紹介する内容は Java EE 6, Java EE 7 共通です。   3  以前は MD5 を指定する事がありましたが、今はセキュリティの観点で MD 5 は非推奨で、   11  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   図  14: デフ ォル トで 作 成さ れる pom.xml フ ァイ ル ここで、pom.xml に対して下記の設定を追加してください。 本プロジェクトでは、PrimeFaces 4.0 で提供されている JSF コンポーネン トを使用します。PrimeFaces 4.0 を利用できるように下記の設定を追加し てください。 <repositories> <repository> <id>prime-repo</id> <name>PrimeFaces Maven Repository</name> <url>http://repository.primefaces.org</url> <layout>default</layout> </repository> </repositories> <dependencies> ……(既存の設定) <dependency> <groupId>org.primefaces</groupId> <artifactId>primefaces</artifactId> <version>4.0</version> </dependency> </dependencies>   12  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   次に Java EE 7 の Web アプリケーション内で Concurrency Utilities for EE (Web Profile に含まれない機能)を利用できるように「artifactId」の箇 所を「javaee-web-api」から「javaee-api」に修正してください。 <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>7.0</version> <scope>provided</scope> </dependency> ※ 設定内容の詳細は「Appendix1 : pom.xml   の設定内容」をご参照ください。 pom.xml ファイルに対して設定を追加・編集を行なった後、ファイルを保存 してください。NetBeans のメニューより「ファイル(F)」→「保存(S)」を 選択してください。 図  15:pom.xml フ ァイ ルの 保存   13  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   図  16: 依存 性で ビル ド 図  17: プロ パテ ィの 編 集   「図   16:依存性でビルド」に従いファイルを保存した後、「依存性でビルド」 を実行してください。すると指定した Maven のリポジトリより必要なファ イルを自動的に取得します。       14  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   3.2 : JavaServer Faces の有効化 次にプロジェクト内で JavaServer Faces を利用できるように、プロジェク トにフレームワークの追加を行ないます。「図  17:プロパティの編集」に従 い「プロジェクト」→「WebSocket-Mailer」を選択した後、右クリックし 「プロパティ」を選択してください。選択すると下記のウィンドウが表示さ れます。 図  18: プロ ジェ クト ・ プロ パテ ィ設 定 画面 ここで、「カテゴリ(C)」より「フレームワーク」を選択し、「追加(A)...」 ボタンを押下してください。押下すると「フレームワークの追加」ウィンド ウが表示されますので、ここで「JavaServer Faces」を選択し「OK」ボタ ンを押下してください。 図  19: JavaServer  Faces の 追加   15  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   ボタンを押下すると下記のウィンドウが表示されます。最後に「OK」ボタン を押下してください。 図  20: プロ ジェ クト ・ プロ パテ ィ ボタンを押下するとプロジェクト内に「WEB-INF」ディレクトリ、 「web.xml」ファイル、「index.xhtml」ファイルが自動的に追加されます。 「web.xml」ファイルを選択しダブル・クリックすると下記の設定内容を確 認できます。 図  21:JSF フ レー ムワ ーク 追 加と web.xml フ ァイ ル ※今回作成するアプリケーションは、メール参照アプリケーションで長時間 動作するアプリケーションのため、必要に応じて<session-timeout>の値を 変更してください。デフォルトは 30 分が指定されています。   16  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   ここで、プロジェクト作成時に自動生成された「index.html」ファイルは不 要になりましたので削除してください。対象の「index.html」ファイルを選 択し右クリックしてください。右クリックすると下記のようにメニューが表 示されますので「削除 Delete」を選択してください。 図  22:index.html  フ ァイ ルの 削除 選択すると下記の確認ダイアログが表示されますので、「はい」を押下して ください。 図  23:index.html フ ァイ ル削 除確 認 ダイ アロ グ   17  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   3.3 : Contexts and Dependency Injection の設定 次に Contexts and Dependency Injection (移行 CDI)の設定を行ないます。 Java EE 6 では、WEB-INF もしくは、META-INF ディレクトリ配下に 「beans.xml」と名付けられたファイルを作成することで CDI が有効になり ました。Java EE 7 からは「beans.xml」ファイルを作成しなくてもデフォ ルトで CDI が有効になりました。しかし Java EE 7 のデフォルトの設定 (annotated)は、@Named のアノテーションが付加された CDI のみがイン ジェクション可能で、@Named 以外のアノテーションが利用不可となって います。そこで@Named 以外のアノテーションでもインジェクションがで きるようにデフォルトの設定を変更します。 プロジェクトより「WebSocket-Mailer」→「新規」→「その他...」を選択 してください。選択すると下記のウィンドウが表示されます。                                 図  24:CDI  の デフ ォル ト設 定 を変 更               18  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   ここで、「カテゴリ(C)」より「コンテキストと依存性」を選択し、「ファイ ル・タイプ(F):」より「beans.xml (CDI 構成ファイル)」を選択し「次 >」ボ タンを押下してください。                                   図  25: beans.xml 構 成フ ァイ ル作 成     ボタンを押下すると下記のウィンドウが表示されます。ここではそのまま 「終了(F)」ボタンを押下してください。                                     図  26:beans.xml 構 成フ ァイ ルの 作 成           19  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   「終了(F)」ボタンを押下すると下記のファイルが作成されます。 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd" bean-discovery-mode="annotated"> </beans> ここで「beans-discovery-mode」の値を「annotated」から「all」に修正 してください。 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd" bean-discovery-mode="all"> </beans> 修正した後、ファイルを保存してください。NetBeans のメニューより「フ ァイル(F)」→「保存(S)」を選択してください。                               図  27:beans.xml の 設定 を保 存 20  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   3.4 : GlassFish のリクエスト・エンコーディングの修正 次に GlassFish のリクエスト・エンコーディングの修正を行ないます。 GlassFish はパラメータのエンコーディングにデフォルトで ISO-8859-1 が 使用されます。そこで日本語環境においては文字化けが発生しますので、パ ラメータのエンコーディングを ISO-8859-1 から UTF-8 に変更します。 プロジェクトより「WebSocket-Mailer」→「Web ページ」→「WEB-INF」 ディレクトリを選択し右クリックした後「その他...」を選択してください。                   図  28: GlassFish の デフ ォル ト・ エ ンコ ーデ ィン グ の修 正 選択すると下記のウィンドウが表示されます。ここで「カテゴリ(C):」より 「GlassFish」を選択し「ファイル・タイプ(F):」より「GlassFish ディスク リプタ」を選択し「次 >」ボタンを押下してください。                                     図  29:GlassFish デ ィス クリ プタ の 作成       21  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   ボタンを押下すると下記のウィンドウが表示されます。そのまま「終了(F)」 ボタンを押下してください。 図  30:GlassFIsh デ ィス クリ プタ の 作成 終了ボタンを押下すると下記の画面が表示されます。ここで「XML」ボタン を押下してください。 図  31: GlassFish デ ィス クリ プタ の 作成   22  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   「XML」ボタンを押下すると下記の画面が表示されます。 図  32: glassfish-­‐web.xml の 内容     ここで、設定ファイル内に「<parameter-encoding defaultcharset="UTF-8" />」の1行を追加してください。   <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd"> <glassfish-web-app error-url=""> <class-loader delegate="true"/> <jsp-config> <property name="keepgenerated" value="true"> <description>Keep a copy of the generated servlet class' java code.</description> </property> </jsp-config> <parameter-encoding default-charset="UTF-8" /> </glassfish-web-app>       23  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   修正した後、ファイルを保存してください。NetBeans のメニューより「フ ァイル(F)」→「保存(S)」を選択してください。                         図  33: glassfish-­‐web.xml フ ァイ ルの 保存   24  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   4.0 ユーザ・グループの登録・削除画面の作成 それでは、実際にアプリケーションの開発を行なっていきます。2 まず、最初に作成する Web アプリケーションは、ユーザとグループを登 録・削除するアプリケーションです。「ユーザ情報登録画面」に「ユーザ 名」、「メールアドレス」、「パスワード」、「所属グループ」を入力し 「ユーザ登録」ボタンを押下し、データベースに情報を登録します。登録す る情報は、事前にデータベース内に作成したテーブル「USERTABLE」、 「GROUPTABLE」に対して行います。また、この際、登録画面に入力され たパスワードは、SHA-256 のメッセージ・ダイジェスト3に変換し保存しま す。 また「ユーザ情報削除画面」には登録した「ユーザ名」を指定し、「ユーザ 削除」ボタンを押下すると該当するユーザを削除します。 図  34: ユー ザ情 報登 録 ・削 除ア プリ ケ ーシ ョン                                                                                                                 2  ここでご紹介する内容は Java EE 6, Java EE 7 共通です。   3  以前は MD5 を指定する事がありましたが、今はセキュリティの観点で MD 5 は非推奨で、 SHA-256 が推奨です。より強度の高い Salted SHA(SSHA)を使用したい場合は、独自のカ スタム・レルムを作成する必要があります。SSHA を利用する場合は下記の URL をご参照 ください。http://blog.eisele.net/2012/07/glassfish-jdbc-security-with-salted.html   25  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   4.1 データベースにテーブルを作成 まず、認証するユーザとユーザが持つ役割を保持するデータベースのテーブ ルを作成します。今回は GlassFish に組み込みの JavaDB (Derby) にテー ブルを作成します。JavaDB 付属コマンドである ij コマンドを使用して作成 するか、もしくは NetBeans の「コマンドの実行 …」からコマンドを実行 することもできます。 今回、簡単に実行するため、NetBeans から SQL コマンドを実行します。 「サービス」タブから「データベース」→ 「jdbc:derby://localhost:1527/sample」を選択しデフォルトで作成され ているデータベース「APP」を選択し右クリックしてください。 図  35:NetBeans  か ら SQL コ マン ドの 実行   右クリックすると上記のメニューが表示されます。ここで「コマンドの実行 …」を選択してください。選択すると下記の画面が表示されます。 図  36: NetBeans か ら SQL  コ マン ドの 実行     26  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   元々何も入力されていません。そこで下記 SQL 文を入力して画面右上部にあ る「SQL の実行(メタ+Shift+E)」ボタンを押下してください。 create table usertable ( username varchar(128) NOT NULL CONSTRAINT USER_PK PRIMARY KEY , mailaddress varchar(128) NOT NULL, password varchar(128) NOT NULL ); create table grouptable( username varchar(128) NOT NULL, groupid varchar(128) NOT NULL, CONSTRAINT GROUP_PK PRIMARY KEY(username, groupid), CONSTRAINT USER_FK FOREIGN KEY(username) REFERENCES usertable(username) ON DELETE CASCADE ON UPDATE RESTRICT ); SQL が正しく実行されると「出力」に下記のメッセージが出力されます。 0.032 秒で実行が成功しました。0 行が変更されました。 1 行目 2 文字目 0.022 秒で実行が成功しました。0 行が変更されました。 8 行目 2 文字目 0.054 秒後に実行が終了しました。0 個のエラーが発生しました。 SQL を実行した後、データベースの「表」を「リフレッシュ」し更新してく ださい。すると下記のように「USERTABLE」、「GROUPTABLE」が作成 されていることを確認できます。 図  37: デー タベ ース 上 に作 成さ れた テ ーブ ルの 確 認     27  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   ユーザとグループ情報を登録するための、テーブルを作成しましたので、次 に実際にユーザとグループのテーブルに情報を登録します。今回はユーザと グループに情報を登録する事だけが目的のため、登録時、削除時の確認画面 や、ユーザに対する複数グループの登録機能は省略します。(※ DB テーブ ルは複数グループの登録に対応しています。) 4.2 JPA のエンティティを作成 今回データベースにユーザ情報、グループ情報を登録・削除するため Java EE 標準の ORM フレームワークである Java Persistence API を使用します。 既にデータベースのテーブルが存在していますので、データベースのテーブ ルから JPA の Entity クラスを自動作成してください。「WebSocketMailer」プロジェクトを選択し右クリックしてください。右クリックすると メニューが表示されますので、「新規」→「その他...」を選択してください。 図  38: デー タベ ース か らエ ンテ ィ ティ の作 成 その他を選択すると下記のウィンドウが表示されます。ここで「カテゴリ (C):」より「持続性」を選択し、「ファイル・タイプ(F):」より「データベー スからのエンティティ・クラス」を選択し「次 >」ボタンを押下してくださ い。   28  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   図  39: デー タベ ース か らの エン ティ テ ィ・ クラ ス の生 成 ボタンを押下すると下記の画面が表示されます。ここで「データ・ソース (D):」より「jdbc/__default」を選択し「使用可能な表(T):」より 「GROUPTABLE」を選択し「追加(A) >」ボタンを押下してください。ボタ ンを押下すると「選択した表(E):」に「GROUPTABLE」と「USERTABLE」 が追加されます。2つの表が選択されている事を確認し「次 >」ボタンを押 下してください。 図  40: デー タベ ース か らの エン ティ テ ィ・ クラ ス の生 成   29  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   ボタンを押下すると下記の画面が表示されます。ここで、「パッケージ(K):」 に「jp.co.oracle.websocket.mailer.entities」と入力し「JAXB 注釈を生成 (J):」のチェックを外し「次 >」ボタンを押下してください。 図  41: デー タベ ース か らの エン ティ テ ィ・ クラ ス の生 成 ボタンを押下すると下記の画面が表示されます。ここではデフォルトの設定 のまま最後に「終了(F)」ボタンを押下してください。 図  42: デー タベ ース か らの エン ティ テ ィ・ クラ ス の生 成   30  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   図  43: 自動 生成 され た エン ティ ティ ・ クラ ス 自動生成されたエンティティ・クラスは「Usertable.java」、 「Grouptable.java」、「GrouptablePK.java」の3クラスで、それぞれ下 記のコードになります。 package jp.co.oracle.websocket.mailer.entities; import import import import import import import import import import import import import java.io.Serializable; java.util.Collection; javax.persistence.Basic; javax.persistence.CascadeType; javax.persistence.Column; javax.persistence.Entity; javax.persistence.Id; javax.persistence.NamedQueries; javax.persistence.NamedQuery; javax.persistence.OneToMany; javax.persistence.Table; javax.validation.constraints.NotNull; javax.validation.constraints.Size; /** * * @author Yoshio Terada */ @Entity @Table(name = "USERTABLE") @NamedQueries({ @NamedQuery(name = "Usertable.findAll", query = "SELECT u FROM Usertable u"), @NamedQuery(name = "Usertable.findByUsername", query = "SELECT u FROM Usertable u WHERE u.username = :username"), @NamedQuery(name = "Usertable.findByMailaddress", query = "SELECT u FROM Usertable u WHERE u.mailaddress = :mailaddress"), @NamedQuery(name = "Usertable.findByPassword", query = "SELECT u FROM Usertable u WHERE u.password = :password")}) public class Usertable implements Serializable { private static final long serialVersionUID = 1L; @Id @Basic(optional = false) @NotNull @Size(min = 1, max = 128) @Column(name = "USERNAME") private String username; @Basic(optional = false) @NotNull   31  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   @Size(min = 1, max = 128) @Column(name = "MAILADDRESS") private String mailaddress; @Basic(optional = false) @NotNull @Size(min = 1, max = 128) @Column(name = "PASSWORD") private String password; @OneToMany(cascade = CascadeType.ALL, mappedBy = "usertable") private Collection<Grouptable> grouptableCollection; public Usertable() { } public Usertable(String username) { this.username = username; } public Usertable(String username, String mailaddress, String password) { this.username = username; this.mailaddress = mailaddress; this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getMailaddress() { return mailaddress; } public void setMailaddress(String mailaddress) { this.mailaddress = mailaddress; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Collection<Grouptable> getGrouptableCollection() { return grouptableCollection; } public void setGrouptableCollection(Collection<Grouptable> grouptableCollection) { this.grouptableCollection = grouptableCollection; } @Override public int hashCode() { int hash = 0; hash += (username != null ? username.hashCode() : 0); return hash;   32  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   } @Override public boolean equals(Object object) { // TODO: Warning - this method won't work in the case the id fields are not set if (!(object instanceof Usertable)) { return false; } Usertable other = (Usertable) object; if ((this.username == null && other.username != null) || (this.username != null && !this.username.equals(other.username))) { return false; } return true; } @Override public String toString() { return "jp.co.oracle.websocket.mailer.entities.Usertable[ username=" + username + " ]"; } } package jp.co.oracle.websocket.mailer.entities; import import import import import import import import java.io.Serializable; javax.persistence.EmbeddedId; javax.persistence.Entity; javax.persistence.JoinColumn; javax.persistence.ManyToOne; javax.persistence.NamedQueries; javax.persistence.NamedQuery; javax.persistence.Table; /** * * @author Yoshio Terada */ @Entity @Table(name = "GROUPTABLE") @NamedQueries({ @NamedQuery(name = "Grouptable.findAll", query = "SELECT g FROM Grouptable g"), @NamedQuery(name = "Grouptable.findByUsername", query = "SELECT g FROM Grouptable g WHERE g.grouptablePK.username = :username"), @NamedQuery(name = "Grouptable.findByGroupid", query = "SELECT g FROM Grouptable g WHERE g.grouptablePK.groupid = :groupid")}) public class Grouptable implements Serializable { private static final long serialVersionUID = 1L; @EmbeddedId protected GrouptablePK grouptablePK; @JoinColumn(name = "USERNAME", referencedColumnName = "USERNAME", insertable = false, updatable = false) @ManyToOne(optional = false) private Usertable usertable; public Grouptable() { }   33  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   public Grouptable(GrouptablePK grouptablePK) { this.grouptablePK = grouptablePK; } public Grouptable(String username, String groupid) { this.grouptablePK = new GrouptablePK(username, groupid); } public GrouptablePK getGrouptablePK() { return grouptablePK; } public void setGrouptablePK(GrouptablePK grouptablePK) { this.grouptablePK = grouptablePK; } public Usertable getUsertable() { return usertable; } public void setUsertable(Usertable usertable) { this.usertable = usertable; } @Override public int hashCode() { int hash = 0; hash += (grouptablePK != null ? grouptablePK.hashCode() : 0); return hash; } @Override public boolean equals(Object object) { // TODO: Warning - this method won't work in the case the id fields are not set if (!(object instanceof Grouptable)) { return false; } Grouptable other = (Grouptable) object; if ((this.grouptablePK == null && other.grouptablePK != null) || (this.grouptablePK != null && !this.grouptablePK.equals(other.grouptablePK))) { return false; } return true; } @Override public String toString() { return "jp.co.oracle.websocket.mailer.entities.Grouptable[ grouptablePK=" + grouptablePK + " ]"; } } package jp.co.oracle.websocket.mailer.entities; import import import import   java.io.Serializable; javax.persistence.Basic; javax.persistence.Column; javax.persistence.Embeddable; 34  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; /** * * @author Yoshio Terada */ @Embeddable public class GrouptablePK implements Serializable { @Basic(optional = false) @NotNull @Size(min = 1, max = 128) @Column(name = "USERNAME") private String username; @Basic(optional = false) @NotNull @Size(min = 1, max = 128) @Column(name = "GROUPID") private String groupid; public GrouptablePK() { } public GrouptablePK(String username, String groupid) { this.username = username; this.groupid = groupid; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getGroupid() { return groupid; } public void setGroupid(String groupid) { this.groupid = groupid; } @Override public int hashCode() { int hash = 0; hash += (username != null ? username.hashCode() : 0); hash += (groupid != null ? groupid.hashCode() : 0); return hash; } @Override public boolean equals(Object object) { // TODO: Warning - this method won't work in the case the id fields are not set if (!(object instanceof GrouptablePK)) { return false; } GrouptablePK other = (GrouptablePK) object; if ((this.username == null && other.username != null) || (this.username != null && !this.username.equals(other.username))) { return false;   35  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   } if ((this.groupid == null && other.groupid != null) || (this.groupid != null && !this.groupid.equals(other.groupid))) { return false; } return true; } @Override public String toString() { return "jp.co.oracle.websocket.mailer.entities.GrouptablePK[ username=" + username + ", groupid=" + groupid + " ]"; } } 4.3 ユーザ管理用の Enterprise JavaBeans の作成 エンティティ・クラスを作成しましたので、次にユーザを管理(登録・削除) するためのビジネス・ロジックを Enterprise JavaBeans (EJB)として作成 します。「WebSocket-Mailer」プロジェクトを選択し右クリックしてくだ さい。右クリックするとメニューが表示されますので、「新規」→「その 他...」を選択してください。 図  44: Enterprise  JavaBeans の 作成 選択すると下記のウィンドウが表示されます。ここで「カテゴリ(C):」より 「エンタープライズ JavaBeans」を選択し「ファイル・タイプ(F):」より 「セッション Bean」を選択し「次 >」ボタンを押下してください。   36  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   図  45: Enterprise  JavaBeans の 作成 ボタンを押下すると下記の画面が表示されます。ここで「EJB 名(N):」に 「UserRegistManager」と入力し「パッケージ(K):」に 「jp.co.oracle.websocket.mailer.ejbs」を入力し最後に「終了(F)」ボタン を押下してください。 図  46: Enterprise  JavaBeans の 作成   37  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   ボタンを押下すると下記の EJB クラスが自動的に生成されます。 package jp.co.oracle.websocket.mailer.ejbs; import javax.ejb.Stateless; /** * * @author Yoshio Terada */ @Stateless public class UserRegistManager { } まず、ユーザを DB に登録するためのビジネス・ロジックを実装します。 ユーザ登録には、ユーザ名、メールアドレス、パスワード、グループ名を指 定して行ないます。(※1ユーザに対して複数のグループを指定する事がで きますが今回は単一グループに所属させる事にします。)下記の太字を実装 してください。 @Stateless public class UserRegistManager { @PersistenceContext EntityManager em; /* 指定したユーザ、メールアドレス、パスワード、グループ名で DB へ登録 */ public void createUserAndGroup(String String String String Usertable user = new Usertable(); user.setUsername(username); user.setMailaddress(mailaddress); username, mailaddress, password, groupname) { SHA256Encoder encoder = new SHA256Encoder(); String encodedPassword = encoder.encodePassword(password); user.setPassword(encodedPassword); Grouptable group = new Grouptable(); group.setGrouptablePK(new GrouptablePK(username, groupname)); group.setUsertable(user); em.persist(user); em.persist(group); } } Usertable, Grouptable の各エンティティのインスタンスを生成しエンティ ティの各フィールドにそれぞれユーザ名、メールアドレス、パスワード、グ ループ名などを設定します。ここでパスワードの内容を平文ではなく、メッ   38  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   セージ・ダイジェスト(ハッシュ値)で保存するため、ダイジェスト・アル ゴリズムとして SHA-256 で生成します。 ここで、SHA-256 のダイジェストを生成するためのユーティリティ・クラ スとして「SHA256Encoder」というクラスを生成してください。 「WebSocket-Mailer」プロジェクトを選択し右クリックしてください。右 クリックするとメニューが表示されますので、「新規」→「その他...」を選 択してください。 図  47: SHA-­‐256 エ ンコ ード ・ユ ー ティ リテ ィク ラ スの 作成 選択すると下記のウィンドウが表示されます。ここで「カテゴリ(C):」より 「Java」、「ファイル・タイプ(F):」より「Java クラス」を選択し「次 >」 ボタンを押下してください。 図  48: SHA-­‐256 エ ンコ ード ・ユ ー ティ リテ ィク ラ スの 作成   39  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   ボタンを押下すると下記の画面が表示されます。ここで「クラス名(N):」に 「SHA256Encoder」と入力し、「パッケージ(K):」に 「jp.co.oracle.websocket.mailer.SHADigestUtil」と入力した後、最後に 「終了(F)」ボタンを押下してください。 図  49: SHA-­‐256 エ ンコ ード ・ユ ー ティ リテ ィク ラ スの 作成 ボタンを押下すると Java のクラスが生成されます。そこでクラスに対して 下記のメソッドを実装してください。 package jp.co.oracle.websocket.mailer.SHADigestUtil; import import import import java.security.MessageDigest; java.security.NoSuchAlgorithmException; java.util.logging.Level; java.util.logging.Logger; /** * DB に保存するパスワードを SHA-256 の * メッセージ・ダイジェストとして保存 * プレイン・テキストとメッセージ・ダイジェストの変換ユーティリティ * * @author Yoshio Terada */ public class SHA256Encoder { // SHA-256 ハッシュとして保存 public String encodePassword(String origPassword){ String returnValue = ""; try { MessageDigest md = MessageDigest.getInstance("SHA-256"); byte[] digest = md.digest(origPassword.getBytes()); StringBuilder builder = new StringBuilder(); for (int i = 0; i < digest.length; i++) { String tmp = Integer.toHexString(digest[i] & 0xff); if (tmp.length() == 1) { builder.append('0').append(tmp); } else {   40  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   builder.append(tmp); } } returnValue = builder.toString(); } catch (NoSuchAlgorithmException ex) { Logger.getLogger(SHA256Encoder.class.getName()).log(Level.SEVERE, null, ex); } return returnValue; } } 次に、EJB に対してユーザ検索とユーザ削除を行なうためのロジッックを追 加します。最終的な EJB のソースコードを下記に示します。 package jp.co.oracle.loginsample.ejbs; import import import import import import import javax.ejb.Stateless; javax.persistence.EntityManager; javax.persistence.PersistenceContext; jp.co.oracle.loginsample.SHADigestUtil.SHA256Encoder; jp.co.oracle.loginsample.entities.Grouptable; jp.co.oracle.loginsample.entities.GrouptablePK; jp.co.oracle.loginsample.entities.Usertable; /** * * @author Yoshio Terada */ @Stateless public class UserRegistManager { @PersistenceContext EntityManager em; /* 指定したユーザ、メールアドレス、パスワード、グループ名で DB へ登録 */ public void createUserAndGroup(String username,String mailaddress, String password, String groupname) { Usertable user = new Usertable(); user.setUsername(username); user.setMailaddress(mailaddress); SHA256Encoder encoder = new SHA256Encoder(); String encodedPassword = encoder.encodePassword(password); user.setPassword(encodedPassword); Grouptable group = new Grouptable(); group.setGrouptablePK(new GrouptablePK(username, groupname)); group.setUsertable(user); em.persist(user); em.persist(group); }   41  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   /* DB から指定したユーザの削除 */ public void removeUser(String username) { Usertable user = em.find(Usertable.class, username); em.remove(user); } /* DB から指定したユーザの検索 */ public Usertable findUser(String username){ Usertable user = em.find(Usertable.class, username); return user; } } 4.4 CDI (JSF 管理対象 Bean)の作成 EJB のビジネス・ロジックを作成したので、JSF のバッキング・ビーンであ る CDI を作成します。ここでは管理用の画面からユーザ名、メールアドレス、 パスワード、グループ名が入力される事を想定し、それぞれのフィールドを 用意し、入力された値から EJB のビジネス・ロジックを呼び出すコードを生 成します。 「WebSocket-Mailer」プロジェクトを選択し右クリックしてください。右 クリックするとメニューが表示されますので、「新規」→「その他...」を選 択してください。 図  50:JSF 管 理対 象 Bean の 作成   42  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   選択すると下記のウィンドウが表示されます。ここで「カテゴリ(C):」より 「JavaServer Faces」、「ファイル・タイプ(F):」より「JSF 管理対象 Bean」を選択し「次 >」ボタンを押下してください。 図  51: JSF  管 理対 象 Bean の 作成 ボタンを押下すると下記の画面が表示されます。ここで「クラス名(N):」に 「RegistPage」、「パッケージ(K):」に 「jp.co.oracle.websocket.mailer.cdis」、「スコープ:」に「request」を 選択し「終了(F)」ボタンを押下してください。 図  52: JSF 管 理対 象 Bean  の 作成   43  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   ボタンを押下すると下記のコードが生成されます。 package jp.co.oracle.websocket.mailer.cdis; import javax.inject.Named; import javax.enterprise.context.RequestScoped; import java.io.Serializable; /** * * @author Yoshio Terada */ @Named(value = "registPage") @SessionScoped public class RegistPage implements Serializable { /** * Creates a new instance of RegistPage */ public RegistPage() { } } ここで、ユーザ名、メールアドレス、パスワード、グループ名が画面から入 力される事を想定し各フィールドを用意します。下記 4 つのフィールドを追 加してください。 @Named(value = "regManage") @SessionScoped public class Regist implements Serializable { private private private private String String String String username; mailaddress; password; group; …… }   44  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   フィールドを追加した後、フィールドを隠蔽します。NetBeans のメニュー より「リファクタリ...」を選択し「フィールドをカプセル化...」を選択してく ださい。 プログラムを作成しユーザ情報、グループ情報を追加します。 まず、JPA の Entity を作成します。 図  53: フィ ール ドの カ プセ ル化 選択すると下記のウィンドウが表示されます。ここで「取得メソッドを作 成」、「設定メソッドを作成」の全チェックボックスにチェックし「リファ クタリング(R)」ボタンを押下してください。 図  54: フィ ール ドの カ プセ ル化 ボタンを押下すると各フィールド用のセッタ・ゲッタメソッドが自動的に作 成されます。   45  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   次に、EJB (UserRegistManager)のビジネス・ロジック(createUserAndGroup) を呼び出しユーザ登録するメソッドを追加してください。ここでは@EJB の アノテーションを付加し、UserRegistManager の EJB をインジェクション しています。また Web ページから入力された各情報を取得し createUserAndGroup()メソッドに値を渡しています。 @EJB UserRegistManager userRegist; /* DB へユーザ情報・グループ情報の登録 */ public void registDB() throws IOException { userRegist.createUserAndGroup( getUsername(), getMailaddress(), getPassword(), getGroup()); } 最終的に、登録用の JSF 管理対象 Bean の全ソースコードは下記になります。 package jp.co.oracle.websocket.mailer.cdis; import import import import import import java.io.IOException; javax.inject.Named; javax.enterprise.context.RequestScoped; java.io.Serializable; javax.ejb.EJB; jp.co.oracle.websocket.mailer.ejbs.UserRegistManager; /** * * @author Yoshio Terada */ @Named(value = "registPage") @RequestScoped public class RegistPage implements Serializable { private String username; private String mailaddress; private String password; private String group; @EJB UserRegistManager userRegist; /* DB へユーザ情報・グループ情報の登録 */ public String registDB() throws IOException { userRegist.createUserAndGroup(getUsername(), getMailaddress(), getPassword(), getGroup()); return "reg-success";   46  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   } /** * Creates a new instance of RegistPage */ public RegistPage() { } /** * @return the username */ public String getUsername() { return username; } /** * @param username the username to set */ public void setUsername(String username) { this.username = username; } /** * @return the mailaddress */ public String getMailaddress() { return mailaddress; } /** * @param mailaddress the mailaddress to set */ public void setMailaddress(String mailaddress) { this.mailaddress = mailaddress; } /** * @return the password */ public String getPassword() { return password; } /** * @param password the password to set */ public void setPassword(String password) { this.password = password; } /** * @return the group */ public String getGroup() { return group; } /** * @param group the group to set */ public void setGroup(String group) { this.group = group; }   47  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   } 同様に削除用の JSF 管理対象 Bean を「RemovePage.java」として作成し てください。削除用の全ソースコードは下記になります。 package jp.co.oracle.websocket.mailer.cdis; import import import import javax.ejb.EJB; javax.inject.Named; javax.enterprise.context.RequestScoped; jp.co.oracle.websocket.mailer.ejbs.UserRegistManager; /** * * @author Yoshio Terada */ @Named(value = "removePage") @RequestScoped public class RemovePage { private String username; @EJB UserRegistManager userManager; /* DB からユーザ情報の削除 */ public String removeDB(){ userManager.removeUser(getUsername()); return "rem-success"; } /** * Creates a new instance of RemovePage */ public RemovePage() { } /** * @return the username */ public String getUsername() { return username; } /** * @param username the username to set */ public void setUsername(String username) { this.username = username; } }   48  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   4.5 ユーザ管理用 Web ページ(JSF Facelets)の作成 JSF の管理対象 Bean が作成されましたので最後にユーザ登録・削除用の Web ページを作成します。管理用の Web ページは「user-manage」ディ レクトリ配下にそれぞれ「regist.xhtml」、「remove.xhtml」を作成します。 図  55: 管理 用 Web ペ ージ のデ ィレ ク トリ 構成 「WebSocket-Mailer」プロジェクト配下の「Web ページ」を選択し右クリ ックしてください。右クリックするとメニューが表示されますので、「新規」 →「その他...」を選択してください。 図  56: 管理 用 Web ペ ージ ・フ ォル ダ の作 成 その他を選択すると下記のウィンドウが表示されます。ここで「カテゴリ (C):」より「その他」を選択し、「ファイル・タイプ(F):」より「フォルダ」 を選択し「次 >」ボタンを押下してください。   49   図  57: 管 理用 Web ペ ージ ・フ ォル ダ の作 成
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   ボタンを押下すると下記の画面が表示されます。ここで「フォルダ名(N):」 に「user-manage」と入力し「終了(F)」ボタンを押下してください。 図  58: 管 理用 Web ペ ージ ・フ ォル ダ の作 成 ボタンを押下すると「Web ページ」配下に「user-manage」ディレクトリ が作成されます。 図  59: 管理 用 Web ペ ージ ・フ ォル ダ の作 成 作成したディレクトリ配下に登録・削除用の Web ページを作成します。   50  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   作成した「user-manage」ディレクトリを選択し右クリックしてください。 右クリックするとメニューが表示されますので、「新規」→「その他...」を 選択してください。 図  60: 登録 用 JSF ペ ージ の作 成 選択すると下記のウィンドウが表示されます。ここで「カテゴリ(C):」より 「JavaServer Faces」を選択し、「ファイル・タイプ(F):」より「JSF ペー ジ」を選択し「次 >」ボタンを押下してください。 図  61: 登録 用 jSF ペ ージ の作 成 ボタンを押下すると下記の画面が表示されます。ここで「ファイル名:」に 「regist」と入力し、最後に「終了(F)」ボタンを押下してください。   51  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   図  62: 登録 用 JSF ペ ージ の作 成 ボタンを押下すると自動的に下記の Facelets が生成されます。 <?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html"> <h:head> <title>Facelet Title</title> </h:head> <h:body> Hello from Facelets </h:body> </html> regist.xhtml に対して下記のようにコードを修正してください。 <?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:p="http://primefaces.org/ui"> <h:head> <title>ユーザ情報登録画面</title> </h:head> <h:body> <h:form> <center> <p:panel header="ユーザ情報登録画面" style="width: 320px"> <h:panelGrid columns="2" columnClasses="column" cellpadding="5"> <h:outputLabel value="ユーザ名: " style="font-size:14px;"/> <h:inputText id="userName" value="#{registPage.username}" style="font-size:14px;"/> <h:outputLabel value="メールアドレス: " style="font-   52  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   size:14px;"/> <h:inputText id="mailaddress" value="#{registPage.mailaddress}" style="font-size:14px;"/> <h:outputLabel value="パスワード: " style="font-size:14px;" /> <h:inputSecret id="password" value="#{registPage.password}" style="font-size:14px;"/> <h:outputLabel for="group" value="所属グループ" style="fontsize:14px;"/> <h:inputText id="group" value="#{registPage.group}" required="true" style="font-size:14px;" /> </h:panelGrid> <h:commandButton value="ユーザ登録" style="font-size:14px;" action="#{registPage.registDB}"/> <p:messages id="messages" autoUpdate="true" closable="true" /> <h:link value="戻る" outcome="/faces/index.xhtml" /> </p:panel> </center> </h:form> </h:body> </html> 上記のコード内で次の EL 式が定義されています。 l l l l #{registPage.username} #{registPage.mailaddress} #{registPage.password} #{registPage.group} Web ページで入力された値は CDI として実装した Regpage のクラスのフ ィールド username, mailaddress, password, group にそれぞれ代入され ます。またボタンが押下された際に、action で指定した #{registPage.registDB}が呼び出され、Regpage クラスの registDB()メソ ッドが実行されます。registDB()メソッドの返り値である String 型 (regsuccess)は JSF で暗黙的に画面遷移先を表します(例:成功した場合 regsuccess.xhtml へ自動的に遷移)。 「図  60:登録用 JSF ページの作成」と同様の手順で「reg-success.xhtml」 ファイルを作成してください。作成した後、下記のように修正してください。 #{registPage.username}に入力されたユーザ名が表示されます。 <?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html"> <h:head> <title>ユーザ情報登録画面完了</title> </h:head> <h:body> ユーザ情報 (#{registPage.username}) は正しく登録されました。 </h:body> </html>   53  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   登録用の Web ページを作成しましたので、削除用の Web ページも作成して ください。「図  60:登録用 JSF ページの作成」と同様の手順でユーザ削除用 のページを「remove.xhtml」として作成してください。 <?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:p="http://primefaces.org/ui"> <h:head> <title>ユーザ情報削除画面</title> </h:head> <h:body> <h:form> <center> <p:panel header="ユーザ情報削除画面" style="width: 320px"> <h:panelGrid columns="2" columnClasses="column" cellpadding="5"> <h:outputLabel value="削除ユーザ名: " style="font-size:14px;"/> <h:inputText id="userName" value="#{removeManage.username}" style="font-size:14px;"/> </h:panelGrid> <h:commandButton value="ユーザ削除" style="font-size:14px;" action="#{removeManage.removeDB}"/> <p:messages id="messages" autoUpdate="true" closable="true" /> <h:link value="戻る" outcome="/faces/login/index.xhtml" /> </p:panel> </center> </h:form> </h:body> </html> 最後に削除完了画面を作成してください。「図   60:登録用 JSF ページの作成」 と同様の手順でユーザ削除完了用のページを「rem-success.xhtml」として 作成してください。 <?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html"> <h:head> <title>ユーザ情報削除画面完了</title> </h:head> <h:body> ユーザ情報 (#{removePage.username}) が正しく削除されました。 </h:body> </html> 以上で、ユーザ登録・削除用の Web アプリケーションは作成されました。   54  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   全てのページを作成すると「user-manage」ディレクトリ配下に4つのファ イルが存在しています。 図  63: 登録 ・削 除用 JSF ペ ージ 一覧 最後に便利のためにデフォルトで表示される「index.xhtml」ファイルを編集 し作成したユーザ登録・削除用の画面へのリンクを記載してください。 「index.xhtml」ファイルをダブル・クリックした後下記のように修正してく ださい。 <?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html"> <h:head> <title>トップ・ページ</title> </h:head> <h:body> <h:form> <h:link value="ユーザ登録画面へ" outcome="/user-manage/regist.xhtml" /><br/> <h:link value="ユーザ削除画面へ" outcome="/user-manage/remove.xhtml" /><br/> </h:form> </h:body> </html> 4.6 ユーザ登録・削除アプリケーションの実行 ユーザ登録・削除を行なう Web アプリケーションの実行準備が全て整いま したので、アプリケーションを実行して動作確認しましょう。 NetBean のプロジェクトを下記の手順で実行してください。「WebSocketMailer」プロジェクトが選択された状態で NetBeans のツールバーより「プ ロジェクト(WebSocket-Mailer)を実行(f6)」ボタンを押下してください。 図  64: プロ ジェ クト の 実行   55  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   もしくは、「WebSocket-Mailer」プロジェクトを選択し右クリックしてく ださい。右クリックするとメニューが表示されますので、「実行」を選択し てください。 図  65: プロ ジェ クト の 実行 プロジェクトを実行すると下記の画面がブラウザ上に表示されます。 図  66: プロ ジェ クト の 実行   56  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   ここで「ユーザ登録画面へ」のリンクを押下してください。押下すると下記 の画面が表示されます。 図  67: ユー ザ情 報登 録 画面 ここで、各フィールドに下記を入力し「ユーザ登録」ボタンを押下してくだ さい。 表  1:登録するユーザ情報   項目 ユーザ名 メールアドレス パスワード 所属グループ 入力値 admin admin@oracle.com admin admin 図  68: ユー ザ情 報登 録 画面 ボタンを押下すると下記の画面が表示されます。ここで()カッコ内に「ユー   57  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   ザ名」で入力した文字列が表示されている事を確認してください。 図  69: ユー ザ情 報登 録 完了 画面 Web ページからユーザ登録した後、データベースに正しく登録されているか 否か確認してください。NetBeans の「サービス」タブを選択し 「USERTABLE」を選択し右クリックしてください。右クリックするとメニ ューが表示されます。ここで「データを表示...」を選択してください。 図  70: DB テ ーブ ル中 のデ ー タを 表示   58  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   選択すると下記の画面が表示されます。ここで「PASSWORD」のカラムに 入力されているデータが平文ではなくメッセージ・ダイジェスト 「8c6976e5b...」になっていることを確認してください。 図  71:DB テ ーブ ル中 のデ ー タを 表示 同様に、「GROUPTABLE」のデータを表示してください。「admin」ユー ザに対して「admin」の GROUPID(ロール:役割)が割り当てられている事を 確認してください。 図  72:DB テ ーブ ル中 のデ ー タを 表示 「ユーザ登録画面」から同様にもう1名「user」のロールを持つユーザを追 加してください。 表  2:登録するユーザ情報   項目 ユーザ名 メールアドレス パスワード 所属グループ 入力値 user user@oracle.com user user 以上でユーザの登録が正常に行なわれました。   59  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   5. アプリケーションに対するアクセス制限:認証・認可 次に本章では、アプリケーション・サーバ上で提供されているサービスに対 して、データベースを利用して認証を行ない、認可設定によりアプリケーシ ョンの保護を行います。ここでご紹介する内容は、JavaServer Faces のア プリケーションに限らず、Servlet, JAX-RS、EJB など Java EE アプリケー ション全体で適用可能です。Java EE 標準のセキュリティ実現方法4のため是 非正しく理解してください。 今回作成するアプリケーションは下記のイメージです。 ログイン画面を作成し「管理者権限を持つユーザ」でログイン(認証)した 場合は、管理者だけが実行可能な機能一覧が表示されるページを表示し(認 可)、「ユーザ権限を持つユーザ」でログイン(認証)した場合は、ユーザ が実行可能な機能一覧が表示されるページを表示します(認可)。 図  73: ログ イン 画面 それではより詳細にアプリケーションに対する認証・認可を実現するための 方法を説明します。 今回認証・認可を実現するために、JDBC レルムを使用します。レルムとは ユーザ情報やグループ情報、そして関連するセキュリティ資格などの情報が 保存された場所で、GlassFish ではレルムを実現する方式として下記が利用 可能です。また下記の認証方式がサポートされています。                                                                                                                 4  ここでご紹介する内容は Java EE 6, Java EE 7 共通です。     60  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   GlassFish で利用可能なレルム方式 l LDAP レルム l クライアント認証・レルム l ファイル・レルム l Solaris レルム l JDBC レルム l PAM レルム l 独自作成のカスタム・レルム GlassFish で利用可能な認証方式 l Basic 認証 l FORM 認証 l クライアント証明書による認証 l ダイジェスト認証 l 相互認証 これらの中で今回は、JDBC レルムを使用した FORM 認証を行ないます。 図  74: JDBC レ ルム を利 用し た 認証 ・認 可の 概 念図 既に、「4.0 ユーザ・グループの登録・削除画面の作成」でデータベー スのテーブル作成は完了しています。そこで本章ではアプリケーション・サ ーバ上の設定と、ログイン認証用のページを作成します。 実装手順は「図  74:JDBC レルムを利用した認証・認可の概念図」に示す順 に行います。   61  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   5.1 ログイン用の JSF ページと JSF 管理対象 Bean の作成 まず、JSF でログインページと、ログインページのデータ管理を行なう管理 対象 Bean を作成します。 図  75: JSF ロ グイ ンペ ージ の 作成 まず、ログイン認証前後に表示するページをまとめた新しいフォルダを作成 します。「WebSocket-Mailer」プロジェクト配下の「Web ページ」を選択 し右クリックしてください。右クリックするとメニューが表示されますので、 「新規」→「その他...」を選択してください。 図  76: 新規 フォ ルダ の 作成   62  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   選択すると下記のウィンドウが表示されます。ここで「カテゴリ(C):」より 「その他」、「ファイル・タイプ(F):」より「フォルダ」を選択し「次 >」ボ タンを押下してください。 図  77: 新規 フォ ルダ の 作成 ボタンを押下すると下記の画面が表示されます。ここで「フォルダ名(N):」 に「login」と入力し、最後に「終了(F)」ボタンを押下してください。 図  78: 新規 フォ ルダ の 作成   63  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   次にログイン用の JSF ページを作成します。作成した「login」ディレクト リを選択し右クリックしてください。右クリックするとメニューが表示され ますので、「新規」→「その他...」を選択してください。 図  79:JSF ロ グイ ンペ ージ の 作成 選択すると下記のウィンドウが表示されます。ここで「カテゴリ(C):」より 「JavaServer Faces」、「ファイル・タイプ(F):」より「JSF ページ」を選 択し「次 >」ボタンを押下してください。 図  80: JSF ロ グイ ンペ ージ の 作成   64  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   ボタンを押下すると下記の画面が表示されます。ここで「ファイル名:」に 「index」と入力し、最後に「終了(F)」ボタンを押下してください。 図  81: JSF ロ グイ ンペ ージ の 作成 ボタンを押下すると下記の Facelets が自動的に生成されます。自動生成され たコードを編集し下記のコードを記述してください。 <?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:p="http://primefaces.org/ui" xmlns:f="http://xmlns.jcp.org/jsf/core"> <h:head> <title>ログイン画面</title> </h:head> <h:body> <h:form> <center> <p:panel header="ログイン画面" style="width: 320px"> <h:panelGrid columns="2" columnClasses="column" cellpadding="5"> <h:outputText value="ログイン名: " style="font-size:14px;"/> <h:inputText id="userName" value="#{indexPage.username}" style="font-size:14px;"/> <h:outputText value="パスワード: " style="font-size:14px;" /> <h:inputSecret onselect="true" id="password" value="#{indexPage.password}" style="font-size:14px;"/> </h:panelGrid> <h:commandButton value="ログイン" style="font-size:14px;" action="#{indexPage.login}"/> <h:messages id="messages" showDetail="true" errorStyle="color:RED;font-size:14px;" />   65  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   <h:commandLink value="ユーザ登録" action="/faces/usermanage/regist.xhtml" /> / <h:commandLink value="ユーザ削除" action="/faces/usermanage/remove.xhtml" /> </p:panel> </center> </h:form> </h:body> </html> つづいて、この「JSF ページ」の処理を行なう「JSF 管理対象 Bean」を作 成します。「ソース・パッケージ」中から 「jp.co.oracle.websocket.mailer.cdis」パッケージを選択し右クリックし てください。右クリックすると下記のメニューが表示されますので、「新規」 →「その他...」を選択してください。 図  82:JSF 管 理対 象 Bean の 作成   66  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   選択すると下記のウィンドウが表示されます。ここで「カテゴリ(C):」に 「JavaServer Faces」、「ファイル・タイプ(F):」に「JSF 管理対象 Bean」 を選択し「次 >」ボタンを押下してください。 図  83:JSF 管 理対 象 Bean の 作成 ボタンを押下すると下記の画面が表示されます。ここで「クラス名(N):」に 「IndexPage」、「スコープ:」で「request」を選択し、最後に「終了(F)」 ボタンを押下してください。 図  84:JSF 管 理対 象 Bean の 作成   67  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   ボタンを押下すると「IndexPage」クラスが自動的に生成されます。自動生 成されたコードに下記のコードを追加してください。 package jp.co.oracle.websocket.mailer.cdis; import java.util.logging.Level; import java.util.logging.Logger; import javax.inject.Named; import javax.enterprise.context.RequestScoped; /** * * @author Yoshio Terada */ @Named(value = "indexPage") @RequestScoped public class IndexPage { private String username; private String password; public IndexPage() { } /* ログインボタンが押下された際の処理 */ public String login() { String name = getUsername(); String pass = getPassword(); Logger.getLogger(IndexPage.class.getName()).log(Level.INFO, name +":"+ pass); return ""; } /** * @return the username */ public String getUsername() { return username; } /** * @param username the username to set */ public void setUsername(String username) { this.username = username; } /** * @return the password */ public String getPassword() { return password; } /** * @param password the password to set */ public void setPassword(String password) { this.password = password; } }   68  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   プログラムを修正した後、アプリケーションを実行してください。 NetBeans のメニューより「実行ボタン」を押下してください。   プロジェクトを実行すると、ブラウザが自動的に起動されます。ブラウザよ り下記の URL にアクセスしてください。 http://localhost:8080/WebSocket-Mailer/faces/login/index.xhtml アクセスすると下記の画面が表示されます。 図  85: ログ イン 画面 ここで、「ログイン名:」に「admin」、「パスワード:」に「admin」と 入力し「ログイン」ボタンを押下してください。すると NetBeans の「出力」 ウィンドウの「GlassFish」のコンソール上に「情報:admin:admin」と表 示される事を確認できます。 図  86: GlassFish の コン ソー ル・ ロ グ出 力 以上で、JSF のログインページから JSF の管理対象 Bean に対して、データ の送信ができる事を確認できました。   69  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   ここで、何らかのエラーが発生した時に表示するエラー・ページも作成して おきます。「図  79:JSF ログインページの作成」と同様の手順で JSF の Web ページ「error.xhtml」を「login」ディレクトリ配下に作成してくださ い。 <?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html"> <h:head> <title>エラー画面</title> </h:head> <h:body> <h:form> エラー画面 <h:commandButton value="戻る" action="#{indexPage.logout()}"/> </h:form> </h:body> </html> 続いてログインが成功した際に表示する画面も「図  79:JSF ログインページ の作成」と同様に「login」ディレクトリ配下に「home.xhtml」として作成 してください。 <?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html"> <h:head> <title>ログイン完了画面</title> </h:head> <h:body> <h:form> ログインユーザ名:<h:outputLabel value="#{request.userPrincipal.name}"/> でログインしました。<br/> <h:commandButton value="ログアウト" action="#{indexPage.logout()}"/> </h:form> </h:body> </html>   70  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   最後にトップ・ページからログインページへ画面遷移するためにリンクを追 加してください。「Web ページ」配下に存在する「index.html」を選択して 下記のように修正してください。 <?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html"> <h:head> <title>トップ・ページ</title> </h:head> <h:body> <h:form> <h:link value="ログイン画面へ" outcome="/login/index.xhtml"/><br/> <h:link value="ユーザ登録画面へ" outcome="/user-manage/regist.xhtml" /><br/> <h:link value="ユーザ削除画面へ" outcome="/user-manage/remove.xhtml" /><br/> </h:form> </h:body> </html>   71  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   5.2 GlassFish における JDBC レルムの設定と実装 クライアント・ブラウザのログイン画面から、ユーザ名、パスワードを入力 し、サーバ上に送信できるようになりました。5そこで、このサーバで取得し たユーザ名、パスワードとデータベースに存在するユーザ情報を元に認証を 行ないます。アプリケーション・サーバからデータベースのユーザ情報、グ ループ情報を参照するために JDBC レルムを設定してください。JDBC レル ムの設定は、asadmin コマンド6、もしくは GUI の管理コンソールから設定 できます。 その前に、もう一度「4.0 ユーザ・グループの登録・削除画面の作成」 で作成したデータベースのテーブルを確認します。 図  87: 作成 済み のデ ー タベ ース ・テ ー ブル 上記データベースの各テーブルを参照するように、JDBC レルムの設定を行 います。 表  3:JDBC レルムの設定項目と設定値   項目 名前 項目の概要説明と設定値 web.xml の設定で指定するレルム名 <login-config> <realm-name> レルム名 </realm-name> </login-config> クラス名 設定値:jdbc-realm GlassFish の JDBCRealm の実装クラス名                                                                                                                 5  この時点でユーザ名、パスワードは HTTP で送信されているためパケット盗聴などにより パスワード情報が漏洩します。HTTPS でデータを送信する方法は後ほど設定します。 6  asadmin コマンドは GlassFish をインストールしたディレクトリ配下の bin ディレクトリ に存在します。例:/Applications/NetBeans/glassfish-4.0 にインストールした場合、 /Applications/NetBeans/glassfish-4.0/bin に存在します。     72  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   JAAS コンテキスト 設定値:com.sun.enterprise.security.ee.auth.realm. jdbc.JDBCRealm JAAS (Java Authentication and Authorization Service)コンテ キスト(このレルムに使用するログイン・モジュールの識別子)。 有効な値は jdbcRealm のみ JNDI 設定値:jdbcRealm レルムで使用するデータベースのユーザ、グループ・テーブルを参 照するための「JDBC リソース」に対する JNDI 名 設定値: jdbc/__default ユーザ表 ※ 本来認証用の「JDBC 接続プール」、「JDBC リソース」を作 成すべきだが、今回は検証のため JDBC のデフォルト・リソー ス「jdbc/__default」を使用 認証対象のユーザ、パスワードが保存されているデータベースのテ ーブル名 ユーザ名列 設定値:APP.USERTABLE ユーザ・テーブルのユーザ名のカラム名 パスワード列 設定値:USERNAME ユーザ・テーブルのパスワードのカラム名 グループ表 設定値:PASSWORD 所属グループが保存されているデータベースのグループ名 グループ表ユーザ名 列 設定値:APP.GROUPTABLE グループ・テーブルのユーザ名のカラム名 グループ名列 設定値:USERNAME グループ・テーブルのグループ名のカラム名 パスワード暗号化 アルゴリズム 設定値:GROUPID データベースに格納されるパスワードを暗号化するためのアルゴリ ズム グループの割当て 設定値:AES グループ名のカンマ区切りリスト データベース・ユー ザー 設定値:省略 JDBC のコネクション・プールを使用しない場合の DB への接続ユ ーザ名 データベース・パス ワード 設定値:省略 今回 JDBC リソース(jdbc/__default)を利用するため省略 JDBC のコネクション・プールを使用しない場合の DB への接続パ スワード ダイジェスト・ アルゴリズム   設定値:省略 今回 JDBC リソース(jdbc/__default)を利用するため省略 パスワードのダイジェスト・アルゴリズムを指定 73  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   設定値:SHA-256 (デフォルト値) エンコーディング パスワードのエンコーディング(Hex, Base 64 を指定可能) 文字セット 設定値:Hex ダイジェスト・アルゴリズムの文字セット 設定値:UTF-8 asadmin コマンドから、上記の設定項目を元に JDBC レルムを作成する場合、 下記のコマンドを実行してください。 $ ./asadmin create-auth-realm --classname com.sun.enterprise.security.ee.auth.realm.jdbc.JDBCRealm --property jaas-context=jdbcRealm: datasource-jndi=jdbc/__default: user-table=APP.USERTABLE: user-name-column=USERNAME: password-column=PASSWORD: group-table=APP.GROUPTABLE: group-table-user-name-column=USERNAME: group-name-column=GROUPID: digestrealm-password-enc-algorithm=AES: digest-algorithm=SHA-256: encoding=Hex: charset=UTF-8 jdbc-realm $ ./asadmin set server-config.security-service.activate-defaultprincipal-to-role-mapping=true GlassFish の管理コンソールから設定を行なう場合、ブラウザから下記 GlassFish の管理コンソールの URL にアクセスしてください。 http://localhost:4848 [Windows, Linux 環境] Windows, Linux 環境で、GlassFish の asadmin コマンド、もしくは GUI の管理コンソールにアクセスする際に、管理者パスワードの入力を促された 場合、デフォルトで設定されている管理者パスワードは、下記の方法で取得 できます。まず、NetBeans の「サービス」タブより「サーバ」→ 「GlassFish Server 4.0」を選択してください。選択した後右クリックし 「プロパティ」を選択してください。 ※ Mac OS/X の環境ではデフォルトで管理者パスワードの入力は求められ ません。   74  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   図  88: GlassFish の プロ パテ ィ 選択すると下記のウィンドウが表示されます。ここで「パスワード(W) :」と 記載されている箇所を確認します。ウィンドウを表示した時点では「●●● ●●」と表示されています。ここで「表示」ボタンを押下するとデフォルト のパスワードが表示されます。ここに記入されている内容をメモ帳などに控 えて実行してください。 図  89:GlassFish の デフ ォル ト・ パ スワ ード 取得   75  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   GlassFish の管理コンソールに接続すると下記のような画面が表示されます。 ここで、左ペインより「構成」→「server-config」→「セキュリティ」のツ リーを展開し「レルム」を選択してください。選択すると右ペインに「レル ム」の管理用ウィザードが表示されます。 図  90: GlassFish 管 理コ ンソ ール に おけ るレ ルム 設 定 ここで「新規...」ボタンを押下してください。新規ボタンを押下し「クラス 名 : 」 に 「 com.sun.enterprise.security.ee.auth.realm.jdbc.JDBCRealm 」 を選択すると下記の画面が表示されます。 ここで、「表   3:JDBC レルムの設定項目と設定値」の内容を記入して「OK」 ボタンを押下してください。   76  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   図  91: 新規 レル ムの 作 成画 面   77  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   新規 JDBCRealm を作成した後、デフォルトのロール・マッピングのプリン シパルを変更します。「図  91:新規レルムの作成画面」で「グループの割当 て:」の設定項目を未入力にしましたが、下記のチェックを付けておく事で、 アプリケーション・サーバが自動的にデータベースのグループ名をロール名 として利用できるようになります。7 また、今回ご紹介する方法では、Java EE 6 の Servlet 3.0 で追加された、 login, logout のメソッドも利用します。 図  92: デ フォ ルト のロ ー ル・ マッ ピン グ のプ リン シ パル の 設定 以上で JDBC レルムを作成し、データベースに存在するユーザ・グループテ ーブルを認証目的で利用できるようになりました。 5.3 認証設定、認証コードの実装、動作確認 上記でアプリケーション・サーバから認証用データベースの参照ができるよ うになりました。そこで、ここではアプリケーション側で認証設定、実装を 行ないます。 まず、Web アプリケーションで認証ができるように設定変更を行ないます。 プロジェクト「WebSocket-Mailer」→「Web ページ」→「WEB-INF」デ ィレクトリ配下に存在する「web.xml」をダブル・クリックしてください。 ダブル・クリックすると NetBeans の右ペインに下記の画面が表示されます。 そこで「セキュリティ」タブを押下してください。                                                                                                                 7  グループ名とロール名は必ずしも一致させる必要はありませんし、一つのロールに対して 複数のグループを割り当てる事もできます。これらの設定を行なう場合は、XML の設定ファ イルで行ないます。     78  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   図  93: web.xml の 編集 タブを押下すると下記の画面が表示されます。ここで「ログイン構成」を行 ないます。今回、FORM 認証を行いますので「フォーム(F)」のラジオボタ ンにチェックします。次にログインページとして「login」ディレクトリ配下 に存在する「index.xhtml」ファイルを使用しますので「フォームのログイ ン・ページ(L):」に「/faces/login/index.xhtml」を入力します。また「フォ ームのエラー・ページ(P):」に「/faces/login/error.xhtml」と入力してくだ さい。 また、認証方式には「表  3:JDBC レルムの設定項目と設定値」で設定した JDBC レルムを使用するため、「レルム名(R):」には「jdbc-realm」と入力 してください。全て入力したのち web.xml を保存してください。 図  94: ログ イン 構成 の 設定 保存すると、下記のコードが「web.xml」に記載されます。   79  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   <web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"> 前略・・・ <login-config> <auth-method>FORM</auth-method> <realm-name>jdbc-realm</realm-name> <form-login-config> <form-login-page>/faces/login/index.xhtml</form-login-page> <form-error-page>/faces/login/error.xhtml</form-error-page> </form-login-config> </login-config> 後略・・・ </web-app> 続いて「セキュリティ」の「セキュリティ・ロール」を設定します。今回デ ータベースに登録したユーザが所属するグループ・テーブルは「admin」も しくは「user」の役割として登録しています。そこで「セキュリティ・ロー ル」に対して2つのロールを追加してください。「追加(A)...」ボタンを押下 して下記2つのロールを追加してください。ロールを追加後「web.xml」フ ァイルを保存してください。 図  95: セキ ュリ ティ ・ ロー ルの 設定 保存すると、下記のコードが「web.xml」に記載されます。 <web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"> 前略・・・ <security-role> <description>管理者用のロール</description> <role-name>admin</role-name> </security-role> <security-role> <description>一般ユーザ用のロール</description> <role-name>user</role-name> </security-role>   80  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   後略・・・ </web-app> 最後に「セキュリティ制約」を設定します。「セキュリティ制約の追加」ボ タンを押下してください。 図  96: セキ ュリ ティ 制 約の 追加 ボタンを押下すると下記の画面が表示されます。ここで新しいセキュリティ 制約を追加します。「表示名(N):」に「Authrized Resource」(識別用の任 意の文字)と入力してください。 続いて「web リソース・コレクション(W):」の「追加(A)...」ボタンを押下し 「名前」、「URL パターン」、「HTTP メソッド」、「説明を」入力してく ださい。ここでは、「/faces/login/*」ディレクトリ配下に存在する全 Web ページに対して制約を掛けます。また HTTP のメソッドとして「GET」もし くは「POST」を許可します。 次に「認証制約を有効にする(H)」のチェック・ボタンにチェックし、「編集 (I)」ボタンを押下してください。ボタンを押下すると「図  95:セキュリテ ィ・ロールの設定」で設定したロールが表示されますので「admin」、 「user」のロールを「追加 >」のボタンを押下して追加し「OK」ボタンを押 下してください。 最後に「/faces/login/*」ディレクトリ配下に存在する Web ページに対して HTTPS で接続する設定を行ないます。「ユーザ・データ制約を有効にする (U)」にチェックし「トランスポート保証(T)」のコンボ・ボックスより 「CONFIDENTIAL」を選択してください。設定が完了したのち「web.xml」 ファイルを保存してください。   81   図  97: セキ ュリ ティ 制 約の 追加
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   保存すると、下記のコードが「web.xml」に記載されます。 <web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"> 前略・・・ <security-constraint> <display-name>Authorized Resource</display-name> <web-resource-collection> <web-resource-name>protected-page</web-resource-name> <description>ログイン認証後に表示されるリソース</description> <url-pattern>/faces/login/*</url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> </web-resource-collection> <auth-constraint> <description>認証完了したユーザが参照できるリソース</description> <role-name>admin</role-name> <role-name>user</role-name> </auth-constraint> <user-data-constraint> <description>このリソースに対しては HTTPS での接続が必須</description> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint> 後略・・・ </web-app> 以上で、アプリケーションの設定は完了です。 それでは、ここでプロジェクトを実行して設定後の Web アプリケーション の振る舞いを確認してみましょう。NetBeans より「WebSocket-Mailer」 プロジェクトを選択し実行してください。実行するとブラウザ上で下記の画 面が表示されます。   図  98: プロ ジェ クト の 実行     82  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   ここで、「ログイン画面へ」のリンクを押下してください。「図  97:セキュ リティ制約の追加」の「トランスポート・保証」の設定で「CONFIDENTIAL」 と設定した通り、自動的に 「https:localhost:8181/******」 へリダイレクト される事を確認できます。 図  99: CONFIDENTIAL 設 定に よる HTTPS へ リダ イレ クト また、現在「/faces/login/」ディレクトリ配下には「index.xhtml」の他に 「home.xhtml」のファイルが存在しますが、「/faces/login/*」ディレクト リ配下のコンテンツにアクセス制限が掛かっているかを確認します。ログイ ンしていない状態でブラウザより下記の URL にアクセスしてください。 https://localhost:8181/WebSocket-Mailer/faces/login/home.xhtml 「/faces/login/」ディレクトリ配下のコンテンツに直接 URL を指定してア クセスしても「ログイン画面」が表示されアクセス制限が掛かっていること を確認できます。 図  100: コン テン ツに 対 する アク セス 制 限   83  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   それでは実際に、認証を行なうためのコードを実装します。「IndexPage」 クラスの「login」メソッドに対して下記のコードを実装してください。ここ では「Java EE 6」の「Servlet 3.0」に含まれる「HttpServletRequest」 で新たに追加されたメソッド「login」メソッドを使用してログイン処理を行 なっています。 ログインが成功した際、画面遷移先の return 値として「home.xhtml」と指 定していますが、URL だけではなく下記のようにリダイレクトも指定してい ます。「home.xhtml?faces-redirect=true」このリダイレクトの設定は 非常に重要です。JSF ではリダイレクト指定を行なう事で URL が 「/faces/login/home.xhtml」へ切り代わり(リダイレクトされ)ます。 リダイレクトを行なわない場合、URL は「/faces/login/index.xhtml」のま ま、「home.xhtml」の内容が表示されます。 「図  97:セキュリティ制約の追加」で設定したように「/faces/login/*」デ ィレクトリ配下に存在する Web ページは、認証完了後「admin, user」の権 限を持つユーザだけが表示できます。しかし URL が変わらない場合(つまり ログインページのと同じ URL の場合)、仮に DB との認証に成功したユーザ で、「/faces/login/*」ディレクトリ配下にアクセス権限を持たないユーザ が存在した場合、URL が切り替わらないため「home.xhtml」の内容が表示 されてしまいます。リダイレクトを行なうことで正しく認可機能が働きます ので必ずリダイレクトを行なってください。 リダイレクト設定により、所属するグループのロールによって認可されてい ない(ここでは admin, user 以外のグループのメンバー)場合、サーバから 「HTTP Status 403 - Forbidden」が返されるようになります。 @Named(value = "indexPage") @RequestScoped public class IndexPage { public String login() { FacesContext context = FacesContext.getCurrentInstance(); ExternalContext externalContext = context.getExternalContext(); HttpServletRequest request = (HttpServletRequest) externalContext.getRequest(); try { request.login(getUsername(), getPassword()); } catch (ServletException ex) { context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "ログインに失敗しました。", "ユーザ名、パスワードを正しく入力してください。")); return ""; } return "home.xhtml?faces-redirect=true"; } } つづいて、「IndexPage」クラスに対してログアウト用の「logout」メソッ ドも実装してください。ここではセッション情報を持つ場合破棄し、Servlet 3.0 の「HttpServletRequest」に新しく追加された「logout」メソッドを   84  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   使用してログアウトを行なっています。処理が終わったのち「index.xhtml」 へリダイレクトしています。 @Named(value = "indexPage") @RequestScoped public class IndexPage { public String logout() { ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext(); externalContext.invalidateSession(); HttpServletRequest request = (HttpServletRequest) externalContext.getRequest(); try { request.logout(); } catch (ServletException ex) { Logger.getLogger(IndexPage.class.getName()). log(Level.SEVERE, “ログアウト失敗”, ex); } return "index.xhtml?faces-redirect=true "; } } 以上で、認証設定と認証コードの実装は完了です。 それでは実際に DB に登録されているユーザで認証、認可ができているか確 認します。 今データベースには「admin」、「user」というユーザが登録されています。 ※登録していない場合、再度「図  67:ユーザ情報登録画面」を参照し登録し てください。 図  101: デー タベ ース に 登録 され てい る 情報 確認 また、「admin」ユーザに対して所属グループは「admin」、「user」ユー ザに対して所属グループは「user」が設定されていることを確認してくださ い。 図  102: デー タベ ース に 登録 され てい る 情報 確認   85  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   これらのユーザ名、パスワードを利用してログインができるか否かを確認し ます。プロジェクトを実行して「ログイン画面」を表示し、ユーザ名 「admin」、パスワード「admin」を入力したのち、「ログイン」ボタンを 押下してください。 図  103: ログ イン 画面 「ログイン」ボタンを押下すると画面が遷移し、ブラウザ上で下記のメッセ ージが表示されます。この際、画面遷移先の URL が下記のように 「home.xhtml」へ正しくリダイレクトされている事も確認してください。 https://localhost:8181/WebSocket-Mailer/faces/login/home.xhtml 図  104: admin  ユ ーザ のロ グイ ン 完了 画面 ここで、「ログアウト」ボタンを押下してください。再度「ログイン画面」 が表示されますので、続いて「user」でログインします。 図  105: ログ イン 画面   86  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   「ログイン」ボタンを押下すると画面が遷移し、ブラウザ上で下記のメッセ ージが表示されます。 図  106: user  ユ ーザ のロ グイ ン 完了 画面 上記で、「admin」、「user」でログインできるようになりましたので、デ ータベースに対して新たなユーザ「invaliduser」を追加し、コンテンツに対 してアクセスが認められていない所属グループ「invalidgroup」を設定しま す。ユーザ情報登録画面に接続し、下記の内容を登録してください。パスワ ードはここでは「invaliduser」としています。 図  107: コン テン ツに ア クセ スが 禁じ ら れて いる ユ ーザ の 作成 登録が完了すると下記がブラウザに表示されます。 図  108: コン テン ツに ア クセ スが 禁じ ら れて いる ユ ーザ の作 成 完了   87  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   ユーザを登録後、再度「ログイン画面」に接続して作成した「invaliduser」 でログインを行なってください。 図  109:invalid  ユ ーザ でロ グイ ン 「ログイン」ボタンを押下するとブラウザ上に下記が表示されます。 図  110: HTTP  Status  403  -­‐  Forbidden  の 表示 以上で、「/faces/login/*」ディレクトリ配下に存在するコンテンツが 「admin」もしくは「user」の役割を持つユーザしかアクセスできない事が 確認できました。上記でデータベースによる認証・認可を確認できました。 5.4 細かいカスタマイズ 上記により、認証・認可を実現するための設定、実装、検証は終わりました が、現時点の実装ではいくつか仮題が残っています。たとえば、ログインが 完了した後でも、「ログイン画面」を表示可能です。またログイン後、自動 的に「home.xhtml」へ画面遷移した後、ブラウザの戻るボタンで「ログイ ン画面」へ戻ることも可能です。さらには、アクセス権限がないユーザがロ グインした際に「図  110:HTTP  Status  403  -­‐  Forbidden  の表示」が表示される ことも画面設計上好ましくありません。そこでそれらの仮題に対して対応を 行ないます。   88  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   ログイン完了後、ログイン画面を非表示 現在、たとえば「admin」でログインした後に再度「ログイン画面」の URL にアクセスすると再度「ログイン画面」が表示されます。 図  111:admin  に よる ログ イン ログインが完了した後、ブラウザのアドレス・バーに直接下記の URL を入力 しアクセスしてください。下記の画面が表示されます。 図  112: ログ イン 画面 の 再表 示 一度、ログインしたユーザに、ログアウトするまで上記の画面を二度と表示 させないようにするために、JSF の Facelets と CDI をそれぞれ修正します。 8                                                                                                                 8  以降では admin, user のユーザを利用してください。本 Web アプリケーションでは invaliduer のためのログアウト・コードを実装していません。仮に Invaliduesr でログイン してしまった場合は、一度ブラウザを閉じて再度立ち上げ直してログインしなおしてくださ い。   89  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   まず、CDI 側の編集を行ないます。IndexPage クラスに対して新たに 「onPageLoad()」メソッドを作成してください。このメソッドは、メソッ ドが呼び出された際、「HttpServletRequest」の「getUserPrincipal()」 メソッドを呼び出し「Principal」オブジェクトを取得しています。一旦ログ インが完了したユーザはこの「Principal」オブジェクトに値が代入されてい ます。そこで、このオブジェクトが null でない場合は、ログイン済みのユー ザと判定できます。仮にログイン済みのユーザの場合は、ログイン後に表示 するページ「/home.xhtml」へ強制的にリダイレクトします。 @Named(value = "indexPage") @RequestScoped public class IndexPage { /* 既にログイン済みだった場合、ログイン後のページ(home.xhtml)へリダイレクトし login.xhtml を非表示 */ public void onPageLoad() throws ServletException { FacesContext context = FacesContext.getCurrentInstance(); ExternalContext externalContext = context.getExternalContext(); HttpServletRequest request = (HttpServletRequest) externalContext.getRequest(); Principal principal = request.getUserPrincipal(); if(principal != null){ try { StringBuilder redirectURL = new StringBuilder(request.getContextPath()); redirectURL.append("/faces/login/home.xhtml"); FacesContext.getCurrentInstance().getExternalContext(). redirect(redirectURL.toString()); } catch (IOException ex) { request.logout(); } } } } 次に「index.xhtml」の Web ページ側を修正します。「index.xhtml」ファ イルを開き、下記「f:event」タグの1行を追加してください。 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:p="http://primefaces.org/ui" xmlns:f="http://xmlns.jcp.org/jsf/core"> <h:head> <title>JSF-WebSocket WebMail ログイン画面</title> <f:event type="preRenderView" listener="#{indexPage.onPageLoad}"/> </h:head> <h:body> <h:form> これにより「index.xhtml」へアクセスされた際、ビューがレンダリングを行 なう前に、「IndexPage#onPageLoad()」メソッドが呼び出され、既にロ   90  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   グイン済みの場合は、強制的に「home.xhtml」へリダイレクトするように なります。 上記を修正した後、動作確認をしてください。「admin」でログイン後、ブ ラウザのアドレス・バーに対して下記の URL を入力して直接「index.xhtml」 へアクセスしてください。 図  113: ログ イン 完了 後 、ア ドレ ス・ バ ーか ら index.xhtml に 強制 アク セス アドレス・バーから直接入力した場合、「home.xhtml」へリダイレクトさ れることを確認できます。 以上で、ログイン後は「ログイン画面」が表示されなくなります。   91  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   ブラウザの「戻る」ボタンによるログイン画面の非表示 上記の対応で、直接「index.xhtml」へアクセスされた場合はリダイレクトさ れるようになりました。しかし、ログイン後にブラウザの「戻る」ボタンを 押下された場合は「ログイン画面」が表示されてしまいます。そこで「戻る」 ボタンに対応したいと思います。これは一般的な JavaScript のコードを追 加し実現します。「index.xhtml」ファイルに対して<script></script> タグ部分を追記してください。 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:p="http://primefaces.org/ui" xmlns:f="http://xmlns.jcp.org/jsf/core"> <h:head> <title>JSF-WebSocket WebMail ログイン画面</title> <f:event type="preRenderView" listener="#{indexPage.onPageLoad}"/> </h:head> <script> window.onunload = function() { }; history.forward(); </script> <h:body> <h:form> <center> 上記を記述した後、再度実行すると一度ログインした後、二度と「ログイン 画面」が表示される事はなくなります。   92  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   HTTP Status 403 発生時に表示するエラー・ページ さて、現在「invaliduer」などアクセス権限がないユーザがログインした際 に「図  110:HTTP  Status  403  -­‐  Forbidden  の表示」で示したようにアプリケー ション・サーバが用意するエラー・ページが表示されます。そこで、発生す る例外や HTTP のステータス・コードに応じて特定のエラー・ページを表示 させるように設定変更を行ないます。 まず、「Web ページ」ディレクトリ配下にエラー・ページ用のフォルダ 「errors」を作成してください。 図  114: エラ ー・ ペー ジ 用の フォ ルダ を 作成 次に、「errors」ディレクトリ配下にファイル名「error-403.xhtml」の JSF ページを作成してください。 図  115:error-­‐403.xhtml フ ァイ ルの 作成   93  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   「error-403.xhtml」には、下記のコードを記載します。 <?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html"> <h:head> <title>アクセス禁止</title> </h:head> <h:body> <h:form> 指定のコンテンツに対してアクセスする権限がありません。<br/> <h:link value="Top ページ" outcome="/index.xhtml"/> </h:form> </h:body> </html> エラー・ページを作成した後、「web.xml」を編集して HTTP のステータ ス・コード:403 が帰ってきた際に「error-403.xhtml」を表示するように 設定します。「web.xml」ファイルをダブル・クリックして選択し「ページ」 タブを押下してください。タブを押下すると下記の画面が表示されます。こ こで「エラー・ページ」より「追加(A)...」ボタンを押下してください。 図  116:web.xml ファイルの編集   94    
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   ボタンを押下すると下記「エラー・ページの追加」ウィンドウが表示されま す。ここで「参照...」ボタンを押下すると「ファイルを参照」ウィンドウが 表示されますので、作成した「error-403.xhtml」ファイルを選択し、「フ ァイルを選択」ボタンを押下してください。 図  117: エラ ー・ ペー ジ の追 加 ファイルを選択すると下記画面が表示されます。ここで「OK」ボタンを押下 してください。 図  118: エラ ー・ ペー ジ の追 加 ボタンを押下すると下記の画面が表示されます。表示後「web.xml」ファイ ルを保存してください。 図  119: エラ ー・ ペー ジ の追 加     95  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   ファイルを保存すると「web.xml」に下記が追加されます。 <web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"> 前略… <error-page> <error-code>403</error-code> <location>/errors/error-403.xhtml</location> </error-page> 後略… </web-app> ここで、静的な HTML ファイルであれば上記設定で問題ありませんが、エラ ー・ページも JSF のページとして実装したい場合、上記では動作しません。 そこで、エラー・ページも JSF のページとして実装したい場合、下記のよう に「/faces」を先頭に追加して保存してください。 <error-page> <error-code>403</error-code> <location>/faces/errors/error-403.xhtml</location> </error-page> 最後に実行して、新たに作成したエラー・ページが表示されるか否か確認し てください。「ログイン画面」を表示し「invaliduser」でログインしてくだ さい。 図  120:invaliduser  で ログ イン ボタンを押下すると下記のエラー画面が表示されます。9 図  121: アク セス 禁止 エ ラー ・ペ ージ の 表示                                                                                                                 9  今回は invaliduser のログアウト・メソッドを実装していません。そこで他のユーザ・アカ ウントで再度ログインできるようにするためには、Invaliduser 用のログアウト処理を別途実 装するか、もしくはブラウザを再起動してください。     96  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   今回は、HTTP ステータス・コード 403 に対するエラー・ページを作成し ましたが、同様の手順で他のステータス・コードに対するエラー・ページを 用意できる他、特定の例外(Exception)が発生した時に表示するエラー・ペー ジを設定する事も可能です。エラー・ページをカスタマイズしたい場合は、 ここで行なってください。 5.5 処理単位でのアクセス制限方法 ここまでは、接続 URL の単位でアクセス制限をかけてきました。これを利用 すると特定の役割を持つ人しかアクセスができないページに誘導する事もで きます。 しかし、レルムを使用すると、さらに機能単位でアクセス制限、実行権限を 指定する事もできます。例えば、今「/faces/login/*」ディレクトリ配下の コンテンツは、「admin」もしくは「user」の役割を持つユーザであれば、 誰でも「home.xhtml」に対して接続ができました。しかし、この 「home.xhtml」のページ内で共通に表示されるコンテンツの他に、 「admin」だけが表示できるコンテンツ、もしくは「user」だけが表示でき るコンテンツといったように役割に応じて画面表示を切り変えたい場合もあ ります。このような場合、プログラム側でアクセス制限を掛けることも可能 です。 ここでは、「home.xhtml」を利用して「admin」だけが表示されるコンテ ンツ、もしくは「user」だけが表示されるコンテンツの作成を行ないたいと 思います。 まず、「home.xhtml」に対応する「JSF 管理対象 Bean」を 「HomePage.java」として作成してください。 図  122: home.xhtml 用 の JSF 管 理対 象 Bean の 作成   97  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   「JSF 管理対象 Bean」を作成するとコードが自動的に生成されます。ここ で、下記のようにログインしたユーザが、引数で指定したロールをもつユー ザか否かを検証するメソッド「isUserInRole()」を実装してください。 package jp.co.oracle.websocket.mailer.cdis; import javax.inject.Named; import javax.enterprise.context.RequestScoped; import javax.faces.context.FacesContext; /** * * @author Yoshio Terada */ @Named(value = "homePage") @RequestScoped public class HomePage { /** * Creates a new instance of HomePage */ public HomePage() { } /* ログインしたユーザが、引数で指定した役割(ロール)を持つ ユーザか否かを検証 */ public boolean isUserInRole(String role){ return FacesContext.getCurrentInstance(). getExternalContext().isUserInRole(role); } } 次に、「home.xhtml」に下記 <h:outputLabel> を追加してください。ここ で、JSF タグ内の rendered 属性の true, false で描画内容を切り替えて います。例えば「admin」権限を持つユーザがログインした場合は「管理者 の表示文字列」が表示され、「user」権限を持つユーザがログインした場合 は、「ユーザの表示文字列」が表示されます。 <h:form> ログインユーザ名:<h:outputLabel value="#{request.userPrincipal.name}"/>でログインしました。<br/> <h:outputLabel value="管理者の表示文字列" rendered="#{homePage.isUserInRole('admin')}"/> <h:outputLabel value="ユーザの表示文字列" rendered="#{homePage.isUserInRole('user')}"/> <br/> <h:commandButton value="ログアウト" action="#{indexPage.logout()}"/> </h:form>   98  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   「home.xhtml」を保存したのち、プロジェクトを実行してください。実行 した後、「admin」、「user」それぞれでログインした際、下記のように画 面が表示されます。 図  123: 役割 に応 じた 画 面表 示 また、EJB を使った場合は役割に応じてメソッド単位で実行権限を指定する 事も可能です。EJB のメソッド単位での実行権限の検証を行なうために新た に EJB を作成してください。 EJB のパッケージを選択し右クリックしてください。右クリックするとメニ ューが表示されますので「新規」→「その他」を選択してください。 図  124: 新規 EJB の 作成   99  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   選択すると下記のウィンドウが表示されます。ここで「カテゴリ(C):」より 「エンタープライズ JavaBeans」、「ファイル・タイプ(F):」より「セッシ ョン Bean」を選択し「次 >」ボタンを押下してください。 図  125: 新規 EJB の 作成 ボタンを押下すると下記の画面が表示されます。ここで「EJB 名(N):」に 「RoleCheckLogic」と入力し「終了(F)」ボタンを押下してください。   100  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   ボタンを押下するとステートレス・セッション Bean が自動生成されます。 ここで、@RolesAllowed のアノテーションを付加した2つのメソッドを追 加してください。このアノテーションを付加したメソッドは、該当の役割を 持つユーザしか実行できなくなります。 仮に権限を持たないユーザが実行した場合、例外が発生するようになります。 package jp.co.oracle.websocket.mailer.ejbs; import javax.annotation.security.RolesAllowed; import javax.ejb.Stateless; /** * * @author Yoshio Terada */ @Stateless public class RoleCheckLogic { @RolesAllowed("admin") public String executableByAdmin() { return "管理者による実行が可能なロジック"; } @RolesAllowed("user") public String executableByUser() { return "ユーザによる実行が可能なロジック"; } } 実際に実行権限の無いユーザが上記メソッドを呼び出した場合、下記のよう に javax.ejb.AccessLocalException が送出されます。 警告: StandardWrapperValve[Faces Servlet]: Servlet.service() for servlet Faces Servlet threw exception javax.ejb.AccessLocalException: クライアントはこの起動を承認されていません at com.sun.ejb.containers.BaseContainer.preInvoke(BaseContainer.java:1895) at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocation Handler.java:210) at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectIn vocationHandlerDelegate.java:88) at com.sun.proxy.$Proxy727.executableByAdmin(Unknown Source) at jp.co.oracle.websocket.mailer.ejbs.__EJB31_Generated__RoleCheckLogic__Intf____Bean__.e xecutableByAdmin(Unknown Source) at jp.co.oracle.websocket.mailer.cdis.HomePage.getRoleChekerString(HomePage.java:31)   101  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   次に、上記の EJB のビジネス・ロジックを呼び出すために、CDI にメソッド を追加します。10「HomePage」クラスに対して下記のコードを追加してく ださい。下記では作成した EJB をインジェクトし、「admin」権限を持つ場 合、executableByAdmin()メソッドを実行し、「user」権限を持つ場合、 executableByUser()メソッドを実行しています。 @Named(value = "homePage") @RequestScoped public class HomePage { 前略… @EJB RoleCheckLogic roleCheckLogic; private String roleChekerString; public String getRoleChekerString() { if (isUserInRole("admin")) { String adminRoleString = roleCheckLogic.executableByAdmin(); roleChekerString = adminRoleString; } if (isUserInRole("user")) { String userRoleString = roleCheckLogic.executableByUser(); roleChekerString = userRoleString; } return roleChekerString; } 後略… } 最後に roleChekerString の文字列を画面に表示するために「home.xhtml」 ファイルを編集します。<h:outputLabel>の2行を追加してください。 前略… <h:body> <h:form> ログインユーザ名:<h:outputLabel value="#{request.userPrincipal.name}"/> でログインしました。<br/> <h:outputLabel value="EJB 呼び出し結果:" /> <h:outputLabel value="#{  homePage.roleChekerString}" /><br/> 後略…                                                                                                                 10  @RolesAllowed アノテーションは Servlet,  JAX-­‐RS 等でも利用できますが、CDI では利用で きません。CDI も宣言的にアクセス制限を掛けたい場合、独自の Interceptor を実装する方法 などがあります。参考: http://www.mirkosertic.de/doku.php/architecturedesign/weldsewithee     102  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   修正後、プロジェクトを実行してください。下記のように権限に応じた実行 結果が得られます。 図  126: 宣言 的な アク セ ス制 限 このようにして、Java EE のセキュリティ機構を使用すると、プログラム側 でもより安全にアクセスの制限を掛ける事ができるようになります。 @RolesAllowed のアノテーション以外に、Java EE では @DeclareRoles, @PermitAll, @DenyAll, @RunAs 等のアノテーションを付加してアクセス 制限を掛けることができるほか、ロールを設定する事ができますので、これ らを利用してよりセキュアな Java EE のアプリケーションを構築してくださ い。 プログラム上で実装するセキュリティのより詳しい情報は下記の URL などを ご参照ください。 The Java EE 6 Tutorial Securing Enterprise Beans http://docs.oracle.com/javaee/6/tutorial/doc/bnbyl.html sli   103  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4     104  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   Appendix.1 pom.xml  の 設定内容   下記に、ハンズオン・ラボで作成するプロジェクトの pom.xml の設定内容 を記載します。 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>jp.co.oracle</groupId> <artifactId>WebSocket-Mailer</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>WebSocket-Mailer</name> <repositories> <repository> <id>prime-repo</id> <name>PrimeFaces Maven Repository</name> <url>http://repository.primefaces.org</url> <layout>default</layout> </repository> </repositories> <properties> <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir> <project.build.sourceEncoding>UTF8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>7.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.primefaces</groupId> <artifactId>primefaces</artifactId> <version>4.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.7</source>   105  
  • Java  EE  7  Hands-­‐on  Lab  using  GlassFish  4   <target>1.7</target> <compilerArguments> <endorseddirs>${endorsed.dir}</endorseddirs> </compilerArguments> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.3</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>2.6</version> <executions> <execution> <phase>validate</phase> <goals> <goal>copy</goal> </goals> <configuration> <outputDirectory>${endorsed.dir}</outputDirectory> <silent>true</silent> <artifactItems> <artifactItem> <groupId>javax</groupId> <artifactId>javaee-endorsedapi</artifactId> <version>7.0</version> <type>jar</type> </artifactItem> </artifactItems> </configuration> </execution> </executions> </plugin> </plugins> </build> </project> 以上   106