ACL Security In Seam, Part 1

来源:互联网 发布:java成神之路 编辑:程序博客网 时间:2024/06/14 19:04

Seam has always been about solving the common issues faced by webapplication developers.  By providing a selection of "Best Practice"solutions to various development challenges in a unified componentmodel, the developer is free to work on the business logic of theirapplication without having to worry as much about the concerns thatshould be rightly addressed by the framework.  Seam makes it very easyto do things such as generate PDF documents, generate and send e-mails,and internationalise your application.  It also integrates with thirdparty projects such as jBPM and Drools to provide support for longrunning business processes and business rules.  Support for CAPTCHA,and a wiki-style markup language are also there, as well as a number ofways of doing AJAX.

One of the most important areas of enterpriseapplication development though is security.  Seam has long provided arobust Security API allowing the components and views that a typicalapplication consists of to be secured via user and role security, orrule-based security permissions.  Recently though (as of version2.1.0.GA) Seam has overhauled its security engine to provide a numberof new features offering even more ways to secure your sensitive data. This article will look at one of these new features, persistentpermissions to see how ACL, or "instance" based security can be used tosecure your application at the object level.

To get started,let's examine the differences between rule-based and ACL-basedsecurity.  Rule-based security is great for applying blanketpermissions to a particular class of object.  For example, let's take alook at the following security rule from one of the Seam examples:

  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

Theconditional part of this rule (which allows users to delete images thatthey've previously uploaded) essentially says, "if you're the owner ofthis image, then you're allowed to delete it".  In this example, thesecurity permission applies to all images and is dependent on the factthat there is a relational link between the image and its owner.  It isthrough this relationship that the security rule can determine that thecurrent user is the owner of the image, and in turn grant permission toexecute the action.  However, what if there was no relationship betweenthe target of the permission check and the user (who we'll refer to asthe principal from here on)?  This is where ACL security comes in.

AnACL (Access Control List) is a list of explicit permissions assigned toa particular object.  Each entry in the list contains a recipient (theprincipal who is granted the permission) and an action.  If you've everused a *nix based operating system then you should already be familiarwith a particular type of ACL - the file system contains a table ofread, write and execute permissions for each file (yes, Windows hassimilar file security but it's not as obvious).  ACL-based security inSeam works much the same way, except that it is used to secure objectinstances instead of files.  In a typical application these objectinstances will generally be entities, however we'll soon see that it ispossible to secure any type of object.

 

Before we can start assigning permissions for our objects, we firstneed to do a little preparation.  Most importantly we need a place tostore the actual permissions themselves.  Seam provides aPermissionStore interface that declares the methods required formanaging ACL object permissions.  While it is theoretically possible tostore permissions in any type of persistent storage (e.g. in files, inLDAP, etc) it generally makes most sense to use a relational database. To that effect Seam comes with a PermissionStore implementation calledJpaPermissionStore, which allows permissions to be stored in a databaseusing JPA.  To use JpaPermissionStore we need to do two things; createan entity bean to hold the permission records, and configure thatentity bean in Seam's component.xml.

Aspecial set of annotations is used to configure which properties of theentity represent the aspects of the permission.  The following codeshows a bare minimum example (for the sake of brevity the annotationsare shown on the fields, and getter/setter methods are omitted):

  @Entity
public class AccountPermission implements Serializable
{
@Id @GeneratedValue public Integer permissionId;
@PermissionUser @PermissionRole public String recipient;
@PermissionTarget public String target;
@PermissionAction public String action;
@PermissionDiscriminator public String discriminator;
}

 

The@PermissionUser and @PermissionRole annotations indicate the propertycontaining the recipient of the permission.  In this example we areusing a single table to hold both user and role permissions, so we putboth of the annotations on the recipient field - and since we arestoring both types of permission in the same table we also need adiscriminator (annotated with @PermissionDiscriminator) property sothat Seam can tell which entries are for users and which are forroles.  Finally, we need a property to store the permission target(annotated with @PermissionTarget) and a property for the permissionaction (annotated with @PermissionAction). 

Once we havecreated our entity, we simply need to configure JpaPermissionStore touse it by adding the following entry to Seam's components.xmlconfiguration file:

 <security:jpa-permission-store user-permission-class="com.acme.AccountPermission"/>

  
Nowthat we have created and configured our permission store entity, we canstart assigning permissions.  Seam's Security API provides a convenientcomponent called PermissionManager, which allows us to easily manageobject permissions.  Its methods look very similar to those found inthe PermissionStore interface, and in fact they essentially delegate tothe underlying PermissionStore however with one small restriction -each permission related operation that is invoked is first checked toensure that the calling user has the necessary privileges to invokethat operation.  More details about this can be found in the SeamReference Guide, however suffice it to say that not just any user canmanage object permissions, they must first have the required privilegesto do so.

 

Let's grant our first permission!  Imagine that your applicationcontains a table of customers (represented by an entity bean calledCustomer) and you would like to grant update privileges on certaincustomers to your various salespeople.  Let's say that you want toallow Bob the salesman to manage the details of your best customer, theJones account (which happens to have a customer ID of 1234).  We grantpermission to Bob to manage this customer by invoking the followingmethod:

  PermissionManager.instance().grantPermission(new Permission(entityManager.find(Customer.class, 1234), 
"update", new SimplePrincipal("bob")));

 Indoing this, the PermissionManager will delegate the grantPermission()call to the configured JpaPermissionStore (after validating that thecurrent user has the necessary privileges to do so) and a newpermission record will be created in the database.  Let's diverge for amoment to see exactly what gets written to the AccountPermission table:

AccountPermission
=================
RECIPIENT  TARGET         ACTION  DISCRIMINATOR
-----------------------------------------------
bob        Customer:1234  update  user

Herewe can obviously see from the column values that the recipient is"bob", the action is "update" and the discriminator is "user" (becauseBob is a user, not a role).  The contents of the target column are alittle more interesting.  The value that is displayed here is known asthe object identifier, and is used to uniquely identify a particularinstance of an object.  In this case, the target in question is anentity and fortunately for us Seam already knows how to generate uniqueobject identifiers for entities.  If however the target of thepermission isn't an entity but an instance of some other type of classthen Seam must be told how to generate an object identifier for thatclass.  This is done by adding the @Identifier annotation to the classin question, and specifying an implementation of IdentifierStrategylike so:

  @Identifier(CustomIdentifierStrategy.class)
public class MyNonEntityClassThatIWantToAssignPermissionsTo {
public String getUniqueProperty() { return foo; }
}

TheIdentifierStrategy interface is extremely simple, declaring only twomethods.  The canIdentify() method returns true if theIdentifierStrategy implementation is capable of generating anidentifier for the specified class, and the getIdentifier() methodreturns a unique identifier String for the specified object.  Forexample, the EntityIdentifierStrategy implementation that is includedwith Seam produces identifiers for entities by concatenating the nameof 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);
}
public String getIdentifier(Object target) {
return ((MyNonEntityClassThatIWantToAssignPermissionsTo) object).getUniqueProperty();
}
}

Itis also worth mentioning that it is possible to assign permissions forliteral string constants.  I.e, the permission target isn't alwaysrequired to be an entity or other object instance.  ThePermissionManager will happily allow you to grant permissions against astring literal, which may be useful if you need to maintain a set ofarbitrary permissions.  The same goes for classes, for example if you'dlike to assign a "create" permission for a certain class then it ispossible to do so (obviously it's not possible to assign a "create"permission for an object instance when it doesn't exist yet).

Onceall the pieces are in place, you can use the standard mechanismsprovided by Seam to secure your objects in the view and within youraction components (see the Seam Reference Guide for more info).

Inthe next article, we'll look in more detail at the way that permissionactions can be defined and stored, and also look at how we can createpermission management views to more easily manage our objectpermissions through a nice user interface.

 

转自:http://java.dzone.com/articles/acl-security-in-seam?page=0%2C0

原创粉丝点击