Builing an ACL Plugin for DataMapper - Part II

Last time I wrote about the internals of a proposed ACL plugin. Today I want to focus on the model. How would you define the ACL on the model? What additional methods will be made available on the model?

We should consider the following items:

  • How to set up a default of which resource (self or container) the ACL token is attached to.
  • How to override this default on a per ACL token instance basis. I.e. All on self except READ on container.
  • How to specify the default policy when no ACL is applied to CRUD methods. I.e. GRANT ALL or DENY ALL
  • How will CRUD method ACL tokens be specified
  • How will additional ACL tokens be specified.
  • How will we deal with the CREATE ACL token. It will have to live on the class. There is also the case where resources are “owned”. CREATE would then live on the owner instance.
  • How will we integrate into the finders, and other CRUD methods.
  • What custom methods will we add to the model.
  • Would we want multiple ACL tokens per action? For example reading a resource is allowed if you have MANAGER_READ or EMPLOYEE_READ tokens. (Kind of a silly example, but you get what i mean.) If so, would we want to configure OR’ing or AND’ing the tokens to get a result.

Enough talk! Lets give it a bash.

  1.  
  2. class Organisation
  3.   include DataMapper::Resource
  4.   include SuperDuper::ACL
  5.  
  6.   property :id, Fixnum, :serial => true
  7.   property :name, String
  8.  
  9.   # Start the SuperDuper::ACL configuration
  10.   acl_grant_on :organisation   # When granting store token on self
  11.   acl_deny_all                 # If not explicidly defined, DENY
  12.  
  13.   # Define the tokens we will grant/revoke and protect with
  14.   acl_create   :create, :grant_on => :class
  15.   acl_read     :read
  16.   acl_update   :update
  17.   acl_delete   :delete
  18.  
  19.   # Define a couple of custom tokens
  20.   acl_custom   :liquidate_assets
  21.   acl_custom   :throw_party  
  22. end
  23.  

Lets look at the code above, starting from line 10, acl_grant_on would define where we store the tokens. In this case tokens are stored on the instance. This is one area I want more clarity on. If we had a contact that was contained by an organisation and we were storing the token on the container, what would the syntax look like?

  1.  
  2. class Contact
  3.   include DataMapper::Resource
  4.   include SuperDuper::ACL
  5.  
  6.   property :id, Fixnum, :serial => true
  7.   property :name, String
  8.   property :organisation_id, Fixnum
  9.  
  10.   belongs_to :organisation
  11.  
  12.   # Start the SuperDuper::ACL config
  13.   acl_grant_on ‘contact.organisation’   # looking for a good way to do this.
  14. end
  15.  

On a side note, it is likley that the location of ACL token storage would have to be the instance or an association in the instances association chain. I don’t see being able to store it on some arbitrary object instance.

Moving to line 11 of the Organisation code, acl_deny_all simply says if a CRUD methods ACL token is not explicitly defined, DENY it. The opposite to this would be acl_allow_all which would ALLOW a CRUD method without an ACL token defined. It might be smart to default the resource to acl_deny_all so that you would only need to specify acl_allow_all if you where not happy with the default.

Lines 14-17 set a permission token for each of the CRUD methods. Line 14 shows the overriding of acl_grant_on for a individual ACL instance. In all likelihood acl_create would default to :class and you would not have the include the :grant_on option. An interesting idea on create might be to allow either :class or a named parameter of the constructor to be used. For example:

  1.  
  2. class Organisation
  3.   ..
  4.   acl_create   :create, :grant_on => :owner
  5.   ..
  6.   def initialize(user,owner,opts={})
  7.     ..
  8.   end  
  9. end
  10.  

At this stage I have no idea if/how to intergrate with the constructor. I will ask around! This also needs more thought. Does the above mean when I grant the ACL token to some user on an instance, the token is stored on the instance’s owner (yes), when in fact what I was trying to convey is that before you can create an org with instance as owner, you must have CREATE token on instance (if that makes scene).

Finally, at line 20-21 on the organisation code (top), acl_custom adds a couple of custom ACL tokens to the resource. These are obviously used to determine if the user can sell all the organisations assets and throw a big party with the proceeds.

Well this has turning into a rather long post. I haven’t gotten into the finder & other CRUD methods. They will have to have to wait for a part III.

– until next time –

Leave a Comment

Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.