第7回 J2EEのセキュリティのキホンを知る
――セキュリティの宣言的アプローチ――


 J2EEでの権限設定

 J2EEでは、あるアプリケーション中のあるBeanの特定のメソッドに対して、呼び出しの権限を与えたり、権限を認めなかったりすることができます。J2EEで、こうしたアプリケーションごとの権限設定の際に、大事な役割を果たすのが、「ロール」(Role)と呼ばれる、ユーザーの集まりの概念です。

 ロールは、J2EEのグループとよく似ていますが、次の点で異なります。J2EEのグループはJ2EEサーバ全体で定義されるのに対して、ロールはJ2EEサーバ上の特定のアプリケーションに対して定義されます。例えば、StudentというJ2EEのグループが存在するとしたら、同一のJ2EEサーバ上にdeployされるすべてのアプリケーション上で、そのStudentグループは意味を持ちます。それに対して、もしも、Studentというのがグループではなくロールだとすれば、そのStudentロールは、そのロールが定義されている、例えば、Universityアプリケーション上だけで意味を持ち、ほかのアプリケーションでは意味を持ちません。

 

 ロールの宣言

 ロールは、具体的にはWebコンポーネント、EJBコンポーネントごとに定義されます。ですから、コンポーネントを設計するときはどのような種類のユーザー、すなわちロールにこのコンポーネントへのアクセスを許すのかを考えておく必要があります。例えば、銀行口座のBean「Account」に対しては、「客」「銀行窓口」「支店長」からのアクセスが予想されます。こうしたユーザーのカテゴリがロールになるわけです。

 あるアプリケーションに対してロールを作るためには、そのアプリケーションに含まれるEJBの.jarファイルか、あるいは、Webコンポーネントの.warファイルで、ロールを宣言する必要があります。こうしたロールの宣言は、次のような手順でdeploytoolで可能です。

 deploytoolのツリーで、EJBの.jarファイル、あるいはWebコンポーネントの.warファイルを選びます。ついで、[Roles]のタブをクリックします。そして、そのタブで、まずロールの「名前」に値を入れます。このほかにも、[Edit Roles]のボタンが、セキュリティ関連のペインのいろいろなところに置かれていますので、必要に応じてロールを追加します。

 

 ロールへのユーザーとグループの対応づけ

 J2EEでは、Beanを配置する際に、J2EEユーザー(あるいはグループ)に、ロールを対応づけます。例えば、AccountというBeanで、佐藤を支店長に、高橋と斎藤を客に、山田を窓口に割り当てるというように考えるわけです。ここで、「客」「銀行窓口」「支店長」は、ロール名です。残念ながら、SunのRIで、ロール名やユーザー名に、日本語が使えるか、ちゃんと確かめることができませんでした。

 ロールへユーザーを対応づけるには、次のようにします。deploytoolのツリーで、アプリケーションを選びます。[Security]のタブの[Role Name]から適当なRoleを選び[Add]をクリックします(図5)。そうすると[User]ダイアログが開きますので、そのロールに属するユーザーあるいはグループを選びます(図6)。基本的には、アプリケーションに対応したロールの定義には、J2EEユーザーの定義とJ2EEグループの定義が先行していなければなりません。

図5 ロールへユーザーを対応づけるには、まずアプリケーションを選ぶ

図6 ロールに属するユーザーを選ぶ


 

 EJBメソッドのコントロール

 銀行で考えれば、客は自分の口座にお金を預けたり引き出したりは自由にできますが、口座を自分で作ることはできません。銀行の支店長と出納係は、口座の新設・抹消ができますが、客の口座の内容は変更できません。また、支店長だけが、監査の権限を持っています。次の表は、銀行Beanのメソッドごとのパーミッションの例です。

支店長 銀行 窓口
create(口座新設) ×
remove (口座抹消) ×
audit (監査) × ×
credit (預け入れ) × ×
debit (借り出し) × ×
transfer(振替) × ×

 このように、EJBの特定のメソッドの中は、特定のロールの属するユーザーからの呼び出しを許したり、逆に、禁止したりする、アクセスのコントロールが必要な場合があります。J2EEでは次のようにして、EJB内のすべてのメソッドに対して、宣言されたロールごとにパーミッションを設定することができます。

 deploytoolのツリーでビーンを選び、[Security]のタブをクリックします。その[Method Permissions]タブで、そのメソッドの呼び出しが認められるロールのチェックボックスを選びます(図7)

図7 ロールごとに設定を行う

 デフォルトでは、[Role Name]タブでは[ANYONE]というロールが、メソッドに割り当てられています。認証されていない匿名のguestユーザーは、この[ANYONE]ロールに属しています。ということは、デフォルトの状態のままで、ロールの対応づけをしなかったら、どのユーザーもBeanのメソッドを呼び出すことができるということになります。

 

 メソッド・パーミッションのからくり

 冒頭に書いたように、例えばisCallerInRoleメソッドを利用して、ロール名をハードコードするようなプログラムでBeanを作ることは可能です。その場合でもJ2EEでは、ハードコードされたロール名とdeploy時に与えられるロール名とを対応づけることが可能です。これは、データベース利用の際のJNDI名でも、同じようなメカニズムがあります。しかし、先ほど見たように、J2EEのセキュリティの特徴は、なんといっても外部から事後的な宣言でメソッドの呼び出しをコントロールできることです。ですから、Beanをコードする時点ではどのロールに属するユーザーにそのメソッドの呼び出しを許すかを意識するコードを書く必要がありません。

 最後に、J2EEでどのようにしてこのようなことが可能となっているのかを見てみようと思います。前回見たようにBeanのメソッドは、ユーザーの書いたコードが直接呼ばれるのではなく、コンテナによって、多少変形されたメソッドが呼び出されています。コンテナが、メソッドの呼び出し前と呼び出し後にいろんな処理を追加してメソッドを挟み込んでいることが、セキュリティ設定の場面でも非常に柔軟な処理を可能にしています。

 次のリストは、EJBの実装をオープンソースで行うことを目指している、OpenEJBプロジェクトが公開している、Entity Beanのコンテナ・クラスのソースです。リストを示したのは、コンテナがビーンのメソッドを呼び出すときに使われるinvokeメソッドの一部です。引数で与えられたcallMethodがビーンで定義された元のメソッドなのですが、それが呼び出される前にisCallerAuthorizedメソッドで、callMethodの呼び出し権限のチェックが行われています。Session Beanのコンテナについても、この部分についてはまったく同じコードを使っています。

public class EntityContainer implements org.openejb.RpcContainer {
.............
  public Object invoke(Object deployID, Method callMethod,
Object [] args,Object primKey, Object securityIdentity)
throws org.openejb.OpenEJBException
  {
  try{
    org.openejb.core.DeploymentInfo deployInfo =
(org.openejb.core.DeploymentInfo)this.getDeploymentInfo(deployID);
    ThreadContext callContext = ThreadContext.getThreadContext();
    callContext.set(deployInfo, primKey, securityIdentity);

    // isCallerAuthorizedでのメソッド呼び出しの権限のチェック
    boolean authorized =
    OpenEJB.
    getSecurityService().
    isCallerAuthorized(securityIdentity,
    deployInfo.getAuthorizedRoles(callMethod));

    if(!authorized)
throw new org.openejb.ApplicationException(
new RemoteException("Unauthorized Access by Principal Denied"));
    .............
    // メソッドの呼び出しへ
    .............
  }
  .............
  .............

}

 次に、boole値を返すisCallerAuthorizedメソッドの定義を示します。このメソッドは、securityIdentityが指定されたアクションを実行できるかを、メソッドの呼び手がロールの集合に含まれているかをチェックすることを通じて判定しています。

public boolean isCallerAuthorized(Object securityIdentity,String [] roleNames){
  try{
    Subject subject = this.getSubject(securityIdentity);
    java.util.Set prncplsSet = subject.getPrincipals();
    java.util.Iterator prncplsIterator = prncplsSet.iterator();

    while(prncplsIterator.hasNext()){
      Principal principal = (Principal)prncplsIterator.next();
     for(int i = 0; i < roleNames.length; i++){
        if(principal.getName().equals(roleNames[i]))
        return true;
      }
    }
    return false;
  }catch(org.openejb.OpenEJBException oee){
  return false;
  // FIXME: this interface should throw   org.openejb.spi.ServiceExceptions
  }
}

 J2EEの理解には、いくつかの段階があるように思います。J2EEの宣言的なアプローチは使う立場から見れば非常に便利ですので、その「約束事」を、ある意味ではまるごと覚えてキチンとマスターすることが必要です。覚えることはたくさんありますので、最初は無理に全部を相手にしないで、だんだんに守備範囲を拡大することです。ある程度「約束事」の理解ができたら、J2EEの要素技術やJ2EE内部の処理にも目を向けていってほしいと思います。できれば前回の記事も参考にして、J2EEのコンテナの行っている仕事をあらためて見直してください。

3/3

J2EEの基礎(第7回)
  セキュリティの宣言的アプローチ
  J2EEでの認証
J2EEでの権限設定

連載内容
J2EEの基礎
  第1回 Java Pet Storeで、J2EEを体験する(1)
  第2回 Java Pet Storeで、J2EEを体験する(2)
 

第3回 J2EEアプリケーションと配置(deployment)

  第4回 J2EEアプリケーションを構成するコンポーネント
  第5回 データベースのブラウザを作る
  第6回 EJBにおけるコンテナとコンポーネント
第7回 J2EEのセキュリティのキホンを知る
  第8回 J2EEのトランザクション処理


連載記事一覧




Java Agile フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Java Agile 記事ランキング

本日 月間