WebSphere Application Server Community Edition を使用した EJB アプリケーション・セキュリティーの構成方法

WebSphere® Application Server Community Edition 2.x ではクレデンシャル・ストア、run-as-subject および default-subject を導入していることから、そのセキュリティー構成は今までのバージョンとは異なります。そこで、この記事では、WebSphere Application Server Community Edition V2 を使用した EJB アプリケーション・セキュリティーの構成方法を説明します。セキュリティー関連のさまざまなアノテーションや EJB デプロイメント記述子の要素について、そしてセッション、エンティティー、およびメッセージ駆動型 EJB をセキュアにする Community Edition 固有のデプロイメント・プランについて十分に理解してください。

Vamsavardhana Reddy Chillakuru, Advisory Software Engineer, WSO2 Inc

Author photoVamsavardhana Reddy Chillakuru (別名は Vamsi) はインドのバンガロールにある IBM India Software Labs の Advisory Software Engineer です。彼は Apache Geronimo プロジェクトと Apache Tuscany プロジェクトのコミッターであり、Apache Geronimo Project Management Committee のメンバーであり、そして IBM WebSphere Application Server Community Edition Level 3 Support Team の一員でもあります。彼はインドのカルカッタにある Indian Statistical Institute で 1994年 と 1996年にそれぞれ統計学の (優等) 学位と修士号を取得しています。



Manu T. George, Staff Software Engineer, WSO2 Inc

author photoManu T. George はインドのバンガロールにある IBM India Software Labs の Staff Software Engineer です。彼は Apache Geronimo プロジェクトと Apache OpenEJB プロジェクトのコミッターであり、IBM WebSphere Application Server Community Edition Level 3 Support Team の一員でもあります。彼は 2001年に College of Engineering Trivandrum で応用電子工学の学位を取得しています。



2008年 11月 26日

はじめに

Java EE アプリケーションのセキュリティーにおいて最も重要な側面の 1 つは、EJB (Securing Enterprise Java Bean) をセキュアにすることです。IBM WebSphere Application Server Community Edition V2.1 (以下、Community Edition) は、Java EE5 (Java Enterprise Edition 5.0) 認定の無料で使用できるアプリケーション・サーバーです。そのベースとなっているのは EJB アプリケーションをセキュアにする Apache Geronimo v2.1 で、Community Edition の EJB コンテナーには、Apache OpenEJB が使用されています。EJB 認証および許可を構成するには、各メソッドが実行の際に参照するデプロイメント記述子にセキュリティー・ロールを定義し、定義したセキュリティー・ロールを Community Edition 固有のデプロイメント・プランのプリンシパルにマッピングするという方法を使います。

この記事では、Community Edition を使用してセッション、エンティティー、およびメッセージ駆動型 EJB をセキュアにするために使用できる方法をいくつか紹介するとともに、EJB アプリケーションを開発する手順をとおして、セキュリティーを構成するさまざまな方法についても説明します。この記事の手順に従うには、WebSphere Application Server Community Edition v2.1 が必要です。


セキュリティーが構成されていない単純な EJB アプリケーション

まずは、セキュリティーが構成されていない単純な EJB アプリケーションについて検討しましょう。このアプリケーションには、EJB2.1 ステートレス・セッション Bean と EJB3 ステートレス・セッション Bean が含まれています。リスト 1 に、このアプリケーションのデプロイメント記述子ファイル、ejb-jar.xml を記載します。

リスト 1. デプロイメント記述子でのBean 定義
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar ...>
    <display-name>SimpleEjbApp</display-name>
    <enterprise-beans>
        <session>
            <description>Simple Session Bean</description>
            <display-name>SimpleSessionBean</display-name>
            <ejb-name>SimpleSessionBean</ejb-name>
            <home>simple.ejb21.SimpleServiceHome</home>
            <remote>simple.ejb21.SimpleService</remote>
            <local-home>simple.ejb21.SimpleServiceLocalHome</local-home>
            <local>simple.ejb21.SimpleServiceLocal</local>
            <ejb-class>simple.ejb21.SimpleServiceBean</ejb-class>
            <session-type>Stateless</session-type>
            <transaction-type>Container</transaction-type>
        </session>
    </enterprise-beans>
</ejb-jar>

上記のデプロイメント記述子では、1 つの Bean、具体的には SimpleSessionBean しか定義していないことに注目してください。EJB3 セッション Bean のデプロイメント・メタデータは、Bean クラスでアノテーションを使用して指定します。リスト 2 に、Simple3ServiceBean の Bean クラスを記載します。

リスト 2. Simple3ServiceBean クラス
import  javax.ejb.Stateless;
...

@Stateless
public class Simple3ServiceBean implements Simple3Service {

	  public String commonMethod(){
		  ...
	  }

	  public String userMethod(){
		  ...
	  }

	  public String adminMethod(){
		  ...
	  }
	  
	  public String noaccessMethod(){
		  ...
	  }
}

この例では @Stateless アノテーションによって、Simple3ServiceBean をステートレス・セッション Bean として指定しています。

SimpleSessionBeanSimple3ServiceBean はどちらもセキュリティーが構成されていないセッション Bean なので、すべてのメソッドからは制限なくアクセスすることができます。リスト 3 に、このアプリケーションのデプロイメント・プラン、openejb-jar.xml を記載します。

リスト 3. 単純な EJB アプリケーションのデプロイメント・プラン
<openejb-jar ...>
    <environment>
        <moduleId>
            <groupId>dw</groupId>
            <artifactId>simple-ejb-app</artifactId>
            <version>1.0</version>
            <type>jar</type>
        </moduleId>
        <dependencies/>
        <hidden-classes/>
        <non-overridable-classes/>
    </environment>
    <enterprise-beans>
        <session>
            <ejb-name>SimpleSessionBean</ejb-name>
            <jndi-name>ejb/SimpleSessionBean</jndi-name>
        </session>
    </enterprise-beans>
</openejb-jar>

この EJB アプリケーションは、ID が dw/simple-ejb-app/1.0/jar に設定されたモジュールの下にデプロイされます。この後説明するように、このアプリケーションの EJB へのマッピングを行うには、moduleId 要素に含まれる情報を使用することに注意してください。


EJB セキュリティーのデモンストレーションを行う単純な Web アプリケーション

この記事では、単純な Web アプリケーションを例に用いて EJB セキュリティーのデモンストレーションを行います。この Web アプリケーションは、「bank」と「customer」という 2 つのセキュリティー・ロールを使用します。Web アプリケーションを構成するのは、制限なしでアクセスできるホーム・ページ、そして「bank」または「customer」のロールでアクセス可能な 2 つのセキュアなページです。この 2 つのページのそれぞれが SimpleSessionBean メソッドと Simple3ServiceBean メソッドにアクセスし、メソッドの結果、あるいはメソッドの呼び出しでスローされた例外を表示します。リスト 4 に、web.xml デプロイメント記述子を記載します。

リスト 4. 単純な Web アプリケーションのデプロイメント記述子
<web-app ...>
    <display-name>simple-web-app</display-name>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
        ...
    </welcome-file-list>

    <login-config>
        <auth-method>FORM</auth-method>
        <realm-name>Not required for FORM auth</realm-name>
        <form-login-config>
            <form-login-page>/login/login.jsp</form-login-page>
            <form-error-page>/login/loginerror.jsp</form-error-page>
        </form-login-config>
    </login-config>

    <security-role>
        <role-name>customer</role-name>
    </security-role>
    <security-role>
        <role-name>bank</role-name>
    </security-role>
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Customer</web-resource-name>
            <url-pattern>/customer/*</url-pattern>
            <http-method>GET</http-method>
            <http-method>POST</http-method>
        </web-resource-collection>
        <auth-constraint>
            <role-name>customer</role-name>
                 <!-- This comes from the security-role element -->
        </auth-constraint>
    </security-constraint>
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Bank</web-resource-name>
            <url-pattern>/bank/*</url-pattern>
            <http-method>GET</http-method>
            <http-method>POST</http-method>
        </web-resource-collection>
        <auth-constraint>
            <role-name>bank</role-name> 
                   <!-- This comes from the security-role element -->
        </auth-constraint>
    </security-constraint>

    <ejb-ref>
        <ejb-ref-name>ejb/SimpleService</ejb-ref-name>
        <ejb-ref-type>Session</ejb-ref-type>
        <home>simple.ejb21.SimpleServiceHome</home>
        <remote>simple.ejb21.SimpleService</remote>
    </ejb-ref>
    <ejb-ref>
        <ejb-ref-name>ejb/Simple3Service</ejb-ref-name>
        <ejb-ref-type>Session</ejb-ref-type>
        <remote>simple.ejb3.Simple3Service</remote>
    </ejb-ref>
    ....
</web-app>

この Web アプリケーションは、login-config 要素に構成された FORM 認証を使用します。2 つのセキュリティー・ロールを定義するために使用するのは security-role 要素です。リソース・コレクションのセキュリティー権限を構成するには、security-constraint タグを使用します。この例では、bank ロールのユーザーは /bank/* というパターンでURL にアクセスし、customer ロールのユーザーは /customer/* というパターンで URL にアクセスします。

Bean にリモート・ホーム・インターフェースとリモート・インターフェースでアクセスするための EJB 参照は、ejb-ref 要素を使用して定義します。この例で定義している EJB 参照は、ejb/SimpleServiceejb/Simple3Service の 2 つです。EJB3 セッション Bean である Simple3Service Bean にはホーム・インターフェースは定義されないことに注意してください。この Bean にローカル・ホーム・インターフェースとリモート・インターフェースでアクセスするための EJB 参照は、ejb-local-ref 要素を使用して宣言することができます。

geronimo-web.xml Web アプリケーション・デプロイメント・プランでは、web.xml に定義された EJB 参照を特定の EJB にマッピングし、セキュリティー・ロールをプリンシパルにマッピングします。リスト 5 に、サンプル Web アプリケーションのデプロイメント・プランを記載します。

リスト 5. 単純な Web アプリケーションのデプロイメント・プラン
<web-app ...>
    ...
    <context-root>simple-web-app</context-root>
    <nam:ejb-ref xmlns:nam="http://geronimo.apache.org/xml/ns/naming-1.2">
        <nam:ref-name>ejb/SimpleService</nam:ref-name>
        <nam:pattern>
            <nam:groupId>dw</nam:groupId>
            <nam:artifactId>simple-ejb-app</nam:artifactId>
            <nam:version>1.0</nam:version>
            <nam:name>SimpleSessionBean</nam:name>
        </nam:pattern>
    </nam:ejb-ref>
    <nam:ejb-ref xmlns:nam="http://geronimo.apache.org/xml/ns/naming-1.2">
        <nam:ref-name>ejb/Simple3Service</nam:ref-name>
        <nam:pattern>
            <nam:groupId>dw</nam:groupId>
            <nam:artifactId>simple-ejb-app</nam:artifactId>
            <nam:version>1.0</nam:version>
            <nam:name>Simple3ServiceBean</nam:name>
        </nam:pattern>
    </nam:ejb-ref>
    ...
    <security-realm-name>SampleSecurityRealm</security-realm-name>
    <app:security ...>
        ...
        <sec:role-mappings>
            <sec:role role-name="customer">
                <sec:principal name="UserGrp" 
                    class="o.a.g.s.r.providers.GeronimoGroupPrincipal"/>
                ...
            </sec:role>
            <sec:role role-name="bank">
                <sec:principal name="AdminGrp" 
                    class="o.a.g.s.r.providers.GeronimoGroupPrincipal"/>
            ...
            </sec:role>
        </sec:role-mappings>
    </app:security>
</web-app>

EJB 参照を特定の EJB にマッピングするためには、ejb-ref 要素を使用します。上記の例で注目すべき点は、ejb-ref に含まれる ref-name 要素の値が、web.xml での ejb-ref に含まれる ejb-ref-name 要素の値と一致していることです (リスト 4 を参照)。これと同じく、EJB ローカル参照を特定の EJB にマッピングするには ejb-local-ref 要素を使用します。

security-realm-name 要素は、アプリケーションによるユーザー認証の対象となるセキュリティー・レルムを構成するために使用します。この例では、SampleSecurityRealm という名前のレルムを使用しています。

セキュリティー・ロールとプリンシパルとのマッピングは、security 要素に含まれる role-mappings 要素で行います。ここでは、マッピングするセキュリティー・ロールごとに role 要素を使用します。この role 要素の role-name 属性にセキュリティー・ロールの名前を指定し、role 要素の principal 要素を使用してセキュリティー・ロールにマッピングするプリンシパルを指定します。この例では、bank ロールを AdminGrp という名前の GeronimoGroupPrincipal にマッピングし、customer ロールを UserGrp という名前の GeronimoGroupPrincipal にマッピングしています。プリンシパルとロールとのマッピングについての詳細は、「参考文献」で紹介している「Configuring Web application security in WebSphere Application Server Community Edition V2.0」を参照してください。


EJB セキュリティーを構成していないサンプル・アプリケーションの実行

ここで、EJB アプリケーションの EJB にアクセスする単純な Web アプリケーションを実行してみます。注意する点として、この時点では、EJB のセキュリティーは一切構成されていません。作業を進める前に、サンプル・アーカイブをダウンロードして任意のディレクトリー (この例では <SAMPLES_HOME> ディレクトリーを使用) に解凍し、dw_users.properties と dw_groups.properties ファイルを <WASCE_HOME>/var/security ディレクトリー (<WASCE_HOME> は Community Edition のインストール・ディレクトリー) にコピーしてください。

以下の手順でサンプル・アプリケーションを実行します。

  1. Community Edition を起動し、ブラウザーで http://localhost:8080/console/ を開きます。
  2. user name には systempassword には manager と入力します。これで Login をクリックすると、管理コンソールにウェルカム・ページが表示されます。
  3. Deploy New ポートレットまでナビゲートします。
  4. Plan フィールドで <SAMPLES_HOME> までナビゲートし、SampleSecurityRealm-plan.xml ファイルを選択します。
  5. Install をクリックして、セキュリティー・レルムをデプロイします。
  6. Archive フィールドで <SAMPLES_HOME> までナビゲートし、simple-ejb-app.jar ファイルを選択します。
  7. Install をクリックして、EJB アプリケーションをデプロイします。
  8. Archive フィールドで <SAMPLES_HOME> までナビゲートし、simple-web-app.war ファイルを選択します。
  9. Install をクリックして、この Web アプリケーションをデプロイします。
  10. http://localhost:8080/simple-web-app にアクセスします。すると、図 1 の画面が表示されます。
    図 1. Web アプリケーションのホーム・ページ
    Web アプリケーションのホーム・ページ

    User Info セクションには、現在ログインしているユーザーがこの Web アプリケーションで持っている UserPrincipalUserRole が表示されます。EJB2.1 セクションに表示されているのは SimpleSessionBean のメソッドごとの呼び出し結果、EJB3 セクションに表示されているのは、Simple3ServiceBean のメソッドごとの呼び出し結果です。アプリケーションにはまだログインしていないので、上記の図の UserPrincipalUserRole には何も表示されていません。また、セキュリティーが構成されている EJB メソッドは 1 つもないため、すべてのメソッドにアクセス可能で、その呼び出しは Unauthenticated ユーザーとして行われます。

  11. http://localhost:8080/simple-web-app/bank にアクセスし、ユーザー名 dwadmin とパスワード admin を使用してログインします。すると今度は図 2 の画面が表示されます。
    図 2. Web アプリケーションの bank ページ
    Web アプリケーションの bank ページ

    UserPrincipal にはログイン・ユーザーとして dwadmin が示され、UserRolebank と示されていることに注目してください。ただし、ここでもセキュリティーが構成されている EJB メソッドは 1 つもないため、すべてのメソッドにアクセス可能で、メソッドは Unauthenticated ユーザーとして呼び出されます。

メソッド・アクセス権が制限されていない EJB2.1 および EJB3 セッション Bean を呼び出す Web アプリケーションを検討したところで、次は EJB2.1 および EJB3 セッション Bean のメソッド・アクセス権を構成します。


EJB2.1 デプロイメント記述子でのセキュリティー構成

EJB アプリケーションは、Bean レベルとメソッド・レベルのセキュリティーにロール・ベースのセキュリティーを使用します。このセクションでは、セキュリティー・ロールを定義してメソッド・アクセス権を構成する方法を説明します。

セキュリティー・ロールの定義方法

セキュリティー・ロールを定義するには、デプロイメント記述子ファイル ejb-jar.xmlassembly-descriptor の下で security-role 要素を設定します。セキュリティー・ロールの名前は role-name 要素が指定します。リスト 6 に、この記事で使用しているサンプル・アプリケーションのなかから ejb-jar.xml を抜粋します。

リスト 6. assembly-descriptor でのロール定義
<ejb-jar ...>
    <display-name>SimpleEjbApp</display-name>
    <enterprise-beans>
    ...
    </enterprise-beans>
    <assembly-descriptor>
      <security-role>
         <description>User role</description>
         <role-name>ejbuser</role-name>
      </security-role>
      <security-role>
         <description>Administrator role</description>
         <role-name>ejbadmin</role-name>
      </security-role>
      ...
    </assembly-descriptor>
</ejb-jar>

この例のアプリケーションでは、ejbuserejbadmin という 2 つのロールを定義しています。

メソッド・アクセス権の構成方法

EJB のメソッドを呼び出すためのセキュリティー ID を構成するには、ejb-jar.xmlenterprise-beans 要素のなかの Bean 定義にある security-identity 要素を使用します。Bean メソッド・アクセス権は、ejb-jar.xmlassembly-descriptor に含まれる method-permission 要素を使用して構成します。リスト 7 に、SimpleSessionBean のメソッド・アクセス権を構成するために使用されている EJB アプリケーション・デプロイメント記述子の該当する部分を記載します。

リスト 7. EJB アプリケーションのデプロイメント記述子
<ejb-jar id="SimpleEjbAppWithSecurity" ...>
    <enterprise-beans>
        <session>
            ...
            <ejb-name>SimpleSessionBean</ejb-name>
            ...
            <security-identity>
                <use-caller-identity />
            </security-identity>
        </session>
        ...
    </enterprise-beans>
    <assembly-descriptor>
        <security-role>
        ...
        </security-role>
        <method-permission>
            <role-name>ejbuser</role-name>
            <method>
                <ejb-name>SimpleSessionBean</ejb-name>
                <method-name>userMethod</method-name>
            </method>
        </method-permission>
        <method-permission>
            <role-name>ejbadmin</role-name>
            <method>
                <ejb-name>SimpleSessionBean</ejb-name>
                <method-name>adminMethod</method-name>
            </method>
        </method-permission>
        <method-permission>
            <unchecked/>
            <method>
                <ejb-name>SimpleSessionBean</ejb-name>
                <method-name>commonMethod</method-name>
            </method>
        </method-permission>
        <method-permission>
            <role-name/>
            <method>
                <ejb-name>SimpleSessionBean</ejb-name>
                <method-name>noaccessMethod</method-name>
            </method>
        </method-permission>
    </assembly-descriptor>
</ejb-jar>

上記の例で使用したタグについて 1 つひとつ説明します。

  • security-identity 要素は、SimpleSessionBean のメソッドを呼び出すために使用するセキュリティー ID を指定します。
  • use-caller-identity 要素は、呼び出し側のセキュリティー ID をエンタープライズ Bean メソッドを実行するためのセキュリティー ID として使用するように指定します。別の選択肢としては、この後説明するように run-as 要素を使用して、run-as の ID で Bean のメソッドを呼び出すように指定することもできます。
  • method-permissionmethod 要素は、Bean の 1 つ以上のメソッドに対してセキュリティー権限を指定します。
  • アクセス権を指定するには、メソッドへのアクセスを許可するロールごとに 1 つまたは複数の role-name 要素を使用します。この要素は複数あっても構いません。空の role-name 要素が 1 つしかない場合、そのロールはメソッドにアクセスできないことになります。無制限のアクセス権を指定するには、unchecked 要素を使用します。
  • メソッドの ejb-name 要素は EJB の名前を指定し、method-name 要素はメソッドの名前を指定します。EJB のすべてのメソッドを指定するには、method-name“*” の値を指定します。
  • 個々の method-name は、オーバーロードされたメソッドを含め、その名前を持つすべてのメソッドに共通の内容を指定します。オーバーロードされたメソッドのなかから特定のメソッドに関する指定をするには、method-params 要素を使用してください。
  • method-permission は、Bean の Home、Remote、Local、および LocalHome インターフェースのメソッドに対する構成をします。特定インターフェースのメソッドに対するアクセス権を指定するには、対応する値を持つメソッドで method-intf 要素を使用します。

リスト 7 の SimpleSession Bean で構成した内容は以下のとおりです。

  • userMethod には ejbuser ロールでアクセスできること
  • adminMethod には ejbadmin ロールでアクセスできること
  • commonMethod のアクセスは制限されないこと
  • noaccessMethod にはどのロールでもアクセスできないこと

アノテーションを使用した EJB3 Bean でのセキュリティー構成

EJB3 エンタープライズ Bean では、セキュリティー・アノテーションを使用して Bean レベルとメソッド・レベルのセキュリティーを構成することができます。このセクションでは各種のセキュリティー・アノテーション (@DeclareRoles、@DenyAll、@PermitAll、@RolesAllowed) を紹介し、それぞれがどのようにセキュリティー構成に影響するかを説明します。この記事の後では、さらに @RunAs アノテーションについて説明します。

セキュリティー・ロールの定義方法

セキュリティー・ロールを定義するには、Bean クラスで @DeclareRoles アノテーションを使用します (リスト 8 を参照)。

リスト 8. @DeclareRoles アノテーションを設定した Simple3ServiceBean
@Stateless
@DeclareRoles({"ejb3user", "ejb3admin"})
public class Simple3ServiceBean implements Simple3Service {
...
}

上記の例では、Simple3ServiceBeanejb3userejb3admin という 2 つのセキュリティー・ロールを定義しています。

メソッド・アクセス権の構成方法

エンタープライズ Bean メソッドに対するアクセス権を構成するには、@DenyAll@PermitAll、および @RolesAllowed といったアノテーションを使用します。@PermitAll および @RolesAllowed アノテーションは Bean クラスと Bean メソッドに適用できる一方、@DenyAll アノテーションを適用できるのは Bean メソッドのみです。クラスに適用されたアノテーションは、そのクラスのすべてのメソッドに適用されます。一方、メソッドに適用されたアノテーションは、そのクラスに適用されたすべてのアノテーションよりも優先されます。リスト 9 に、Simple3ServiceBean クラスを記載します。

リスト 9. セキュリティー・アノテーションを設定した Simple3ServiceBean クラス
@Stateless
@DeclareRoles({"ejb3user", "ejb3admin"})
public class Simple3ServiceBean implements Simple3Service {

	  @Resource
	  private SessionContext ctx;
	
        @PermitAll
	  public String commonMethod() {
		  return logCall("commonMethod");
	  }

        @RolesAllowed({"ejb3user"})
	  public String userMethod() {
		  return logCall("userMethod");
	  }

        @RolesAllowed({"ejb3admin"})
	  public String adminMethod() {
		  return logCall("adminMethod");
	  }
	  
        @DenyAll
	  public String noaccessMethod() {
		  return logCall("noaccessMethod");
	  }
	  
	  private String logCall(String method) {
              ...
		  return msg;
	  }
}

上記の例では、以下のアクセス構成を定義しています。

  • commonMethod のアクセスは制限されないこと
  • userMethod には ejb3user ロールでアクセスできること
  • adminMethod には ejb3admin ロールでアクセスできること
  • noaccessMethod にはどのロールでもアクセスできないこと

EJB デプロイメント・プランでのセキュリティー・ロールのマッピング

EJB デプロイメント記述子に定義されたセキュリティー・ロールと、@DeclareRoles アノテーションによって定義されたロールは、EJB デプロイメント・プラン openejb-jar.xml のプリンシパルにマッピングされます。リスト 10 に、EJB デプロイメント・プランでのプリンシパルとロールとのマッピングを記載します。

リスト 10. プリンシパルとロールとのマッピング
<security>
    <role-mappings>
        <role role-name="ejbuser">
            <principal class="o.a.g.s.r.providers.GeronimoGroupPrincipal" 
                  name="UserGrp"/>
        </role>
        <role role-name="ejbadmin">
            <principal class="o.a.g.s.r.providers.GeronimoGroupPrincipal" 
                  name="AdminGrp"/>
        </role>
        <role role-name="ejb3user">
            <principal class="o.a.g.s.r.providers.GeronimoGroupPrincipal"
                  name="UserGrp"/>
        </role>
        <role role-name="ejb3admin">
            <principal class="o.a.g.s.r.providers.GeronimoGroupPrincipal" 
                  name="AdminGrp"/>
            <principal class="o.a.g.s.r.providers.GeronimoUserPrincipal" 
                  name="dwuser3"/>
        </role>
    </role-mappings>
</security>

上記では、ejb-jar.xml@DeclareRoles アノテーションのセキュリティー・ロールのそれぞれが、以下のプリンシパルにマッピングされています。

  • ejbuser ロールは、「UserGrp」という名前の GeronimoGroupPrincipal にマッピングされます。
  • ejbadmin ロールは、「AdminGrp」という名前の GeronimoGroupPrincipal にマッピングされます。
  • ejb3user ロールは、「UserGrp」という名前の GeronimoGroupPrincipal にマッピングされます。
  • ejb3admin ロールは、「AdminGrp」という名前の GeronimoGroupPrincipal と、「dwuser3」という名前の GeronimoUserPrincipal にマッピングされます。

プリンシパルとロールとのマッピングについての詳細は、「Configuring Web application security in WebSphere Application Server Community Edition V2.0」を参照してください。


EJB セキュリティーを構成したサンプル・アプリケーションの実行

まずは Deploy New ポートレットまでナビゲートしてから、以下の手順を実行します。

  1. Archive フィールドで <SAMPLES_HOME> までナビゲートし、simple-ejb-app-w-security.jar ファイルを選択します。
  2. Redeploy application オプションを選択して Install をクリックします。
  3. Web App WARs ポートレットまでナビゲートし、dw/simple-web-app/1.0/war を起動します。
  4. http://localhost:8080/simple-web-app にアクセスします。すると、図 3 の画面が表示されます。
    図 3. セキュア EJB にアクセスする Web アプリケーションのホーム・ページ
    セキュア EJB にアクセスする Web アプリケーションのホーム・ページ

    ユーザーはまだアプリケーションにログインしていないので、ホーム・ページから呼び出せるメソッドは、SimpleSessionBeanSimple3ServiceBeancommonMethod (無制限アクセスが設定されたメソッド) に限られます。この Principal は許可されていないため、それ以外のすべてのメソッドを呼び出そうとすると、AccessException または EJBAccessException という結果になります。

  5. http://localhost:8080/simple-web-app/bank にアクセスして、ユーザー名には dwadmin、パスワードには admin を使用してログインします。すると今度は図 4 の画面が表示されます。
    図 4. セキュア EJB にアクセスする Web アプリケーションの bank ページ
    セキュア EJB にアクセスする Web アプリケーションの bank ページ

    ユーザーが dwadmin としてログインしたことから、Subject には dwadmin という名前の GeronimoUserPrincipalAdminGrp という名前の GeronimoGroupPrincipal が記載されています。ロール・マッピングに従って、ユーザーは ejbadmin ロールと ejb3admin ロールにマッピングされているため、制限なしでアクセスできる commonMethod だけでなく、adminMethod (SimpleSessionBean の場合は ejbadmin ロールで、Simple3ServiceBean の場合は ejb3admin ロールでアクセスが許可されたメソッド) にもアクセスすることができます。userMethodnoaccessMethod については、呼び出そうとすると AccessException または EJBAccessException という結果になります。これは、userMethod へのアクセスが許可されているのは ejbuser ロール (Simple3ServiceBean の場合は ejb3user ロール) であり、また noaccessMethod はどのロールでもアクセスできないためです。

  6. 新しいブラウザー・ウィンドウを開いて、http://localhost:8080/simple-web-app/customer/ にアクセスします。ユーザー名 dwuser3 とパスワード user3 を使用してログインすると、図 5 の画面が表示されます。
    図 5. セキュア EJB にアクセスする Web アプリケーションの customer ページ
    セキュア EJB にアクセスする Web アプリケーションの customer ページ

    今度はユーザーが dwuser3 としてログインしているため、Subject には dwuser3 という名前の GeronimoUserPrincipalUserGrp という名前の GeronimoGroupPrincipal が記載されています。ユーザーはロール・マッピングに従って ejbuserejb3user、および ejb3admin ロールにマッピングされます。SimpleSessionBean では、ユーザーは無制限アクセスが設定された commonMethod と、ejbuser ロールでアクセス可能な userMethod にアクセスすることができます。一方の Simple3ServiceBean では、無制限アクセスが設定された commonMethod、そして ejb3user ロールでアクセス可能な userMethodejb3admin ロールでアクセス可能な adminMethod にアクセスすることができます (「EJB2.1 デプロイメント記述子でのセキュリティー構成」を参照)。その他のメソッドについては、メソッド呼び出し時に AccessException または EJBAccessException が返されることになります。


run-as サブジェクトとデフォルト・サブジェクト

Bean のメソッドに対するメソッド・アクセス権を構成するだけでなく、Bean の run-as ロールを構成して、Bean が他の Bean の呼び出しに使用するセキュリティー ID を指定することもできます。この構成は、Bean のメソッドがその呼び出しに使用されたセキュリティー ID とは異なるセキュリティー ID を使用して他の Bean を呼び出さなければならない場合に役立ちます。その一例は、セキュリティー ID を使わずに呼び出されるメッセージ駆動型 Bean メソッドが、セキュアなセッション Bean メソッドを呼び出す場合です。run-as ロール・セキュリティーのサブジェクトを構成するセキュリティー・クレデンシャルは、デプロイメント・プランの中で構成します。

2.0 より前の Community Edition リリースでは、run-as サブジェクトとデフォルト・サブジェクトのセキュリティー構成は、プリンシパルの default-principal タグと designated-run-as 属性によって指定されたプリンシパルとクレデンシャルを使用して構成されていました。Community Edition 2.0 からは、すべてのセキュリティー・フローは、セキュリティー・レルムへのログインによるサブジェクトから始まるようになっています。これらのサブジェクトを使用するには、それぞれのサブジェクトにログイン情報を提供する必要があります。このログイン情報は、クレデンシャル・ストアから取り込まれます。


クレデンシャル・ストア

Community Edition には、クレデンシャル・ストアの実装が用意されています。この SimpleCredentialStoreImpl という実装は、デプロイメント・プランでの XML によるクレデンシャル・ストアの構成を可能にします。リスト 11 に、この記事のサンプル・アプリケーションで使用したクレデンシャル・ストアを記載します。

リスト 11. クレデンシャル・ストア gbean
<gbean name="SampleCredentialStore" 
      class="o.a.g.s.credentialstore.SimpleCredentialStoreImpl" ...>
    <xml-attribute name="credentialStore">
        <credential-store 
              xmlns="http://geronimo.apache.org/xml/ns/credentialstore-1.0">
            <realm name="SampleSecurityRealm">
                <subject>
                <id>dwuser1-subject</id>
                    <credential>
                        <type>o.a.g.s.credentialstore.NameCallbackHandler</type>
                        <value>dwuser1</value>
                    </credential>
                    <credential>
                        <type>o.a.g.s.credentialstore.PasswordCallbackHandler</type>
                        <value>user1</value>
                    </credential>
                </subject>
                <subject>
                    <id>dwuser2-subject</id>
                    ...
                </subject>
                <subject>
                    <id>dwuser3-subject</id>
                    ...
                </subject>
                <subject>
                    <id>dwadmin-subject</id>
                    ...
                </subject>
            </realm>
            <realm name="AnotherRealm">
                <subject>
                ...
                </subject>
                ...
            </realm>
        </credential-store>
    </xml-attribute>
</gbean>

上記の realm 要素の name 属性が、subject を作成するために使用する security-realm の名前を指定します。subject 要素に含まれる id 要素が指定するサブジェクト ID は、後で説明するように、run-as サブジェクトとデフォルト・サブジェクトを構成するときに security-realm 名と組み合わせて使用することができます。

security-realm のログイン情報を構成するには、subject に含まれる credential 要素を使用します。リスト 11 では、ユーザー名 dwuser1 とパスワード user1 を使用して SampleSecurityRealm にログインする dwuser1-subject を取得しています。認証に名前とパスワードを必要とするセキュリティー・レルムを使用するには、現在 Community Edition が提供する名前とパスワードのコールバック・ハンドラーで十分対応できますが、クレデンシャル・ストアでその他のセキュリティー・レルム (デジタル証明書を使用するものなど) を使用する場合には、必要なコールバック・ハンドラーを実装してください。また、アプリケーションごとのクレデンシャル・ストアにすることも、すべてのアプリケーションで 1 つのクレデンシャル・ストアを使用することもできます。


クレデンシャル・ストアを使用するアプリケーションの構成

アプリケーションで使用するクレデンシャル・ストアは、アプリケーションのデプロイメント・プランのセキュリティー構成の中で指定します。リスト 12 に、この記事で使用しているサンプル・アプリケーションのセキュリティー構成を記載します。

リスト 12. セキュリティー構成での credential-store-ref
<security>
    <credential-store-ref>
        <name xmlns="http://geronimo.apache.org/xml/ns/deployment-1.2">
             SampleCredentialStore</name>
    </credential-store-ref>
    ...
</security>

上記の例では、credential-store-ref に含まれる name 要素が、アプリケーションで使用するクレデンシャル・ストアを指定しています。この値は、リスト 11 に記載したクレデンシャル・ストア gbean の name 属性に設定された値と同じであることに注意してください。


run-as サブジェクトとデフォルト・サブジェクトの構成

アプリケーションの run-as サブジェクトとデフォルト・サブジェクトは、アプリケーションのデプロイメント・プランのセキュリティー構成の中で指定します。run-as サブジェクトがどのロールに対しても構成されていない場合、構成済みの default-subject が代わりに使用されます。リスト 13 に、この記事で使用しているサンプル・アプリケーションの run-as サブジェクトとデフォルト・サブジェクト構成を記載します。

リスト 13. セキュリティー構成での run-as サブジェクトとデフォルト・サブジェクト
<security>
    ...
    <default-subject>
        <realm>SampleSecurityRealm</realm>
        <id>dwuser1-subject</id>
    </default-subject>
    <role-mappings>
        <role role-name="ejb3user">
            <run-as-subject>
                <realm>SampleSecurityRealm</realm>
                <id>dwuser3-subject </id>
            </run-as-subject>
            <principal class="o.a.g.s.r.providers.GeronimoGroupPrincipal" name="UserGrp"/>
        </role>
        <role role-name="another">
        ...
        </role>
        ...
    </role-mappings>
</security>

security 要素に含まれる default-subject 要素は、アプリケーションで使用するデフォルト・サブジェクトを構成します。default-subject では、realm 要素がセキュリティー・レルムを指定し、id 要素がクレデンシャル・ストアに構成されたサブジェクトの ID を指定します。default-subject 配下の realm および id に指定された値は、それぞれリスト 11 に記載されている realm 要素の name 属性および複数ある subject のいずれかの id と一致することに注意してください。

role-mappings 配下の role 要素に含まれる run-as-subject 要素は、そのロールの run-as サブジェクトを構成します。リスト 13 に記載しているのは、ejb3user ロールに対して構成された run-as サブジェクトです。run-as-subject 配下の realm および id に指定された値は、それぞれリスト 11 に記載されている realm 要素の name 属性および複数ある subject のいずれかの id と一致することに注意してください。


run-as を設定したサンプル EJB アプリケーション

さらに 2 つのセッション Bean (Simple3ServiceBean2Simple3SeviceBean3) を追加して、この 2 つが Simple3ServiceBean の対応するメソッドを呼び出すようにしました。Simple3ServiceBean2 は、ejb3user ロールとして実行されるように構成してあります。一方の Simple3ServiceBean3 の構成には、run-as ロールを使用していません。リスト 14 に、Simple3ServiceBean2 Bean クラスを記載します。

リスト 14. Simple3ServiceBean2 クラス
@Stateless
@DeclareRoles(value = {"ejb3user", "ejb3admin"})
@RunAs("ejb3user")
public class Simple3ServiceBean2 implements Simple3Service2 {

	  @EJB
	  private Simple3Service simple; // Simple3Service injected here
	
        @PermitAll
	  public String commonMethod() {
          Object temp;
          try {
              temp = simple.commonMethod();
          } catch(Throwable t) {
              temp = t;
          }
          return logCall("commonMethod") + "::" + temp;
	  }

        @RolesAllowed({"ejb3user"})
	  public String userMethod() {
            ...
	  }

        @RolesAllowed({"ejb3admin"})
	  public String adminMethod() {
            ...
	  }
	  
        @DenyAll
	  public String noaccessMethod() {
            ...
	  }
	  
      private String logCall(String method) {
            ...
	  }
}

上記の例では、ejb3user ロールで @RunAs アノテーションを使用して、Simple3ServiceBean2 の run-as ロールを構成してあります。この構成により、Simple3Service のメソッド呼び出しはデプロイメント・プランで指定された run-as-subject を使用することになります。ejb3user ロールの run-as-subject は、dwuser3-subject として指定されていることに注意してください (リスト 13 を参照)。


run-as EJB セキュリティーを構成したサンプル・アプリケーションの実行

  1. Deploy New ポートレットまでナビゲートします。
  2. サンプルに付属の simple-ejb-app-w-runas.jar をデプロイします。Install をクリックする前に、必ず Redeploy application オプションを選択してください。
  3. Web App WARs ポートレットまでナビゲートし、dw/simple-web-app/1.0/war を起動します。
  4. http://localhost:8080/simple-web-app にアクセスします。RunAs セクションまでスクロール・ダウンすると、図 6 の画面が表示されます。
    図 6. run-as を設定した EJB にアクセスする Web アプリケーションのホーム・ページ
    run-as を設定した EJB にアクセスする Web アプリケーションのホーム・ページ

    RunAs セクションでは、Simple3ServiceBean2commonMethod の呼び出しは Unauthenticated ユーザーとして行われている一方、Simple3ServiceBeancommonMethod の呼び出しは run-as-subject で構成された dwuser3 として行われていることに注目してください。Simple3ServiceBean3 は run-as ロールを設定して構成されていないため、Simple3ServiceBeancommonMethod 呼び出しは Unauthenticated ユーザーとして行われるというわけです。

  5. http://localhost:8080/simple-web-app/customer/ にアクセスして、ユーザー名として dwuser1、パスワードとして user1 を使用してログインします。RunAs セクションまでスクロール・ダウンすると、図 7 の画面が表示されます。
    図 7. run-as を設定した EJB にアクセスする Web アプリケーションの customer ページ
    run-as を設定した EJB にアクセスする Web アプリケーションの customer ページ

RunAs セクションには、Simple3ServiceBean2commonMethoduserMethod の呼び出しが、Web アプリケーションに現在ログインしているユーザー、dwuser1 として行われていることが表示されています。その一方で、Simple3ServiceBeancommonMethoduserMethod の呼び出しは、run-as-subject で構成された dwuser3 として行われています。Simple3ServiceBean3 は run-as ロールで構成されていないことから、Simple3ServiceBeancommonMethoduserMethod の呼び出しは、このように dwuser1 として行われることになります。


エンティティー Bean セキュリティーの構成

セッション Bean セキュリティーの場合と同じように、エンティティー Bean セキュリティーも deployment-descriptor とセキュリティー・アノテーションを使用して構成することができます。リスト 15 に、エンティティー Bean を使用したサンプル EJB アプリケーションの assembly-descriptor を記載します。

リスト 15. assembly-descriptor
    <assembly-descriptor>
       <security-role>
           <description>Bank Manager</description>
           <role-name>manager</role-name>
       </security-role>
       <method-permission>
           <role-name>manager</role-name>
           <method>
               <ejb-name>MyBank</ejb-name>
               <method-name>create</method-name>
           </method>
       </method-permission>
   </assembly-descriptor>

上記の例で構成している内容は、MyBank エンティティー Bean の Home インターフェースでは、 create メソッドに manager ロールでしかアクセスできないようにするというものです。


エンティティー Bean サンプル・アプリケーションの実行

サンプルに付属の MyBankEJB サンプル・アプリケーションには、MyBank という EJB2.1 エンティティー Bean が 1 つ含まれています。この Bean の LocalHome および Home インターフェースの create メソッドには manager ロールでしかアクセスできないように構成してあります。

以下の手順に従って、このアプリケーションを実行してください。

  1. Deploy New ポートレットまでナビゲートします。
  2. Archive フィールドで <SAMPLES_HOME> までナビゲートし、bank-db-pool.rar ファイルを選択します。
  3. Install をクリックして、MyBankEJB アプリケーションが使用するデータベース・プールをデプロイします。
  4. Archive フィールドで <SAMPLES_HOME>までナビゲートし、MyBankEJB.jar ファイルを選択します。
  5. Install をクリックして、MyBankEJB アプリケーションをデプロイします。
  6. Archive フィールドで <SAMPLES_HOME> までナビゲートし、MyBankWeb.war. ファイルを選択します。
  7. Install をクリックして、MyBankWeb アプリケーションをデプロイします。
  8. http://localhost:8080/MyBankWeb. にアクセスします。
  9. 表示されるページの Create an account セクションには、例外が発生したことが示されますが、これはユーザーがまだログインしていないためです。
  10. 今度は http://localhost:8080/MyBankWeb/manager にアクセスします。

この場合に表示されるページには、アカウントが正常に作成されたことが示されます。アカウントの作成に成功したのは、このページの構成には run-as ロールが使用されていて、MyBankEJB デプロイメント・プランに構成された manager ロールにマッピングするユーザー ID dwadmin で MyBank Bean にアクセスするようになっているためです。


メッセージ駆動型 Bean セキュリティーの構成

メッセージ駆動型 Bean はセッション Bean やエンティティー Bean とは異なり、他の Bean またはクライアント・アプリケーションによって呼び出されることはありません。また、メッセージ駆動型 Bean は、JMS リスナーがモニターする入力宛先にメッセージが到着したときに呼び出されます。メッセージ駆動型 Bean が他のセッション Bean およびエンティティー Bean を呼び出すことは可能です。メッセージ駆動型 Bean からセキュア EJB を呼び出すには、メッセージ駆動型 Bean が run-as ロールで構成されている必要があります。EJB2.1 メッセージ駆動型 Bean の場合には、デプロイメント記述子の security-identity 要素を使用して run-as ロールを構成することができます。一方、EJB3 メッセージ駆動型 Bean の場合には @RunAs アノテーションを使用して run-as ロールを構成します。


メッセージ駆動型 Bean サンプル・アプリケーションの実行

EJB3 メッセージ駆動型 Bean の run-as セキュリティーを説明するため、サンプルに jms-mdb-sample-ear-2.1.0.1.ear というアプリケーションを用意しました。このアプリケーションは OrderRecvMDB というメッセージ駆動型 Bean と、Simple30ServiceBean というステートレス・セッション Bean で構成されています。このセッション Bean の userMethodejb3user ロールでアクセスできるように、OrderRecvMDB Bean は run-as ロール、ejb3user でアクセスできるように構成しました。デプロイメント・プランでは、セキュリティー構成で ejb3user ロールの run-as-subject として dwuser1-subject を指定しています。この OrderRecvMDB Bean クラスは、リスト 16 に記載するとおりです。

リスト 16. OrderRecvMDB Bean クラス
import javax.annotation.security.RunAs;
...

//
// MessageDrivenBean that listens to items on the
// 'OrderQueue' queue and processes them accordingly.
//
@MessageDriven(activationConfig = {
       @ActivationConfigProperty(propertyName="destinationType", 
           propertyValue="javax.jms.Queue"),
       @ActivationConfigProperty(propertyName="destination", 
           propertyValue="OrderQueue")
   })
@RunAs("ejb3user")               
public class OrderRecvMDB implements MessageListener {
	
	@EJB
	private Simple30Service simple; // Session bean is injected

	/*
     * Process a message.
     * 
     * @param message The message to process. 
     */
    public void onMessage(Message message) {
        TextMessage textMessage = (TextMessage) message;
        try {
            System.out.println("Order Received \n"+ textMessage.getText());
            simple.userMethod();
        } catch ( JMSException e ) {
            e.printStackTrace();
        }
    }
}

以下の手順に従って、このアプリケーションを実行してください。

  1. Deploy New ポートレットまでナビゲートします。
  2. Archive フィールドで <SAMPLES_HOME> を参照し、jms-mdb-sample-ear-2.1.0.1.ear を選択します。
  3. Install をクリックして、このサンプル・アプリケーションをデプロイします。
  4. http://localhost:8080/order にアクセスします。
  5. フィールドに値を入力して Order をクリックします。

サーバーのコンソール・ウィンドウに、受信した注文とともに、Simple30ServiceBeanuserMethod を呼び出すために使用したセキュリティー ID、dwuser1 の詳細が表示されるはずです。


まとめ

この記事では、EJB2.1 セッション Bean と EJB3 セッション Bean、そして EJB2.1 エンティティー Bean を作成し、デプロイメント記述子とセキュリティー・アノテーションによって Bean メソッドのアクセス権を構成する方法を説明しました。さらに、セッション Bean とメッセージ駆動型 Bean の run-as ロールを構成して、このセキュリティー構成を使用する EJB アプリケーションをデプロイするために必要なクレデンシャル・ストアなどの成果物を作成する方法も説明しました。EJB を呼び出すサンプル Web アプリケーションの例から、EJB セキュリティーの実際の機能を理解していただけたと思います。


謝辞

この記事をレビューしてくださった Phani Madgula 氏に感謝いたします。


ダウンロード

内容ファイル名サイズ
Sample source codesamples.zip1.6MB

参考文献

学ぶために

製品や技術を入手するために

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=WebSphere, Open source
ArticleID=361065
ArticleTitle=WebSphere Application Server Community Edition を使用した EJB アプリケーション・セキュリティーの構成方法
publish-date=11262008