Acegi を使って Java アプリケーションをセキュアにする、第 3 回: Java オブジェクトのアクセス制御

メソッド・ベースのセキュリティーで Java クラスのインスタンスを保護する

Acegi Security System を紹介するこの 3 回連載の最終回では、Bilal Siddiqui が Java™ クラスのインスタンスへのアクセスをセキュアにする方法を説明します。Java クラスへのアクセスをセキュアにしなければならない理由、Spring が Java クラスのインスタンスを生成してセキュアにする仕組み、そして Java アプリケーションにクラスのセキュリティーを組み込むように Acegi を構成する方法を学んでください。

Bilal Siddiqui , Freelance consultant, WaxSys

Bilal Siddiqui は、電気工学エンジニア、XML コンサルタント、そして e-business の簡易化を専門とする会社、WaxSys の共同設立者でもあります。1995年に電子工学技術の学位で University of Engineering and Technology, Lahore を卒業した後、産業用制御システムを対象としたソフトウェア・ソリューションの設計を始めました。その後、XML に転向し、C++ のプログラミング経験を生かして Web ベースや Wap ベースの XML 処理ツール、サーバー側の構文解析ソリューション、そしてサービス・アプリケーションを作成しました。技術の熱烈な支持者である彼が書いた技術書は、頻繁に発行されています。



2007年 9月 25日

この 3 回からなる連載では、Acegi Security System を使用して Java エンタープライズ・アプリケーションをセキュアにする方法を紹介しています。連載第 1 回で説明したのは、Acegi の概要ならびに Acegi の組み込みセキュリティー・フィルターを使用して単純な URL ベースのセキュリティー・システムを実装する方法です。続く第 2 回では、アクセス制御ポリシーを作成して LDAP ディレクトリー・サーバーに保管する方法、そしてこのディレクトリー・サーバーと相互作用するように Acegi を構成してアクセス制御ポリシーを実装する方法を説明しました。最終回となるこの第 3 回では、Acegi を使用してエンタープライズ・アプリケーションでの Java クラス・インスタンスへのアクセスをセキュアにする方法を紹介します。

この記事ではまず、参考のために一般的なエンタープライズ・アプリケーションのシナリオをいくつか引用して、Java クラスへのアクセスをセキュアにしなければならない場合を簡単に説明するところから始めます。続いてさらに踏み込んだ背景として、Spring の IoC (Inversion of Control) フレームワークが JSP またはサーブレットからアクセス可能な Java クラスのインスタンスを生成する流れを説明します。また、Spring が Java オブジェクトへのアクセスをフィルタリングするために使用する Bean プロキシーについての重要な概念も紹介します。その上で説明するのが、Java クラスへのアクセスを制御するように Acegi のメソッド・セキュリティー・インターセプターを構成する方法です。最後に、第 2 回のサンプル・アプリケーションを拡張してセキュアな Java オブジェクトのサポートを組み込むことで、連載の最終回を締めくくります。

記事の説明は連載のこれまでの記事に基づいているため、第 1 回第 2 回ザー・ウィンドウに開いておくことをお勧めします。

Java クラスをセキュアにする事例

この連載を始めるときに、エンタープライズ・アプリケーションのセキュリティーについて簡単に説明したのを覚えているでしょうか。その説明のなかで、URL セキュリティーだけでは足りない以下のシナリオを取り上げました。

例えば、特定の製造会社が製造する特定の製品に関するデータが含まれる PDF 文書があるとします。この文書の一部には、会社の設計部門で編集および更新されることになっている設計データが含まれます。別の部分には生産データが含まれていて、これは生産管理者が使用することになります。このようなシナリオでは、よりきめの細かいセキュリティーを実装して、文書のそれぞれの部分に異なるアクセス権を適用しなければなりません。

話を進める前に、他にも URL セキュリティーを実装するだけでなく個々のクラスもセキュアにしなければならないアプリケーション・シナリオをいくつか検討してみましょう。

ビジネス自動化

ビジネス自動化アプリケーションでのワークフローはプロセスで構成されます。例えば、病理検査室で血液検査を行う際のワークフローは以下のようなステップからなりますが、このそれぞれのステップがプロセスであると考えられています。

  1. 検査員が患者から血液サンプルを採取し、そのサンプルに ID 番号を割り当てます。
  2. 検査技師がサンプルで必要なテストを実行し、テスト結果をまとめます。
  3. まとめられたテスト結果に基づいて、資格のある病理学者がテスト報告書を作成します。

この例からはっきりとわかるのは、それぞれのプロセスは、その特定のプロセスを実行する権限を与えられた別々の要員によって実行されるということです。認可されていないそれ以外の要員がプロセスを実行できるようであってはなりません。例えば検査技師の場合、認可されているのはテスト結果を準備することだけなので、テスト報告書の作成が可能であってはならないということです。

認可式ビジネス・プロセスは、ほとんどすべてのビジネス自動化アプリケーションに共通しています。通常、各ビジネス・プロセスは Java クラスとして実装し、すべてのクラスは適切なアクセス制御ポリシーによってセキュアにする必要があります。

B2B 統合

B2B (Business-to-Business) 統合とは、2 つの企業体が特定の機能を互いに公開しなければならない場合の一般的なシナリオのことです。一例として、ホテルは宿泊予約機能を旅行業者に公開し、旅行業者はその機能を使用してこのホテルの空いている部屋を旅行者に代わって予約するとします。ビジネス・パートナーであるこの旅行業者には、特別宿泊料金が用意されていることも考えられます。その場合、ホテルの予約システムはその旅行業者を認証してから、特別料金で宿泊予約できるクラスへのアクセスを許可する必要があります。


Spring での Java オブジェクトの生成

以上の説明で、Java クラス・インスタンスへのアクセスをセキュアにできるということが重要である理由がわかったはずです。この高度なセキュリティーに対応した Acegi の機能を紹介する前に、これから説明する例を理解するために必要となる Spring フレームワークの主な特徴についての記憶を新たにしてもらいたいと思います。

まずは、Java クラスをいくつか構成してインスタンス化するところから取り掛かります。第 1 回の説明を覚えているかもしれませんが、Java クラスを構成する場所は Spring の XML 構成ファイルです。Spring 構成ファイルで Java クラスを構成する方法は Acegi フィルターを構成する方法とまったく同じなので、このステップについては説明しません。説明の代わりとして、リスト 1 に publicCatalog という名前の Bean の構成を示します。

リスト 1. Acegi の XML 構成ファイル
<beans>
    <bean id="publicCatalog" 
       class="com.catalog.PublicCatalog" />
    <!--Other bean tags -->
<beans>

Spring の IoC フレームワークが XML 構成ファイルから Java クラスの情報を読み取って、それをインスタンス化する方法を理解しておくことは重要です。連載第 1 回目の記事では、web.xml ファイルを使用して、ContextLoaderListener というクラスを指す <listener> タグを構成しました。この ContextLoaderListener が Spring の IoC フレームワークをロードして Java オブジェクトを生成します。この流れは第 1 回のリスト 8 を参照すると理解することができます。図 1 はそれを図解したものです。

図 1. Spring の IoC フレームワークをロードして Java オブジェクトを生成する流れ
Spring の IoC フレームワークをロードして Java オブジェクトを生成する流れ

上記のステップを詳しく説明しましょう。

  1. Acegi アプリケーションを開始すると、サーブレッド・コンテナー (Servlet Container) (この例では Apache Tomcat) がサーブレット・コンテキスト (ServletContext) を生成します。このサーブレット・コンテキストに、JSP ページやクラスなどのアプリケーション・リソースに関する情報が保持されます。
  2. サーブレッド・コンテナーが、アプリケーションが開始されていることを ContextLoaderListener クラスに通知します。
  3. ContextLoaderListener クラスは、アプリケーションの Spring 固有のリソースに関する情報を保持するために Web アプリケーション・コンテキストを生成します。Spring の IoC フレームワークでは、独自のカスタム・アプリケーション・コンテキストをロードすることができます。IoC フレームワークがアプリケーション・コンテキストの生成に使用するのは、ContextLoader という名前のコンテキスト・ローダー・クラスです。このクラスが、アプリケーション・コンテキストをロードします。
  4. アプリケーションが独自のアプリケーション・コンテキストを定義しない場合には、XMLWebApplicationContext クラスを使用することができます。Spring フレームワークの一部であるこのクラスには、Spring の XML 構成ファイルを処理する機能があります。Acegi アプリケーションは Spring の XML 構成ファイルを使用するため、この記事では XMLWebApplicationContext クラスによって表されるアプリケーション・コンテキストについてのみ説明します。この例の場合、コンテキスト・ローダーがインスタンス化するのは Acegi アプリケーションのアプリケーション・コンテキストを表す XMLWebApplicationContext クラスです。コンテキスト・ローダーは Web アプリケーション・コンテキストにサーブレット・コンテキスト (ステップ 1 で生成) の参照も設定します。
  5. XMLWebApplicationContext クラスが XML 構成ファイルを構文解析し、Java クラスに関する情報をこのクラスの内部オブジェクトにロードします。
  6. XMLWebApplicationContext クラスによって、XML 構成ファイルに指定されたすべての Java クラスがインスタンス化されます。XMLWebApplicationContext は XML 構成ファイルに構成された Java Bean が他の Java オブジェクトに依存しているかどうかをチェックし、依存している場合には他の Bean が依存する Bean を最初にインスタンス化します。このようにして、XMLWebApplicationContext クラスは XML 構成ファイルに定義されたすべての Bean のインスタンスを生成します (ステップ 6 では、XML 構成ファイルに構成されている Bean のなかでセキュアにする必要がある Bean は 1 つもないことを前提としていることに注意してください。ここで生成した Java Bean へのアクセスをセキュアにするためにステップ 5 とステップ 6 の間で発生した追加ステップについては、この後のセクションで説明します)。
  7. XMLWebApplicationContext クラスがすべての Bean を 1 つの配列に保管します。

XML 構成ファイルから Bean 定義をロードし、Java クラスのインスタンスを生成する方法は以上のとおりです。次は Spring Bean プロキシーを取り上げ、Java クラス・インスタンスへのアクセスをセキュアにする際のその重要性を説明します。


Bean プロキシーの使用

前のセクションでは Spring の IoC フレームワークがどのように Java オブジェクトをインスタンス化するかを説明しました。Java オブジェクトへのアクセスをセキュアにするために Spring の IoC フレームワークが使用するのは、Bean プロキシーの概念です。このセクションでは Bean プロキシーを構成する方法を説明した上で、Spring の IoC フレームワークがプロキシー・オブジェクトを生成する流れを説明します。

Java オブジェクトのプロキシーを構成する方法

プロキシー用 Bean を作成するには、Spring IoC フレームワークにプロキシー・クリエーター Bean のインスタンスを構成しなければなりません。Spring IoC フレームワークはプロキシー・クリエーターを使用してプロキシー・オブジェクトを生成します。リスト 2 は、privateCatalog という Java オブジェクトをセキュアにするために使用するプロキシー・クリエーター Bean の構成ファイルです。

リスト 2. プロキシー用 Bean の構成
<bean id="proxyCreator"
   class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="beanNames">
      <list>
        <value>privateCatalog</value>
        <!--Names of other beans to be proxied -->
      </list>
    </property>
    <property name="interceptorNames">
      <list>
         <value>privateCatalogSecurityInterceptor</value>
       </list>
    </property>
</bean>

リスト 2 を見るとわかるように、<bean> タグには class 属性があり、その値は org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator となっています。この BeanNameAutoProxyCreator クラスは、Spring IoC フレームワークの一部であり、Bean プロキシーを自動的に生成します。Spring フレームワークには、拡張性メカニズムを表す BeanPostProcessor という名前のインターフェースがあります。このメカニズムは、アプリケーションが独自のロジックで Bean プロキシーを生成できるようにするためのものです。Spring の BeanNameAutoProxyCreator クラスはこの BeanPostProcessor インターフェースを実装し、Java クラスをセキュアにするために必要なプロキシー生成ロジック一式を提供します。そのため、この記事の場合には BeanPostProcessor インターフェースを実装する必要はありません。

Bean プロキシーを生成する際に、BeanNameAutoProxyCreator クラスは beanNames プロパティーで定義されたすべての Bean に対してプロキシーを生成します (リスト 2 に記載した <bean> タグの最初の子 <property> を参照)。この beanNames プロパティーが取るのは、<list> タグに含まれる Bean 名のリストですが、リスト 2 ではプロキシーを生成する対象として privateCatalog という名前の Bean を 1 つしか構成していません。

今度はリスト 2 の <bean> タグが持つ 2 番目の子 <property> を見てください。ここに指定されている interceptorNames プロパティーは 1 つ以上のインターセプターをラップします。インターセプターの概念については後で詳しく説明するので、とりあえずは、インターセプターではユーザーからの要求をインターセプトし、アクセス制御ポリシーを実装してからユーザーに Bean へのアクセスを許可できるという点だけ覚えておいてください。

保護対象の Bean にプロキシーを構成する方法は以上のとおりです。次に、アプリケーションの Bean に対して Spring の IoC フレームワークが内部でプロキシー・オブジェクトを生成する方法を説明します。

Spring の IoC による引き継ぎ

Spring での Java オブジェクトの生成」セクションのステップ 5 とステップ 6 では、XMLWebApplicationContext クラスが XML 構成ファイルから Bean 定義を読み取って Bean インスタンスを生成しましたが、XMLWebApplicationContext クラスは Bean インスタンスを生成する前に、XML 構成ファイルにプロキシー・クリエーター Bean (つまり、BeanPostProcessor インターフェースを実装する Bean) の構成が含まれているかどうかをチェックします。構成を見つけた場合は、セキュアにする Bean の Bean プロキシーを生成するようプロキシー・クリエーターに要求します。

プロキシー・クリエーターが内部でプロキシー・オブジェクトを生成する方法は以下のとおりです。

  1. プロキシー・クリエーター (BeanNameAutoProxyCreator クラス) が、リスト 2 で構成した beanNames プロパティー・ファイルに指定されたすべての Bean 名をロードします。
  2. ロードした各 Bean 名に対応する Java クラスを、それぞれの Bean 定義の class 属性を使用してロードします。
  3. リスト 2interceptorNames プロパティーに指定されたインターセプターのインスタンスを生成します。
  4. 最後に、Cglib2AopProxy という名前のクラスのインスタンスを生成し、すべての Bean 名 (ステップ 2) とインターセプター (ステップ 3) をこの Cglib2AopProxy クラスに渡します。この Cglib2AopProxy クラスは Spring フレームワークの一部で、動的プロキシー・オブジェクトを生成する際に使用されます。Cglib2AopProxy クラスが生成するプロキシー・オブジェクトは、セキュアな Bean へのアクセスを制御するために必要となります。

Cglib2AopProxy クラスが実装するインターフェースは、AOPProxyMethodInterceptor の 2 つです。AOPProxy インターフェースは Spring フレームワークの一部で、プロキシー化の対象となる実際の Bean を表します。したがって、このインターフェースは該当する Bean と同じメソッドを公開します。AOP 仕様の一部でもある MethodInterceptor インターフェースのメソッドは、プロキシー化された Bean にユーザーがアクセスしようとするときに、必ず制御が渡されます。これはつまり、プロキシー化された Bean に対するユーザーからのアクセス要求は MethodInterceptor インターフェースによって処理されるということです。Cglib2AopProxy クラスは AOPProxy インターフェースと MethodInterceptor インターフェースの両方を実装することから、プロキシー化された Bean を表す完全な機能と、プロキシー化された Bean に対するユーザーのアクセス要求を処理する完全な機能とを提供するのは、このクラスであるということが想像できるはずです (AOP に関する記事へのリンクは「参考文献」セクションを参照してください)。

上記のステップを実行すると必要なプロキシー・オブジェクトが生成されるので、XMLWebApplicationContext クラスは「pring での Java オブジェクトの生成」セクションのステップ 7 での配列に (実際の Bean の代わりに) セキュアな Bean のプロキシーを保管します。


プロキシー Java オブジェクトへのアクセス

これまでのセクションでは、Spring がどのように共通 Bean と専用 Bean を生成するかについて説明しました。この記事では、共通 Bean はセキュアでない Bean、専用 Bean はプロキシーによって保護された Bean だと考えられます。ここからは、クライアント・アプリケーションが共通 Bean および専用 Bean にアクセスする際の一連の手順について見ていきましょう。

リスト 3 に 2 つの Bean、publicCatalogprivateCatalog の XML 構成を記載します。publicCatalog Bean は共通アクセス用なので Bean プロキシーは不要です。もう一方の privateCatalog Bean は指定されたユーザーだけがアクセスするよう意図されているため、セキュアにしなければなりません。したがって、リスト 3 には privateCatalog Bean の Bean プロキシー構成を含めてあります。

リスト 3. publicCatalog Bean および privateCatalog Bean の XML 構成
<beans>
  <bean id="publicCatalog" class="sample.PublicCatalog"/>
  <bean id="privateCatalog" class="sample.PrivateCatalog"/>

  <!-- proxy configuration for privateCatalog bean -->
  <bean id="proxyCreator"
    class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="beanNames">
      <list>
        <value>privateCatalog</value>
        <!--Names of other beans to be proxied -->
      </list>
    </property>    
    <property name="interceptorNames">
      <list>
         <value>privateCatalogSecurityInterceptor</value>
       </list>
    </property>
  </bean>
<beans>

リスト 4 に記載するのは、リスト 3 で構成した publicCatalog Java Bean および privateCatalog Java Bean にアクセスするためにアプリケーションが使用するコードの例です。リスト 4 の Java コードは JSP ページ、またはサーバー・サイド Java アプリケーション用の別の Bean に存在する場合があります。

リスト 4. セキュアな Java Bean および、セキュアでない Java Bean にアクセスするためのクライアント・アプリケーション・コード
//Step 1: Fetching an instance of the application context
XMLWebApplicationContext applicationCtx =
    WebApplicationContextUtils.getWebApplicationContext(
        this.getServletConfig().getServletContext());

//Step 2: Fetching an insecure bean from the application context
PublicCatalog publicCatalog = 
    (PublicCatalog) applicationCtx.getBean("publicCatalog");

//Step 3: Calling a method of the insecure bean
String publicData = publicCatalog.getData();

//Step 4: Fetching a secure bean from the application context
PrivateCatalog privateCatalog = 
    (PrivateCatalog) applicationCtx.getBean("privateCatalog");

//Step 5: Calling a method of the secure bean
String privateData = privateCatalog.getData();

リスト 4 の各ステップの詳細は以下のとおりです。

  • ステップ 1: アプリケーション・コンテキストのインスタンスをフェッチする
    アプリケーションが XML 構成ファイルに構成された Java Bean にアクセスするには、前に「Spring での Java オブジェクトの生成」のステップ 4 に出てきた XMLWebApplicationContext オブジェクトをフェッチする必要があります。XMLWebApplicationContext オブジェクトには、XML 構成ファイルに構成されたすべての Java Bean への参照が含まれるからです。
  • ステップ 2: アプリケーション・コンテキストからセキュアでない Bean をフェッチする
    上記のステップで XMLWebApplicationContext オブジェクトへの参照は取得できました。XMLWebApplicationContext クラスが公開する getBean() というメソッドは、Bean の名前を使って「Spring での Java オブジェクトの生成」のステップ 7 で生成した配列で該当する Bean を検索します。この例の場合、検索対象の Bean は publicCatalog なので (プロキシー化されていません)、XMLWebApplicationContext は実際の Bean を返します。
  • ステップ 3: セキュアでない Bean のメソッドを呼び出す
    ステップ 2 で取得した publicCatalog Bean のメソッドはどれでも呼び出すことができます。例えばリスト 4 の getData() メソッド呼び出しは、アクセス制御なしで実行され、カタログ・データをアプリケーションに返します。
  • ステップ 4: アプリケーション・コンテキストからセキュアな Bean をフェッチする
    セキュアな Bean をフェッチする方法はセキュアでない Bean をフェッチする場合と同様ですが、唯一の違いは、getBean() メソッドを呼び出してセキュアな Bean をフェッチしようとすると、実際のオブジェクトではなくセキュアなオブジェクトのプロキシーが返されることです。このプロキシーは、「Spring の IoC による引き継ぎ」のステップ 4 で Spring フレームワークが生成したオブジェクトと同じです。
  • ステップ 5: セキュアな Bean のメソッドを呼び出す
    セキュアな Bean のメソッドを呼び出すと、上記のステップ 4 で取得したプロキシー・オブジェクトがメソッド呼び出し要求をインターセプターにディスパッチします。インターセプターはメソッド呼び出し要求を処理する手段として、メソッドにアクセスしようとしているユーザーに適切なアクセス権があるかどうかをチェックします。

以上の説明で、Spring フレームワークが Java オブジェクトを生成する方法、そしてクライアント・アプリケーションが生成されたオブジェクトを操作する方法が明確になったはずです。この背景を踏まえていれば、次のセクションで説明する Acegi のメソッド・セキュリティー・インターセプターを理解するのも、使用するのも容易になります。


Acegi のメソッド・セキュリティー・インターセプターの構成

アプリケーションが Acegi Security System を使用してセキュアにされた Bean のメソッドにアクセスしようとすると、常にその要求は自動的に Acegi のメソッド・セキュリティー・インターセプターに転送されます。メソッド・セキュリティー・インターセプターの目的は、セキュアな Java Bean のメソッドへのアクセスを制御することです。このインターセプターは Acegi の認証および許可フレームワークを使用してユーザーにセキュアな Java Bean のメソッドの呼び出しが許可されているかどうかを確認し、その結果に基づいて応答を返します。

リスト 5 は、Acegi のメソッドセキュリティー・インターセプターの構成例です。

リスト 5. Acegi メソッド・セキュリティー・インターセプターの構成
<bean id="privateCatalogSecurityInterceptor"
  class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
  <property name="authenticationManager">
     <ref bean="authenticationManager"/>    
  </property>
  <property name="accessDecisionManager">
     <ref bean="accessDecisionManager"/>
  </property>
  <property name="objectDefinitionSource">
    <value>
      sample.PrivateCatalog.getData=ROLE_HEAD_OF_ENGINEERING
      <!-- Roles required by other beans -->
    </value>
  </property>
</bean>

リスト 5 のインターセプターの構成には、Java Bean へのアクセスをセキュアにするために構成する必要がある 3 つのプロパティー、authenticationManageraccessDecisionManager、および objectDefinitionSource が含まれています。

連載第 1 回で認証処理フィルターを構成する際に authenticationManager プロパティーを構成したことを思い出してください。authenticationManager プロパティーの目的は、ユーザーの認証です。

accessDecisionManager プロパティーについては、連載の第 2 回で説明しました。このアクセス決定マネージャーの役割は、認証の決定を行うことです。メソッド・セキュリティー・インターセプターは authenticationManageraccessDecisionManager プロパティーを使用してユーザーを認証し、権限を与えてからセキュアな Bean へのアクセスを許可します。

今度はリスト 5 で構成した objectDefinitionSource プロパティーを見てください。このプロパティーは第 1 回で説明した objectDefinitionSource プロパティーと似ていますが、元の objectDefinitionSource には /protected/*/** などの URL が含まれている一方、リスト 5 の objectDefinitionSource プロパティーではクラス名とメソッド名を指定しています。つまりこの例では、sample.PrivateCatalog は以前のステップでプロキシー化したクラスの名前で、getData はユーザー・アクセスの制御対象とするメソッドの名前です。

この構成により、ユーザーが PrivateCatalog BeangetData() メソッドにアクセスすると、制御は自動的にインターセプターに移ることになります。インターセプターは Acegi フレームワークを使用して、ユーザーのビジネス・ロールが ROLE_HEAD_OF_ENGINEERING (この例の場合) であるかどうかをチェックします。該当する場合、インターセプターは getData() メソッドへのアクセスを許可します。ユーザーに ROLE_HEAD_OF_ENGINEERING のビジネス・ロールがないことを検出した場合にはアクセスを拒否します。

次のセクションでは、これまでに説明した概念を実装するサンプル Acegi アプリケーションを紹介します。


サンプル Acegi アプリケーション

この記事に付属のソース・コードのダウンロード・ファイルには、AcegiMethodSecurity という名前のサンプル・アプリケーションが含まれています。このサンプル・アプリケーションを構成してデプロイする方法は以下のとおりです。

  1. LDAP サーバーにユーザー情報を設定します。ダウンロードしたサンプル・アプリケーションの LDIF ファイルには、LDAP サーバーにそのままロードできるユーザー情報が用意されています。LDIF ファイルを LDAP サーバーにインポートする方法については、第 2 回の「Populating the server」を参照してください。このアプリケーションでは、第 2 回と同じユーザー (alicebobspecialUser) を扱っています。
  2. ダウンロードしたソース・コードのうち、acegiMethodSecurity.war ファイルを Tomcat システムの webapps ディレクトリーにコピーします。
  3. Acegi の jar ファイルをサンプル・アプリケーションの WEB-INF/lib フォルダーにコピーします (この手順については、第 1 回の「アプリケーションのデプロイメントおよび実行手順」を参照)。
  4. cglib-full-2.0.2.jar ファイルをダウンロードして、サンプル・アプリケーションの WEB-INF/lib フォルダーにコピーします。

これで Tomcat を起動すれば、サンプル・アプリケーションを実行する準備はすべて完了です。

サンプル・アプリケーションの概要

サンプル・アプリケーションを呼び出すには、ブラウザーから URL、http://localhost:8080/acegiMethodSecurity にアクセスします。すると AcegiMethodSecurity アプリケーションは、図 2 のように 2 つのリンク (CatalogLogin) をリストした索引ページを表示します。

図 2. サンプル・アプリケーションのメイン・ページ
サンプル・アプリケーションのメイン・ページ

このアプリケーションの Catalog リンクをクリックすると、ログインが要求されます。alice または specialUser としてログインした場合、サンプル・アプリケーションは共通データと専用データの両方が含まれる完全な一覧を表示します。これは、リンク 5 のメソッド・セキュリティー・インターセプターは ROLE_HEAD_OF_ENGINEERING を持つユーザーに専用データ一覧へのアクセスを許可するように構成されていて、alicespecialUser にはどちらも該当するアクセス権があるからです。一方、bob としてログインした場合には、サンプル・アプリケーションは共通データしか表示しません。


認証済みユーザーへのロールの追加割り当て

このセクションでは、サンプル・アプリケーションの拡張バージョンを紹介します。この拡張バージョンで説明するのは、Acegi が実行時に認証済みユーザーに対して一時的に追加でロールを割り当てられるようにする仕組みです。

セキュアな Bean (リスト 3privateCatalog Bean など) がリモート・リソースにアクセスしなければならない場合には常に、追加のロールが必要になる可能性があります。一例として、セキュアな Bean が Java RMI (Remote Method Invocation) フレームワークまたは Web サービスを介してリモート・アプリケーションにアクセスする必要がある場合を考えてみてください。このとき、セキュアな Bean にアクセスしているユーザーには、リモート・アプリケーションがアクセスを許可する条件としているビジネス・ロールがないとします。

この場合、Acegi はまずユーザーにセキュアな Bean へのアクセス権があるかどうかをチェックした上で、セキュアな Bean へのユーザー・アクセスを許可します。セキュアな Bean がリモート・サービスにアクセスする際には、追加のビジネス・ロールが必要です。セキュアな Bean にアクセスしたユーザーに該当する追加のロールがなければ、セキュアな Bean はリモート・サービスに正常にアクセスすることができません。

run-as-replacement メカニズム

Acegi フレームワークには、run-as-replacement と呼ばれる単純なメカニズムがあります。これは、メソッドを呼び出す期間のみを対象として認証済みユーザーに 1 つ以上の追加のロールを構成できるメカニズムです。この run-as-replacement を使用すれば、セキュアな Bean がリモート・アプリケーションにアクセスするための追加のロールを構成することができます。つまり、セキュアな Bean にリモート・アプリケーションへのアクセスが必要な場合は常に Acegi がユーザーの追加ロールをロードするようにして、セキュアな Bean がリモート・アプリケーションにアクセスできるようにするわけです。

リスト 6 は、リスト 5 に記載したメソッド・セキュリティー・インターセプターを強化した構成です。この強化したバージョンでは、run-as-replacement メカニズムを使用しています。

リスト 6. Acegi のメソッド・セキュリティー・インターセプターを強化した構成

リスティングを見るにはここをクリック

リスト 6. Acegi のメソッド・セキュリティー・インターセプターを強化した構成

<bean id="privateCatalogSecurityInterceptor"
  class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
  <property name="authenticationManager">
     <ref bean="authenticationManager"/>    
  </property>
  <property name="accessDecisionManager">
     <ref bean="accessDecisionManager"/>
  </property>
  <property name="runAsManager">
<bean id="runAsManager" class="org.acegisecurity.runas.RunAsManagerImpl">
<property name="key"> <value>myKeyPass</value> </property> </bean> </property> <property name="objectDefinitionSource"> <value> sample.PrivateCatalog.getData=ROLE_HEAD_OF_ENGINEERING,RUN_AS_MANAGER </value> </property> </bean>

上記のリスト 6 では、機能強化した 2 箇所 (リスト 5 と比較した場合) が太字で示されています。最初の強化箇所は、runAsManager プロパティーです。runAsManager プロパティーの目的は、認証済みユーザーへの動的なロールの追加をサポートすることです。この目的のため、runAsManager プロパティーには RunAsManagerImpl という Bean の定義が含まれています。RunAsManagerImpl Bean は、objectDefinitionSource 内のメソッドのロールの定義に RUN_AS_ プレフィックスが付いたロールを検出した場合にのみアクティブになります。この例の場合、PrivateCatalog.getData() メソッドのロールの定義に RUN_AS_MANAGER のロールが指定されています (リスト 6 の 2 番目の強化箇所)。

RunAsManagerImpl Bean に含まれる key というプロパティーは、run-as-replacement の処理の流れの中でのみ追加でロールが生成されるようにするための暗号鍵をラップします。

ユーザーが getData() メソッドを呼び出すと、RunAsManagerImpl Bean がアクティブになり、RUN_AS_MANAGER というロールを追加で生成します。これによって、getData() メソッドがリモート・アプリケーションにアクセスできるようになります。

強化されたメソッド・セキュリティー

この記事付属のソース・コードのダウンロード・ファイルには、run-as-replacement メカニズムおよびその処理の流れを実演する EnhancedAcegiMethodSecurity というサンプル・アプリケーションが含まれています。このアプリケーションが表示する索引ページでCatalog リンクをクリックすると、ログインするよう要求されます。

ログインが完了すると、EnhancedAcegiMethodSecurity アプリケーションがログイン・ユーザーとそのユーザーのロールに関する完全な情報を表示します。例えば alice または specialUser としてログインした場合、一時的に追加される RUN_AS_MANAGER ロールを含め、該当するユーザーが持つすべてのビジネス・ロールが表示されます。

まとめ

この 3 回連載では、Acegi Security System を使って URL ベースのセキュリティーとメソッド・ベースのセキュリティーの双方ともに実施する手順として、アクセス制御ポリシーを設計してディレクトリー・サーバーでホストする方法、ディレクトリー・サーバーと通信するように Acegi を構成する方法、そしてホストされたアクセス制御ポリシーに基づいて認証および許可を決定する方法を説明しました。

最終回となるこの記事では、メソッド・ベースのセキュリティーで Java クラスのインスタンスを保護する方法に焦点を当てました。また、Acegi と Spring が内部でプロキシー Java オブジェクトを生成する流れと Bean プロキシーがアクセス制御を実装する仕組みについても説明しました。この記事に付属のサンプル・アプリケーションを使用すれば、この連載で学んだ概念をさらに詳しく探ることができます。Acegi によって実現するセキュアな Java アプリケーションについての詳細は、「参考文献」セクションを参照してください。


ダウンロード

内容ファイル名サイズ
Source code for this articlej-acegi3-source.zip36KB

参考文献

学ぶために

議論するために

コメント

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=Java technology
ArticleID=263701
ArticleTitle=Acegi を使って Java アプリケーションをセキュアにする、第 3 回: Java オブジェクトのアクセス制御
publish-date=09252007