rails
(105,849 views)

Authorization in Rails

Here's a review of several authorization add-on's for Rails. Whereas "authentication" refers to managing user login credentials, "authorization" is about managing role-based permissions to access specific areas of your site. [May 15, added Super Simple Authorization to the list]

Not everyone is clear on the distinction between "authentication" and "authorization". Basically authentication manages a list of users and their sessions, handles the login process by checking credentials (e.g. password), and registration. You can then restrict access to areas of your site based on whether a user is logged in or not. For Ruby on Rails applications, you can get authentication with the ActsAsAuthenticated ("AAA") or RestfulAuthentication plug-ins (among others), or build your own.

Authorization adds granularity. In addition to simply asking if you're logged in, different users can have different permissions , or "roles". Thus normal Users may be able to post comments, Moderators may be able to edit/delete comments, and Administrators may have full admin capability such as the ability to modify/remove users.

Here is a survey of a number of authorization add-ons available.

Super Simple Authorization

I recently watched the RailsCast #20 "Restricting Access" and decided to add it to this article. So here it is, at the top of our list.

If you have a User table (using AAA or RA) you can extend the table with an "admin" attribute, and then query current_user.admin? to test for authorization. Simple enough. You could extend this idea by having different booleans for editor, moderator and other roles you may require.

The screencast goes even simpler. If you really only want to restrict access to specific admin functions on an otherwise public site, you may not even need a Users table and registration at all. Instead your login page just asks the user for a password, which you store in the current session. Then you use an admin? method (to the application controller) which compares this against a hardcoded password.

Authorization Recipe

"Authorizing Users with Roles", Recipe 32 in Rails Recipes by Chad Fowler. (Published June 2006).

Builds from an existing User model, as described in Recipe 31 "Authenticating Your Users", or generated with AAA.

This recipe builds two new models for Roles and Rights, such that Users have Roles, Roles have Rights: (HABTM = has_and_belongs_to_many)

  • User HABTM roles
  • Role HABTM users
  • Role HABTM rights
  • Right HABTM roles

A right specifies a Controller name and Action name. Add a before_filter in your controllers to check_authorization, which determines whether the current user has rights to the incoming action call. If not he's redirected to an error page.

Simple enough, and bare bones. The implementation is not RESTful but that wouldn't be hard to change. More complexity is left as an exercise to the reader.

Simple_access_control

http://opensvn.csie.org/mabs29/plugins/simple_access_control

The simple_access_control plugin is basically the same as described above by Chad Fowler, offered in a plug-in, if you prefer. Tests are provided.

acl_system2

http://prometheus.hki.uni-koeln.de/pandora-doc/plugins/acl_system2/

http://opensvn.csie.org/ezra/rails/plugins/dev/acl_system2/

(Revision 146, February 2006, very low activity, no forum)

Like the aforementioned, the acl_system2 plugin provides simple declarative authorization for protecting controller/actions using roles. It provides a flexible permissions string parser that appears quite convenient. For example, a controller can declare:

access_control [:new, :create, :update, :edit] => '(admin | user | moderator)',
:delete => 'admin'

while allows users, moderators, and admins to create and update items, but only admins to delete items. You can specify callback methods for redirecting or doing other stuff (e.g. setting flash messages) when access is permitted or denied. A helper method, restrict_to, is provided for views, e.g.

<% restrict_to "(admin | moderator) & !blacklist" do %>
  <%= link_to "Admin & Moderator only link", :action =>'foo' %>
<% end %> 

ActiveACL Plugin

http://activeacl.rubyforge.org/

http://rubyforge.org/projects/activeacl

http://phpgacl.sourceforge.net/demo/phpgacl/docs/manual.html

(Release 0.2.1, December 2006, very low activity)

ActiveACL (as in active control lists) is based on PhpGacl and claims to be highly scalable, having optimized database access and caching. Permissions range from simple (controller/action) to object level, are assigned at runtime, and may be grouped and inherited.

To me, the documentation and implementation seems overly complicated and confusing. ActiveACL creates and manages ten (10) tables in the database. The phpgacl manual is helpful though. Here's how I think it works (mapping their terminology to more common words):

Let's say we group our users ("requesters") into roles ("groups"). Each user may or may not access different objects ("targets") on the site. Targets can be models, individual objects in a model, controllers, and individual actions in a controller.

We assign access restrictions to each role group, and/or to individual requesters; those lower in the tree override permissions higher up. So if "John" is an "Moderator" with access to all Articles, we can keep him from accessing a specific article (e.g. "Privacy Policy") by creating an access-denied for that one instance.

ActiveACL adds another table, called Section which is simply a way of categorizing access objects for the user interface (e.g. "Rooms", "Floors", "People") but have nothing to do with actual groups in the tree. (This seems to add unnecessary complexity because our models most likely already have attributes for organizing large data sets).

ActiveACL can be used not just for managing user groups/roles, but other application domains like server permissions, or maybe even modeling of engineering constraints.

Authorization Plugin

http://www.writertopia.com/developers/authorization

http://rubyforge.org/projects/authorization/

(Version 1.0, September, 2006, low activity)

The Authorization plug-in provides role based authorization, along with a number of Railsey sugar like dynamic methods and a little grammer parser that potentially enhances the programming experience and readability of your code (a la domain specific languages, DSL). It is compatible with ActsAsAuthenticated plugin out of the box. Documentation is comprehensible, and good test coverage is provided.

User objects just need to implement a has_role? method, using the provided acts_as_authorized_user. And models then use acts_as_authorizable.

Roles can be authorized for the entire application, a model class, or a specific object. The plugin provides a way of checking authorization at the class or instance method level using permit and permit? methods. It also provides english-like dynamic methods like "user.is_manager_of project" (where "user" acts as authorized, "manager" is a role, and "project" is an authorizable model). You can specify how control is redirected if authorization is denied.

Roles are set by has_role and accepts_role methods, with optional scope (such as user.has_role 'site_admin' , or user.has_role 'moderator', group). Models set roles for specific users (such as project.accepts_role 'manager', user). Then, dynamic methods let you say things like user.is_manager_of? project

Cool!

Goldberg

http://goldberg.240gl.org/

http://rubyforge.org/projects/goldberg/

(Version 0.2.0, April 2007, active)

The Goldberg plugin is an example of a high level generator that includes both authorization and authentication. It's like a framework built on top of the Rails framework, but actually sits beside it because you continue to develop your Rails app as usual, Goldberg does not interfere. You don't have to write any Goldberg-specific code in your application or use its API.

You define Roles (which can be has subgroup hierarchy), and assign permissions to the roles. A permssion is a controller/action that the role may access. Then you assign users to roles.

Goldberg installs as application-wide before-filters (if not exactly, at least conceptually) that examines the routed controller/action against its database of permissions ("credentials") for the current logged in user. Credentials are stored in the current session minimizing the need for database access between page loads.

That's just the beginning. Goldberg also provides a little hierarchical page manager (approaching a CMS) for static content; a menu manager for redirecting to pages or any arbitrary controller/action; and a theme system for dynamically re-skinning your application. It does not impose a specific markup on you, however. Finally there is an API for custom access control within your application.

Defense in Depth -- Model Level Security

http://www.perens.com/FreeSoftware/ModelSecurity/Tutorial.html

http://rubyforge.org/projects/model-security/

(Release 0.0.9 November, 2005, inactive)

Second level of defense. You still use your views to hide links to unauthorized actions, and set before_filter's in controllers to prevent unauthorized action methods from executing. But should someone get through, the model can also provide security.

The ModelSecurity gem is a generator. It provides for example let_read, let_write, and let_access added to model declarations, allow fine grained permissions to a whole model or separate attributes.

Includes a user model and UserSuport mixin. (Seems to been written before AAA so integration with AAA requires investigation).

Includes a ModelSecurityHelper which makes fields conform to the model security settings (eg makes form fields hidden or read-only).

Looks like a well thought-out generalized solution. My concern is the performance overhead this generalization requires, whether it plays well with various other helpers, AJAX, etc. Maybe its too scaffold oriented, and simply just overkill.

Conclusions

If your requirements are pretty simple, just a few roles like Visitor, User, and Admin, and don't need a lot of granularity (just control access to specific controller/actions) then you could use the convenient acl_system2, or just roll your own.

If you're looking for a high level, well designed tool to build fairly conventional sites quickly in Rails, then Goldberg is a good shot. It has a lot of commonly needed features built in. Why rebuild it yourself each time?

On the other hand, if you're building an application with more complex authorization requirements, the Authorization plugin seems a very good bet. For most people it may be overkill. But any kind of groupware or social networking site may benefit from this one.

 

Comments

by Valery on May 17, 2007

>>

Very nice overview, thanks!

i am trying to get running some ACL plugin/gem under Hobo and spent a lot of time trying to get Simple Access Control plugin running :-/

Perhaps, i give up with S.A.C. and try acl_system2 now

by Bill Kocik on Sep 19, 2007

acl_system2

Just as an FYI - I'm resurrecting acl_system2, with the blessings of its original author. It's new home is here:

http://rubyforge.org/projects/aclsystem

-Bill (bkocik at gmail dot com)

by Stephen McCants on Oct 29, 2007

>>

Very nice overview. I had done my own Google search and evaluation, but had missed several of the ones you list here.

Thanks!

by ricsrock on Dec 13, 2007

Re: Authorization in Rails

Did I see role_requirement in this article? Great plugin. Simple. Powerful. I'm using it in my project with no problems and great results. Easy to implement model-object security as well. Check it out: http://code.google.com/p/rolerequirement/

by christoph on Jul 19, 2008

>>

Is the information provided here still valid ?

by vince on Aug 07, 2008

Re: Authorization in Rails

yep but acl_system2 is hosting on github now

by PhilT on Jan 28, 2009

>>

Thought I'd update this as I was looking for information and just found a couple, more recent options. Take a look at AuthLogic and also Lockdown. Both seem pretty popular these days.

by Trejkaz on Mar 10, 2010

Re: Authorization in Rails

The one thing that continues to bug me about all these systems is that they are not DRY.

I spend all this time specifying on my controller the types of user who are permitted to access a resource, and then over in the view I have to say the same thing all over again.

I am thinking it would make more sense to make a conditional link_to which determines which controller and action will be called, then asks that controller if the action is accessible, and only shows the link if it is. A lot of these authorisation systems do have enough state information to be able to do this, so it's astonishing that nobody has completed the last part of the exercise.

by dsadsa on Dec 17, 2011

>>

dsafdfgdsgf hdhffggfhgjfhgjhgj

New Comment

markdown formatting permitted