Seamでのアクセス制御リスト(ACL:Access Control List)


※上記の広告は60日以上更新のないWIKIに表示されています。更新することで広告が下部へ移動します。

Seamでのアクセス制御リスト





Seamは常にWebアプリケーション開発者が直面する共通の問題を解決してきました。開発における様々な難問を解決する「ベストプラクティス」を統一コンポーネントモデルに提供することにより、開発者はフレームワークによって正しく解決される懸念事項を心配することなくアプリケーションのビジネスロジックに取り組めます。Seamは、PDFドキュメントの作成、メールの作成と送信、アプリケーションの国際化といったことを非常に簡単にします。また、長期にわたるビジネスプロセスやビジネスルールを提供するjBPMDroolsといったサードパーティプロジェクトと統合されます。CAPTCHAおよびWikiスタイルのマークアップ言語、いくつかの方法によるAjaxの実行もサポートされます。

エンタープライズアプリケーション開発における最も重要な領域の1つはセキュリティです。Seamではユーザーとロールによる、もしくはルール(規則)によるセキリティ許可で構築された安全な典型的なアプリケーションのコンポーネントとビューを作成可能とする強力なセキュリティAPIを長い間提供してきました。最近(バージョン2.1.0.GA現在)、Seamはより多くの方法で機密データを守るいくつかの新機能を提供するセキュリティエンジンを整備しました。本稿はこれらの新機能の一つの"persistent permissions to see how ACL"もしくはアプリケーションをオブジェクトレベルで安全にすることに用いる「インスタンス」ベースのセキュリティを見ていきます。

始めるのにルールベースとアクセス制御リスト(ACL:Access Control List)ベースのセキュリティの違いを調べましょう。ルールベースのセキュリティはオブジェクトの特定のクラスに対し一律の権限を適用するのにむいています。例えば、Seamの例のうちの1つから、以下のセキュリティルールを見ていきましょう:
(Seamのexamples/seamspace/resources/META-INF/security-rules.drl)
rule DeleteImage
  no-loop
  activation-group "permissions"
when
  acct: MemberAccount()
  image: MemberImage(mbr : member -> (mbr.memberId.equals(acct.member.memberId)))
  check: PermissionCheck(target == image, action == "delete", granted == false)
then
  check.grant();
end
 
このルールの条件部(ユーザーが以前にアップロードした画像はユーザー自身で削除することを許可する)が基本的に表すのは「もし、この画像の所有者であれば画像を削除することができる」です。この例では、セキュリティ許可はすべての画像にあてはまって、画像とその所有者に関連リンクがあるという事実に基づいています。この関連を介してセキュリティルールは現在のユーザーが画像の所有者であり、さらに削除の実行権限を付与することを決定できます。ですが権限と照合する対象とユーザー(以下「主役(principal)」)に関連がない場合どうなるでしょう?ここがアクセス制御リスト(ACL:Access Control List)が必要になるところです。

アクセス制御リスト(ACL:Access Control List)は特定のオブジェクトに対し、明白な権限割り当てを行うリストです。リストの各項目は受取人(権限を割り当てられた主役(principal))を含んでいます。*nixベースのオペレーティングシステム(eg Unix,Linux)を使用したことがあるのであれば、特定の種類のアクセス制御リスト(ACL:Access Control List)、ファイルシステムはファイル毎の読み書きの実行権限テーブルを持っている(Windowsは似たようなファイルセキュリティですが人が見てすぐわかるものではありません)をすでによく知っているはずです。Seamでのアクセス制御リスト(ACL:Access Control List)ベースセキュリティも同じ方法ですが、ファイルの代わりにオブジェクトのインスタンスの安全を確保するのに使われます。一般的なアプリケーションではオブジェクトのインスタンスは通常エンティティですが、すぐにどんな種類のオブジェクトも安全にすることが可能であることがわかります。


オブジェクトに権限を割り当てる前に、少し準備をする必要があります。最も重要なのは実際に権限自体を保存するための場所が必要だということです。Seamアクセス制御リスト(ACL:Access Control List)オブジェクトを管理するために必要なメソッドを宣言したPermissionStoreインターフェイスを提供します。理論上どんな種類の保存ストレージ(例えばファイル、LDAP)でも権限を保存できますが、通常リレーショナルデータベースを使用することを意味します。SeamJPAを使用して権限をデータベースに保存することを可能とするJpaPermissionStoreというPermissionStoreの実装でこれを可能とします。JpaPermissionStoreを使用するのに2つのことを行う必要があります。権限の記録を保持するエンティティビーンを作成し、Seamのcomponent.xmlにそのエンティティビーンの設定を行う。


特別なアノテーションセットはエンティティのプロパティが権限におけるどのような側面を意味するのかを構成するのに使用します。以下のコードは最低限の例を示しています(簡潔にするためにアノテーションはフィールドに示します、ゲッタ/セッターメソッドは省略します。)
  1. public class AccountPermission implements Serializable
  2. {
  3. @Id @GeneratedValue public Integer permissionId;
  4. @PermissionUser @PermissionRole public String recipient;
  5. @PermissionTarget public String target;
  6. @PermissionAction public String action;
  7. @PermissionDiscriminator public String discriminator;
  8. }
  9.  

@PermissionUser@PermissionRoleアノテーションはプロパティが権限の受取人(recipient)を含んでいることを表します。この例では、ユーザーと権限を与えられた役割を保持する一つのテーブルを使用するので両方のアノテーションをフィールドに設定します。両方の権限(ユーザーと役割)を同じテーブルに保存する為、Seamがユーザー、役割のどちらのためのエントリなのか見分けることができるように識別(discriminator)(@PermissionDiscriminatorを付与した)プロパティが必要です。最後に権限を付与する対象を保持する(@PermissionTargetを付与した)プロパティと許可する動作を保持する(@PermissionActionを付与した)プロパティが必要です。


エンティティを作成したので、単純に次のエントリをSeamのcomponent.xmlファイルに追加しJpaPermissionStoreを使用するように設定する必要があります。
  1. <security:jpa-permission-store user-permission-class="com.acme.AccountPermission"/>
  2.  

権限を保存するエンティティの作成と設定を行ったので、権限の割り当てを開始できます。SeamのセキュリティAPIはPermissionManagerと呼ばれるオブジェクトの権限管理を簡単にする便利なコンポーネントを提供しています。PermissionManagerのメソッドはPermissionStoreインターフェイスに非常に似ています。実際、

Its methods look very similar to those found in the PermissionStore interface, and in fact they essentially delegate to the underlying PermissionStore however with one small restriction - each permission related operation that is invoked is first checked to ensure that the calling user has the necessary privileges to invoke that operation. More details about this can be found in the Seam Reference Guide, however suffice it to say that not just any user can manage object permissions, they must first have the required privileges to do so.



Let's grant our first permission! Imagine that your application contains a table of customers (represented by an entity bean called Customer) and you would like to grant update privileges on certain customers to your various salespeople. Let's say that you want to allow Bob the salesman to manage the details of your best customer, the Jones account (which happens to have a customer ID of 1234). We grant permission to Bob to manage this customer by invoking the following method:
  1. PermissionManager.instance().grantPermission(new Permission(entityManager.find(Customer.class, 1234),
  2. "update", new SimplePrincipal("bob")));
  3.  
In doing this, the PermissionManager will delegate the grantPermission() call to the configured JpaPermissionStore (after validating that the current user has the necessary privileges to do so) and a new permission record will be created in the database. Let's diverge for a moment to see exactly what gets written to the AccountPermission table:
AccountPermission
=================
RECIPIENT  TARGET         ACTION  DISCRIMINATOR
-----------------------------------------------
bob        Customer:1234  update  user

Here we can obviously see from the column values that the recipient is "bob", the action is "update" and the discriminator is "user" (because Bob is a user, not a role). The contents of the target column are a little more interesting. The value that is displayed here is known as the object identifier, and is used to uniquely identify a particular instance of an object. In this case, the target in question is an entity and fortunately for us Seam already knows how to generate unique object identifiers for entities. If however the target of the permission isn't an entity but an instance of some other type of class then Seam must be told how to generate an object identifier for that class. This is done by adding the @Identifier annotation to the class in question, and specifying an implementation of IdentifierStrategy like so:

  1. @Identifier(CustomIdentifierStrategy.class)
  2. public class MyNonEntityClassThatIWantToAssignPermissionsTo {
  3. public String getUniqueProperty() { return foo; }
  4. }
  5.  

The IdentifierStrategy interface is extremely simple, declaring only two methods. The canIdentify() method returns true if the IdentifierStrategy implementation is capable of generating an identifier for the specified class, and the getIdentifier() method returns a unique identifier String for the specified object. For example, the EntityIdentifierStrategy implementation that is included with Seam produces identifiers for entities by concatenating the name of the entity with its ID property.


Here's an example of what an implementation might look like:
  1. public class CustomIdentifierStrategy implements IdentifierStrategy {
  2. public boolean canIdentify(Class targetClass) {
  3. return targetClass.equals(MyNonEntityClassThatIWantToAssignPermissionsTo.class);
  4. }
  5. public String getIdentifier(Object target) {
  6. return ((MyNonEntityClassThatIWantToAssignPermissionsTo) object).getUniqueProperty();
  7. }
  8. }
  9.  
It is also worth mentioning that it is possible to assign permissions for literal string constants. I.e, the permission target isn't always required to be an entity or other object instance. The PermissionManager will happily allow you to grant permissions against a string literal, which may be useful if you need to maintain a set of arbitrary permissions. The same goes for classes, for example if you'd like to assign a "create" permission for a certain class then it is possible to do so (obviously it's not possible to assign a "create" permission for an object instance when it doesn't exist yet).

Once all the pieces are in place, you can use the standard mechanisms provided by Seam to secure your objects in the view and within your action components (see the Seam Reference Guide for more info).

In the next article, we'll look in more detail at the way that permission actions can be defined and stored, and also look at how we can create permission management views to more easily manage our object permissions through a nice user interface.

ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。