Seamは常に
Webアプリケーション開発者が直面する共通の問題を解決してきました。開発における様々な難問を解決する「ベストプラクティス」を統一コンポーネントモデルに提供することにより、開発者はフレームワークによって正しく解決される懸念事項を心配することなくアプリケーションのビジネスロジックに取り組めます。
Seamは、PDFドキュメントの作成、メールの作成と送信、アプリケーションの国際化といったことを非常に簡単にします。また、長期にわたるビジネスプロセスやビジネスルールを提供する
jBPMや
Droolsといったサードパーティプロジェクトと統合されます。
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)が必要になるところです。
特別な
アノテーションセットはエンティティのプロパティが権限におけるどのような側面を意味するのかを構成するのに使用します。以下のコードは最低限の例を示しています(簡潔にするために
アノテーションはフィールドに示します、ゲッタ/セッターメソッドは省略します。)
{
@Id @GeneratedValue
public Integer permissionId
; @PermissionUser @PermissionRole
public String recipient
; @PermissionTarget
public String target
; @PermissionAction
public String action
; @PermissionDiscriminator
public String discriminator
; }
<security:jpa-permission-store user-permission-class="com.acme.AccountPermission"/>
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:
PermissionManager.
instance().
grantPermission(new Permission(entityManager.
find(Customer.
class,
1234),
"update", new SimplePrincipal("bob")));
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:
@Identifier(CustomIdentifierStrategy.class)
public class MyNonEntityClassThatIWantToAssignPermissionsTo {
public String getUniqueProperty
() { return foo
; } }
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:
public class CustomIdentifierStrategy implements IdentifierStrategy {
public boolean canIdentify(Class targetClass) {
return targetClass.equals(MyNonEntityClassThatIWantToAssignPermissionsTo.class);
}
return ((MyNonEntityClassThatIWantToAssignPermissionsTo) object).getUniqueProperty();
}
}
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.
最終更新:2009年01月27日 08:24