第2章 セキュリティーの概要
2.1. 宣言的セキュリティー
宣言的セキュリティー とは、セキュリティー管理にコンテナを使うことで、お使いのアプリケーションコードからセキュリティーの問題を切り離す方法です。コンテナにより、ファイルのパーミッション、またはユーザー、グループ、ロールに基づき承認を行います。このアプローチは、セキュリティー関連すべてをアプリケーション自体で請け負うプログラム的セキュリティーよりも優れています。
JBoss EAP 6 はセキュリティードメインより宣言的セキュリティーを提供します。
2.1.1. Java EE 宣言型セキュリティーの概要
J2EE セキュリティーモデルは宣言的で、セキュリティーをビジネスコンポーネントに埋め込まずに、セキュリティーロールおよびパーミッションを標準的な XML 記述子で記述します。セキュリティーは、コンポーネントのビジネスロジックに固有のものではなく、コンポーネントがデプロイされる場所の機能となる傾向にあるため、このモデルによりセキュリティーがビジネスレベルコードより隔離されます。たとえば、銀行の預金口座を利用するために使用する ATM の場合、預金口座へのアクセス方法、口座を管理する銀行、ATM の場所などの条件によって、セキュリティー要件、ロール、およびパーミッションが大きく異なります。
J2EE アプリケーションは、標準の J2EE デプロイメント記述子によって指定されたアプリケーションセキュリティー要件を基にセキュア化されます。
ejb-jar.xml
および web.xml
デプロイメント記述子を使用して、エンタープライズアプリケーションの EJB および Web コンポーネントへのアクセスをセキュア化します。
2.1.2. セキュリティーの参照
Enterprise Java Bean (EJB) およびサーブレットは、1 つまたは複数の <security-role-ref> 要素を宣言できます。
図2.1 セキュリティーロール参照モデル
この要素は、コンポーネントが <role-name> 要素の
role-nameType
属性値を isCallerInRole(String)
メソッドへの引数として使用することを宣言します。isCallerInRole
メソッドを使用すると、コンポーネントは <security-role-ref> または <role-name> 要素で宣言されたロールに呼び出し元があるかどうかを検証できます。<role-name> 要素の値は、<role-link> 要素を介して <security-role> へリンクする必要があります。通常、isCallerInRole
は、ロールベースの <method-permissions> 要素を使用して定義できないセキュリティーチェックを実行するために使用されます。
例2.1 ejb-jar.xml 記述子の一部
<!-- A sample ejb-jar.xml fragment --> <ejb-jar> <enterprise-beans> <session> <ejb-name>ASessionBean</ejb-name> ... <security-role-ref> <role-name>TheRoleICheck<role-name> <role-link>TheApplicationRole</role-link> </security-role-ref> </session> </enterprise-beans> ... </ejb-jar>
注記
これは実例ではありません。デプロイメントでは、このセクションの要素に EJB デプロイメントに関連するロール名およびリンクが含まれている必要があります。
例2.2 web.xml 記述子の一部
<web-app> <servlet> <servlet-name>AServlet</servlet-name> ... <security-role-ref> <role-name>TheServletRole</role-name> <role-link>TheApplicationRole</role-link> </security-role-ref> </servlet> ... </web-app>
2.1.3. セキュリティーアイデンティティー (ID)
Enterprise Java Bean (EJB) は、<security-identity> 要素を使用してコンポーネント上でメソッドを呼び出すときに使用する必要がある、別の EJB の ID を指定できます。
図2.2 J2EE セキュリティーアイデンティティーデータモデル
呼び出し ID は現在の呼び出し元の ID、または特定のロールを指定できます。アプリケーションアセンブラーは、<security-identity> 要素と <use-caller-identity> 子要素を使用します。そのため、現在の呼び出し元の ID は、EJB によって実行されたメソッド呼び出しのセキュリティー IDとして伝播される必要があります。呼び出し元の ID の伝播は、<security-identity> 要素が明示的に宣言されていない場合に使用されるデフォルトの動作です。
また、アプリケーションアセンブラーで <run-as> または <role-name> 子要素を使用して、<role-name> 要素値によって提供される特定のセキュリティーロールが、EJB によって実行されたメソッド呼び出しのセキュリティー ID として使用されるように指定することも可能です。
EJBContext.getCallerPrincipal()
メソッドのように呼び出し元の ID が変更されないことに注意してください。呼び出し元のセキュリティーロールは、<run-as> または <role-name> 要素値によって指定された単一のロールに設定されます。
<run-as> 要素を使用すると、外部クライアントによる内部 EJB へのアクセスを防ぐことができます。この挙動を設定するには、内部 EJB の <method-permission> 要素を割り当てます。この要素は、外部クライアントへ割り当てられていないロールへのアクセスを制限します。この後、内部 EJB を使用しなければならない EJB は、<run-as> または <role-name> が制限されたロールと同等として設定されます。以下の記述子の断片は、<security-identity> 要素の使用例を記述します。
<ejb-jar> <enterprise-beans> <session> <ejb-name>ASessionBean</ejb-name> <!-- ... --> <security-identity> <use-caller-identity/> </security-identity> </session> <session> <ejb-name>RunAsBean</ejb-name> <!-- ... --> <security-identity> <run-as> <description>A private internal role</description> <role-name>InternalRole</role-name> </run-as> </security-identity> </session> </enterprise-beans> <!-- ... --> </ejb-jar>
<run-as> を使用して特定のロールを発信呼び出しへ割り当てると、
anonymous
という名前のプリンシパルがすべての発信呼び出しへ割り当てられます。別のプリンシパルを呼び出しに関連付けるには、<run-as-principal> を jboss.xml
ファイルの Bean に関連付けます。以下の断片は、internal
という名前のプリンシパルを前例の RunAsBean
に関連付けます。
<session> <ejb-name>RunAsBean</ejb-name> <security-identity> <run-as-principal>internal</run-as-principal> </security-identity> </session>
<run-as> 要素は、
web.xml
ファイルのサーブレット定義にもあります。以下の例は、InternalRole
ロールをサーブレットに割り当てる方法を示しています。
<servlet> <servlet-name>AServlet</servlet-name> <!-- ... --> <run-as> <role-name>InternalRole</role-name> </run-as> </servlet>
このサーブレットからの呼び出しは、匿名の
principal
に関連付けられます。run-as
ロールに従う特定のプリンシパルを割り当てるため、<run-as-principal> 要素は jboss-web.xml
ファイルにあります。以下の断片は、internal
という名前のプリンシパルを上記のサーブレットに関連付ける方法を示しています。
<servlet> <servlet-name>AServlet</servlet-name> <run-as-principal>internal</run-as-principal> </servlet>
2.1.4. セキュリティーロール
security-role-ref
または security-identity
要素によって参照されるセキュリティーロール名は、アプリケーションの宣言済みロールの 1 つへマップする必要があります。アプリケーションアセンブラーは、security-role
要素を宣言して論理セキュリティーロールを定義します。role-name
の値は、論理アプリケーションロール名になります (Administrator、Architect、SalesManager など)。
J2EE 仕様には、デプロイメント記述子のセキュリティーロールはアプリケーションの論理セキュリティービューを定義するために使用されることを考慮することが重要であると記載されています。J2EE デプロイメント記述子に定義されるロールを、ユーザーグループ、ユーザー、プリンシパル、および目的企業の操作環境に存在するその他の概念と混同してはなりません。デプロイメント記述子ロールは、アプリケーションドメイン固有の名前を持つアプリケーションコンストラクトです。たとえば、銀行取引のアプリケーションでは BankManager、Teller、Customer などをロール名として使用することがあります。
JBoss EAP では、
security-role
要素は security-role-ref/role-name
の値をコンポーネントロールが参照する論理ロールへマップためだけに使用されます。ユーザーの割り当てられたロールは、アプリケーションのセキュリティーマネージャーの動的関数です。JBoss では、メソッドパーミッションの宣言に security-role
の定義は必要ありません。しかし、アプリケーションサーバーにまたがる移植性を維持し、デプロイメント記述子を保持するため、security-role
要素を指定することが推奨されます。
例2.3 security-role 要素の使用を示す ejb-jar.xml 記述子の断片
<!-- A sample ejb-jar.xml fragment --><ejb-jar><assembly-descriptor><security-role><description>The single application role</description><role-name>TheApplicationRole</role-name></security-role></assembly-descriptor></ejb-jar>
例2.4 security-role 要素の使用を示す web.xml 記述子の断片の例
<!-- A sample web.xml fragment --><web-app><security-role><description>The single application role</description><role-name>TheApplicationRole</role-name></security-role></web-app>
2.1.5. EJB メソッドのパーミッション
アプリケーションアセンブラーは、method-permission 要素を宣言して EJB のホームおよびリモートインターフェースメソッドを呼び出せるロールを設定できます。
図2.3 J2EE メソッドパーミッション要素
各
method-permission
要素には、メソッド子要素によって特定された EJB メソッドへアクセスできる論理ロールを定義する 1 つ以上の role-name 子要素が含まれています。また、role-name
要素の代わりに unchecked
要素を指定して、認証されたすべてのユーザーがメソッド子要素によって特定されたメソッドにアクセスできることを宣言できます。さらに、exclude-list
要素があるメソッドにはアクセスできないことを宣言することも可能です。method-permission
要素を使用して、ロールによるアクセスが可能であると宣言されていないメソッドが EJB にある場合、EJB メソッドはデフォルトでは使用されません。これは、メソッドがデフォルトで exclude-list
に含まれるようにすることと同じです。
図2.4 J2EE メソッド要素
メソッド要素宣言のサポートされるスタイルは 3 つあります。
1 つ目のスタイルは、名前付きエンタープライズ Bean のホームおよびコンポーネントインターフェースメソッドをすべて参照するために使用されます。
<method><ejb-name>EJBNAME</ejb-name><method-name>*</method-name></method>
2 つ目のスタイルは、名前付きエンタープライズ Bean のホームまたはコンポーネントインターフェースの指定されたメソッドを参照するために使用されます。
<method><ejb-name>EJBNAME</ejb-name><method-name>METHOD</method-name></method>
同じオーバーロードされた名前を持つ複数のメソッドがある場合、このスタイルはすべてのオーバーロードされたメソッドを参照します。
3 つ目のスタイルは、オーバーロードされた名前を持つメソッドのセット内で指定されたメソッドを参照するために使用されます。
<method><ejb-name>EJBNAME</ejb-name><method-name>METHOD</method-name><method-params><method-param>PARAMETER_1</method-param><!-- ... --><method-param>PARAMETER_N</method-param></method-params></method>
メソッドは指定されたエンタープライズ Bean のホームまたはリモートインターフェースに定義する必要があります。method-param 要素の値は、対応するメソッドパラメータータイプの完全修飾名です。同じオーバーロードされたシグネチャーを持つメソッドが複数ある場合、パーミッションは一致するオーバーロードされたメソッドすべてに適用されます。
任意の
method-intf
要素は、エンタープライズ Bean のホームおよびリモートインターフェースの両方に定義された同じ名前やシグネチャーを持つメソッドを区別するために使用されます。
method-permission
要素の完全な使用例は、例2.5「method-permission 要素の使用を説明する ejb-jar.xml 記述子の断片」 を参照してください。
例2.5 method-permission 要素の使用を説明する ejb-jar.xml 記述子の断片
<ejb-jar><assembly-descriptor><method-permission><description>The employee and temp-employee roles may access any method of the EmployeeService bean </description><role-name>employee</role-name><role-name>temp-employee</role-name><method><ejb-name>EmployeeService</ejb-name><method-name>*</method-name></method></method-permission><method-permission><description>The employee role may access the findByPrimaryKey, getEmployeeInfo, and the updateEmployeeInfo(String) method of the AardvarkPayroll bean </description><role-name>employee</role-name><method><ejb-name>AardvarkPayroll</ejb-name><method-name>findByPrimaryKey</method-name></method><method><ejb-name>AardvarkPayroll</ejb-name><method-name>getEmployeeInfo</method-name></method><method><ejb-name>AardvarkPayroll</ejb-name><method-name>updateEmployeeInfo</method-name><method-params><method-param>java.lang.String</method-param></method-params></method></method-permission><method-permission><description>The admin role may access any method of the EmployeeServiceAdmin bean </description><role-name>admin</role-name><method><ejb-name>EmployeeServiceAdmin</ejb-name><method-name>*</method-name></method></method-permission><method-permission><description>Any authenticated user may access any method of the EmployeeServiceHelp bean</description><unchecked/><method><ejb-name>EmployeeServiceHelp</ejb-name><method-name>*</method-name></method></method-permission><exclude-list><description>No fireTheCTO methods of the EmployeeFiring bean may be used in this deployment</description><method><ejb-name>EmployeeFiring</ejb-name><method-name>fireTheCTO</method-name></method></exclude-list></assembly-descriptor></ejb-jar>
2.1.6. エンタープライズ Bean セキュリティーアノテーション
エンタープライズ Bean はアノテーションを使用し、アプリケーションのセキュリティーやその他の情報をデプロイヤーへ渡します。アノテーションまたはデプロイメント記述子に指定された場合、デプロイヤーはアプリケーションに対して適切なエンタープライズ Bean セキュリティーポリシーを設定できます。
アノテーションの値は、デプロイメント記述子に明示的に指定されたメソッドの値によって上書きされます。メソッドの値がデプロイメント記述子に指定されていない場合、アノテーションを使用して設定された値が使用されます。粒度の上書きはメソッドごとに行われます。
セキュリティーに対応し、エンタープライズ Bean で使用できるアノテーションには以下が含まれます。
@DeclareRoles
- コードに宣言された各セキュリティーロールを宣言します。ロールの設定に関する詳細情報は、『Java EE 5 Tutorial』 の Declaring Security Roles Using Annotations を参照してください。
@RolesAllowed
、@PermitAll
、および@DenyAll
- アノテーションのメソッドパーミッションを指定します。アノテーションメソッドパーミッションの設定に関する詳細は、『Java EE 5 Tutorial』 の Specifying Method Permissions Using Annotations を参照してください。
@RunAs
- コンポーネントの伝播されたセキュリティーアイデンティティーを設定します。伝播されたセキュリティーアイデンティティーをアノテーションを使用して設定する方法については、『Java EE 5 Tutorial』 の Configuring a Component’s Propagated Security Identity を参照してください。
2.1.7. Web コンテンツのセキュリティー制約
Web アプリケーションでは、保護されたコンテンツを識別する URL パターンよりコンテンツへのアクセスが許可されるロールによってセキュリティーが定義されます。この情報セットは、
web.xml
security-constraint 要素を使用して宣言されます。
図2.5 Web コンテンツのセキュリティー制約
セキュア化するコンテンツは、1 つ以上の <web-resource-collection> 要素を使用して宣言されます。各 <web-resource-collection> 要素には、任意の <url-pattern> 要素群と、これに続く任意の <http-method> 要素群が含まれます。<url-pattern> 要素の値は、リクエストがセキュア化されたコンテンツへのアクセスに対応するため、リクエスト URL が一致しなければならない URL パターンを指定します。<http-method> 要素の値は、許可する HTTP リクエストのタイプを指定します。
任意の <user-data-constraint> 要素は、クライアントサーバー接続のトランスポート層の要件を指定します。要件は、コンテンツの整合性 (通信プロセスでのデータ改ざんを防ぐ) または機密性 (送信中の読み取りを防ぐ) に関係することがあります。<transport-guarantee> 要素の値は、クライアントとサーバー間の通信に対する保護レベルを指定します。値は
NONE
、INTEGRAL
、および CONFIDENTIAL
になります。NONE
を指定すると、アプリケーションはトランスポートの保証を必要としません。INTEGRAL
の場合、アプリケーションはクライアントとサーバー間での送信中でデータが変更されない方法を必要とします。CONFIDENTIAL
の場合、アプリケーションは送信中のデータが他のエンティティーによって見られないようにする方法を必要とします。ほとんどの場合で、INTEGRAL
または CONFIDENTIAL
フラグが存在すると SSL の使用が必要になります。
任意の <login-config> 要素は、使用される認証メソッド、アプリケーションに使用されるレルム名、およびフォームログインのメカニズムに必要な属性を設定するために使用されます。
図2.6 Web ログインの設定
<auth-method> 子要素は、Web アプリケーションの認証メカニズムを指定します。承認制約によって保護された Web リソースへアクセスするには、設定されたメカニズムを使用してユーザーが認証されている必要があります。<auth-method> の有効な値は、
BASIC
、DIGEST
、FORM
、および CLIENT-CERT
です。<realm-name> 子要素は、HTTP ベーシックおよびダイジェスト認証で使用されるレルム名を指定します。<form-login-config> 子要素は、フォームベースのログインで使用されるログインおよびエラーページを指定します。<auth-method> 値が FORM
でない場合、form-login-config
と子要素は無視されます。
以下の設定例は、Web アプリケーションの
/restricted
パス下にある URL には /restricted
ロールが必要であることを示しています。トランスポート保証は必要なく、ユーザーアイデンティティーの取得に使用される認証メソッドは BASIC HTTP 認証です。
例2.6 web.xml 記述子の断片
<web-app> <security-constraint> <web-resource-collection> <web-resource-name>Secure Content</web-resource-name> <url-pattern>/restricted/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>AuthorizedUser</role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>NONE</transport-guarantee> </user-data-constraint> </security-constraint> <!-- ... --> <login-config> <auth-method>BASIC</auth-method> <realm-name>The Restricted Zone</realm-name> </login-config> <!-- ... --> <security-role> <description>The role required to access restricted content </description> <role-name>AuthorizedUser</role-name> </security-role> </web-app>
2.1.8. フォームベース認証の有効化
フォームベース認証では、ログインのカスタム JSP/HTML ページや、ログイン中にエラーが発生した場合にユーザーが移動される別のページを柔軟に定義できます。
フォームベースの認証を定義するには、デプロイメント記述子
web.xml
の <login-config> 要素に <auth-method>FORM</auth-method>
が含まれるようにします。ログインおよびエラーページも、以下のように <login-config> に定義されます。
<login-config> <auth-method>FORM</auth-method> <form-login-config> <form-login-page>/login.html</form-login-page> <form-error-page>/error.html</form-error-page> </form-login-config> </login-config>
フォームベース認証の Web アプリケーションがデプロイされると、Web コンテナは
FormAuthenticator
を使用してユーザーを適切なページに移動します。JBoss EAP はセッションプールを保持するため、リクエストごとに認証情報が存在する必要はありません。FormAuthenticator
がリクエストを受け取ると、既存のセッションに関して org.apache.catalina.session.Manager
をクエリします。セッションが存在しない場合、新しいセッションが作成されます。その後、FormAuthenticator
がセッションのクレデンシャルを検証します。
注記
各セッションは、セッション ID によって識別されます。セッション ID は、乱数値から生成された 16 バイトの文字列です。これらの値はデフォルトでは
/dev/urandom
(Linux の場合) より取得され、MD5 でハッシュ化されます。セッション ID は作成時にチェックされ、作成された ID が一意になるようにします。
検証後、セッション ID はクッキーの一部として割り当てられ、クライアントに返されます。後続のクライアントリクエストではクッキーがあることが想定され、ユーザーセッションの識別に使用されます。
クライアントへ渡されるクッキーは、名前と値のペアで、任意の属性が複数含まれています。識別子属性は
JSESSIONID
と呼ばれ、値はセッション ID の 16 進数列です。このクッキーは、非永続として設定されます。そのため、ブラウザーを終了するとクライアント側でこのクッキーが削除されます。サーバー側では、活動がないと 60 秒後にセッションが期限切れになり、セッションオブジェクトとそれらのクレデンシャルが削除されます。
ユーザーがフォームベースの認証で保護された Web アプリケーションにアクセスしようとすると、
FormAuthenticator
によってリクエストがキャッシュされ、必要な場合は新しいセッションが作成されます。さらに、ユーザーは login-config
に定義されたログインページへリダイレクトされます (前述のコード例では、ログインページは login.html
になります)。その後、ユーザーは提供される HTML フォームにユーザー名とパスワードを入力します。ユーザー名とパスワードは、j_security_check
フォームアクションを介して FormAuthenticator
へ渡されます。
次に、
FormAuthenticator
によって、ユーザー名とパスワードが Web アプリケーションコンテキストにアタッチされるレルムに対して認証されます。JBoss Enterprise Application Platform では、レルムは JBossWebRealm
になります。認証に成功すると、FormAuthenticator
によってキャッシュから保存されたリクエストが読み出され、ユーザーが元のリクエストへリダイレクトされます。
注記
サーバーは、URI が
/j_security_check
で終わり、最低でも j_username
および j_password
パラメーターが存在する場合のみ、フォーム認証リクエストを認識します。
2.1.9. 宣言型セキュリティーの有効化
これまで取り上げた Java EE セキュリティー要素は、アプリケーションの視点のみからセキュリティー要件を記述します。Java EE セキュリティー要素は論理ルールを宣言するため、アプリケーションデプロイヤーはロールをアプリケーションドメインからデプロイメント環境へマップします。Java EE 仕様は、このようなアプリケーションサーバー固有の詳細を省略します。
アプリケーションロールをデプロイメント環境にマップするには、JBoss EAP 固有のデプロイメント記述子を使用して Java EE セキュリティーモデルを実装するセキュリティーマネージャーを指定する必要があります。このセキュリティー設定の詳細は、カスタムログインモジュールの例を参照してください。