Skip to content

Tutorial: securing a controller

be9 edited this page Sep 13, 2010 · 44 revisions

Agenda: we’ve got a standard REST controller (ProductsController) and want to discover how access restrictions can be applied to it (using acl9 of course!)

Here’s the controller (with omitted action bodies for brevity):

class ProductsController < ApplicationController
  def index
    # ...
  end

  def show
    # ...
  end

  def new
    # ...
  end

  def edit
    # ...
  end

  def create
    # ...
  end

  def update
    # ...
  end

  def destroy
    # ...
  end
end

Install acl9

Add a line to the config/environment.rb file and install the gem.

config.gem “be9-acl9”, :source => “http://gems.github.com”, :lib => “acl9”

First step: use acl9 with no restrictions

When everyone is allowed to do everything, it’s also access control. So we’ll start from this.

All access rules in controllers are put into access_control block. The all-permissive variant will be:


class ProductsController < ApplicationController
access_control do
allow all
end def index

  1. end
  1. …other actions…
    end

allow all makes sense here, doesn’t it?

This controller should work, if it doesn’t, you might have some problems with acl9 installation.

Second step: allow only logged in users

So, you actually don’t want your competitor to come and delete all your products, replacing them with theirs! A simple scheme could work: you’re the only registered user, you do the stuff, and others are just anonymous users with no rights.

How about this?

  access_control do
     allow logged_in
  end

Seems cool. Only logged in users can… but wait! Now nobody can’t even see your products (except you)! Something must be done:

  access_control do   
     allow logged_in
     allow anonymous, :to => [:index, :show]
  end

The second rule to the rescue. In this case anonymous users can see, but not create, edit, or destroy products.

How acl9 knows the user is logged in or not?

Short answer: not controller.send(:current_user).nil?.

This means you should use some authentication solution (authlogic, restful_authentication, clearance, or roll out your own current_user implementation).

Note_: if the method is named differently (current_account, or even @current_jedi_that_shouldbe@), acl9 can be configured to handle that (see the docs).

What happens when anonymous user goes to, say, /products/new?

Answer: Acl9::AccessDenied exception is raised.

You’ll probably handle this in the ApplicationController, in the following manner:

  class ApplicationController < ActionController::Base
    rescue_from 'Acl9::AccessDenied', :with => :access_denied

    # ...other stuff...
    private

    def access_denied
      if current_user
        render :template => 'home/access_denied'
      else
        flash[:notice] = 'Access denied. Try to log in first.'
        redirect_to login_path
      end
    end    
  end

More to come…

Clone this wiki locally