Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Authority helps you authorize actions in your Rails app. It's ORM-neutral and has very little fancy syntax; just group your models under one or more Authorizer classes and write plain Ruby methods on them.
Ruby

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.
lib
spec
.gitignore
.rvmrc
Gemfile
LICENSE
README.md
Rakefile
authority.gemspec

README.md

Authority

SUPER ALPHA VERSION

Overview

Authority gives you a clean and easy way to say, in your Rails app, who is allowed to do what with your models.

It assumes that you already have some kind of user object in your application.

The goals of Authority are:

  • To allow broad, class-level rules. Examples:

    • "Basic users cannot delete any Widget."
    • "Only admin users can create Offices."
  • To allow fine-grained, instance-level rules. Examples:

    • "Management users can only edit schedules in their jurisdiction."
    • "Users can't create playlists more than 20 songs long unless they've paid."
  • To provide a clear syntax for permissions-based views. Example:

    • link_to 'Edit Widget', edit_widget_path(@widget) if current_user.can_edit?(@widget)
  • To gracefully handle any access violations: display a "you can't do that" screen and log the violation.

  • To do all of this without cluttering either your controllers or your models. This is done by letting Authorizer classes do most of the work. More on that below.

Installation

Add this line to your application's Gemfile:

gem 'authority'

And then execute:

$ bundle

Or install it yourself as:

$ gem install authority

How it works

In broad terms, the authorization process flows like this:

  • A request comes to a model, either the class or an instance, saying "can this user do this action to you?"
  • The model passes that question to its Authorizer
  • The Authorizer checks whatever user properties and business rules are relevant to answer that question.
  • The answer is passed back up to the model, then back to the original caller

Usage

Users

Your user model (whatever you call it) should include Authority::UserAbilities. This defines methods like can_edit?(resource), which are just nice shortcuts for resource.editable_by?(user). (TODO: Add this module).

Models

In your models, simply include Authority::Abilities. This sets up both class-level and instance-level methods like creatable_by?(user), etc, all of which delegate to the model's corresponding authorizer. For example, the Rabbit model would delegate to RabbitAuthorizer.

Controllers

Basic Usage

In your controllers, add this method call:

check_authorization_on ModelName

That sets up a :before_filter that calls your class-level methods before each action. For instance, before running the update action, it will check whether ModelName is updatable_by? the current user at a class level. A return value of false means "this user can never update models of this class."

If that's all you need, one line does it.

In-action usage

If you need to check some attributes of a model instance to decide if an action is permissible, you can use check_authorization_for(:action, @model_instance, @user) (TODO: determine this)

Authorizers

Authorizers should be added under app/authorizers, one for each of your models. Each authorizer should correspond to a single model. So if you have app/models/laser_cannon.rb, you should have, at minimum:

# app/authorizers/laser_cannon_authorizer.rb
class LaserCannonAuthorizer < Authority::Authorizer
end

These are where your actual authorization logic goes. You do have to specify your own business rules, but Authority comes with the following baked in:

  • All class-level methods defined on Authority::Authorizer return false by default; you must override them in your Authorizers to grant permissions. This whitelisting approach will keep you from accidentally allowing things you didn't intend.
  • All instance-level methods defined on Authority::Authorizer call their corresponding class-level method by default.

This combination means that, with this code:

# app/authorizers/laser_cannon_authorizer.rb
class LaserCannonAuthorizer < Authority::Authorizer
end

... you can already do the following:

current_user.can_create?(LaserCannon)    # false; all inherited class-level permissions are false
current_user.can_create?(@laser_cannon)  # false; instance-level permissions check class-level ones by default

If you update your authorizer as follows:

# app/authorizers/laser_cannon_authorizer.rb
class LaserCannonAuthorizer < Authority::Authorizer

  def self.creatable_by?(user) # class-level permission
    true
  end

  def deletable_by?(user)      # instance_level permission
    user.first_name == 'Larry' && Date.today.friday?
  end

end

... you can now do this following:

current_user.can_create?(LaserCannon)    # true, per class method above
current_user.can_create?(@laser_cannon)  # true; inherited instance method calls class method
current_user.can_delete?(@laser_cannon)  # Only Larry, and only on Fridays

TODO

  • Add a module, to be included in whatever user class an app has, which defines all the can_(verb) methods.
  • Determine exact syntax for checking rules during a controller action.
  • Add ability to customize default authorization
  • Add customizable logger for authorization violations

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Added some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request
Something went wrong with that request. Please try again.