Home > aclatraz

aclatraz

Aclatraz is a project mainly written in Ruby, based on the MIT license.

Flexible access control mechanism!

= ACLatraz

Extremaly fast, flexible and intuitive access control mechanism, powered by fast key value stores like Redis.

== Installation

You can simple install ACLatraz via rubygems:

sudo gem install aclatraz

== Configuration

Before you'll start play with access controll in your apps you have to correctly configure datastore for permissions (at this moment ACLatraz is only supporting Redis database as storage). Redis datastore configuration looks very simple:

Aclatraz.init :redis, "redis://localhost:6379/0"

Remember that using Redis, you should specify database dedicated only for ACLatraz.

== Suspects

Suspects are objects which we can assign specific permissions. There is only one condition which object have to meet to be suspect - it must have the #id method which returns an unique identifier after which we will be able to reference this object. To enable suspect behaviour you have to include the Aclatraz::Suspect module to specified class, eg:

class Account < ActiveRecord::Base include Aclatraz::Suspect end

Now your suspect have few methods which will helps you manage it permissions.

=== Managing roles

ACLatraz distinguishes between three types of roles:

  • global: simple roles, which are most commonly assigned to many users. We can say that they are kind of groups. Global roles are eg. guest, admin, customer.
  • class-related: roles that affects management of a particular class. Example of this kind of role can be manager of +Pages+, admin of +Products+, etc.
  • object-related: roles that affects management of an object. For example author of specified page, owner of specified product, etc.

Now there is two ways for managing roles. You can use #roles or semanticaly look like #is and #is_not proxies.

==== Assigning

To add given role you can use #assign method from #roles proxy or use semantic shortcuts. Semantic shortcut have to ends with "!", and can have optional suffixes: _on, _of, _at, _for, _in, _by. Take a look at the following examples to get everything to be clear:

@account.roles.assign(:admin) # or ... @account.is.admin!

...will assign global admin role to the account.

@account.roles.assign(:responsible, Foo) # or... @account.is.responsible_for!(Foo)

...will assign to the account responsible role related with +Foo+ class.

@account.roles.assign(:author, Page.find(15)) # or... @account.is.author_of!(Page.find(15))

...will assign to the account author role related with given +Page+ object.

==== Checking

Using #roles proxy you can call #has? method on it, eg:

@account.roles.has?(:admin) # => true @account.roles.has?(:responsible, Foo) # => true @account.roles.has?(:author, Page.find(15) # => true

With semantic shortcuts your method name have to ends with "?" and can contain any of suffixes listed above, eg:

@account.is.admin? # => true @account.is.responsible_for?(Foo) # => true @account.is.author_of?(Page.find(15)) # => true

Few more examples with semantic negation:

@account.is_not.admin? # => false @account.is_not.responsible_for?(Foo) # => false

You can also check permissions using nice block-style syntax. The code inside the block will be executed only when object has given role. An quick example:

@account.is.admin? do

only admins can se this...

end

==== Deleting

To unassign given role from object use #delete method from #roles, eg:

@account.roles.delete(:admin) @account.roles.delete(:responsible, Foo)

Another way is to use semantic negation, where method name have to ends with "!" and can contain one of allowed suffixes, eg:

@account.is_not.admin! @account.is_not.author_of!(Page.find(15))

== Guards

To enable access control in your for your objects you have to include to it the Aclatraz::Guard module. This module provides methods for defining and checking permissions of an suspected object. Take a look for this basic example:

class Foo include Aclatraz::Guard

suspects :account do 
  deny all # notice that it's a method, not symbol
  allow :admin
end

end

The #suspects block is passing one argument - suspected object. When there is symbol given, like in example above, then will treat #account instance method result as suspected object. When you will use string, eg:

suspects "account" do # or suspects "@account" do ...

... it will treat @account instance variable as suspect. You can also specify suspected object directly, eg:

account = Account.find(1) suspects account do # ...

=== Setting up permissions

As you probably noticed, there is two methods responsible for access control, namely #allow and #deny. As its argument you can pass simple name of role or permission statement, eg:

allow :admin deny :guest allow :responsible_for => Foo allow :author_of => "@page"

Like you see, you can easy specify access for each kind of role. The object-related permissions behaviour is similar to #suspects method. When given related object is string then applies permissions for an instance variable, when symbol then applies it for instance method, otherwise directly for given object.

=== Actions

In your access control block you can specify separate action with its own permissions, eg:

suspects :account do deny all allow :admin

action :manage do 
  allow :responsible_for => Foo
end

action :delete do 
  allow :author_of => "@page"
end

end

Obviously all actions inherits all permissions from main block.

=== Authorizing

The Aclatraz::Guards module provides #guard! method for checking permissions. When suspected object don't have any of allowed permissions or have any of defnied then it will raise the Aclatraz::AccessDenied error. Here's an comprehensive example:

class Foo suspects "@account" do deny all allow :admin action :foo allow :foo end action :bar allow :bar deny :admin end end

def initialize(account)
  @account = account
end

def simple
  guard!
  # only for accounts with :admin role...
end

def foo
  guard!(:foo)
  # only for accounts with :admin or :foo role...
end

def bar
  guard!(:bar)
  # only for accounts with :bar role...
end

def foobar
  guard!(:foo, :bar)
  # only for accounts with :foo or :bar, and mandatory without :admin role...
end

end

There is also a very nice feature. You can define additional permissions directly in #guard! block, eg:

def foo guard! do allow :foo deny :bar end

...

end

=== Inheritance

ACLatraz access control supports inheritance. It means that when you define your ACL in parent class it will be applied also for all child classes. Obviously in each child class you can freely modify permissions. Here's an example:

class Foo suspects :account do deny all allow :admin end end

class Bar < Foo suspects do

notice, that in child class don't have to again specify suspect...

  allow :foobar
end

end

class Spam < Foo suspects :egg do

but of course you can specify different suspect than in parent class...

end  

end

=== Aliases

If you prefer you can use aliases: #access_control instead of #suspects and #authorize! instead of #guard!.

== Note on Patches/Pull Requests

  • Fork the project.
  • Make your feature addition or bug fix.
  • Add tests for it. This is important so I don't break it in a future version unintentionally.
  • Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
  • Send me a pull request. Bonus points for topic branches.

== Copyright

Copyright (c) 2010 Kriss 'nu7hatch' Kowalik. See LICENSE for details.

Previous:litclub