Role Based Authorization recipe implementation?


#1

i got the rails recipes book, i have now an auth system for users
without problems, now i want to made a role based acces for my app, im
following the “Role Based Authorization” recipe of the book but i cant
make it to work even when the tables created and correctly added data
manually definig the roles and rights. als i dont know how to define a
right for use all the actions in a certain controller or define another
that gives right to use a group of controllers.

If someone knows where to find an implementation of this, good
references about this kind of auth system or willing to help with this
will be excellent. :slight_smile:


#2

I implemented the RBAC from the recipes book it seems to work fine. I
added
synchronize_with_controllers to my rights model, taken from the
user_engine (which is a
great resource to get ideas from), it automatically finds all
controllers and actions
and adds them to the rights table.

Then all you have to do is associate the relevant right with the
relevant role.

I have an example view to do that which I’ll try to write up and post
somewhere.

It is also helpful to have an override to get things setup initially,
what I do is allow
any used logged in with the name admin, to get rights to everything.
basically add
something like this to the authorized? method…

    # admin can do everything
    if user.login_name == 'admin'
        return true
    end

this is the Rights model…

class Right < ActiveRecord::Base
has_and_belongs_to_many :roles
validates_presence_of :controller, :action, :name
validates_uniqueness_of :name

# Ensure that the table has one entry for each controller/action 

pair
def self.synchronize_with_controllers
# weird hack. otherwise ActiveRecord has no idea about the
superclass of any
# ActionController stuff…
require RAILS_ROOT + “/app/controllers/application”

    # Load all the controller files
    controller_files = Dir[RAILS_ROOT + 

“/app/controllers/**/*_controller.rb”]

    # we need to load all the controllers...
    controller_files.each do |file_name|
        require file_name #if /_controller.rb$/ =~ file_name
    end


    # Find the actions in each of the controllers, and add them to 

the database
subclasses_of(ApplicationController).each do |controller|
controller.public_instance_methods(false).each do |action|
next if action =~
/return_to_main|component_update|component/
if
find_all_by_controller_and_action(controller.controller_path,
action).empty?
self.new(:name => “#{controller}.#{action}”,
:controller =>
controller.controller_path, :action => action).save!
logger.info “added: #{controller} -
#{controller.controller_path},
#{action}”
end
end
end
end
end


#3

I thinks thats far more complicated that what im trying to do, i have
this data:

users id username
15 ana

roles_users role user_id
2 15

roles id name
2 moderator

rights_roles right_id role_id
2 2

rights id name controller action
2 see dashboard dashboard list

so it gives permission to the user ana to see the dashboard and its list
action, but when i try to login i get “You are not authorized to view
the page you requested” and shows again the login form.

Note: if i take of the check_authorization action from the controller
the authentication works perfect.

Here is my code:

#admin_controller--------where auth takes place
class Admin::AdminController < ApplicationController
before_filter :check_authentication, :check_authorization,
:except => [:signin_form, :signin]

layout ‘admin/login_form’
def index
redirect_to :controller => ‘dashboard’
end
def check_authentication
unless session[:user]
flash[:notice] = “caminaste”
redirect_to :controller => “admin”, :action => “signin_form”
end
end

def check_authorization
user = session[:user].id
unless user.roles.detect{|role|
role.rights.detect{|right|
right.action == action_name && right.controller ==
controller_name
}
}
flash[:notice] = “You are not authorized to view the page you
requested”
request.env[“HTTP_REFERER”] ? (redirect_to :back) : (redirect_to
:controller => ‘dashboard’)

return false
end

end

hope im a little more clear :frowning:


#4

Without knowing what url you are trying to access I can take a guess.

The only controller/action that will not give this error is
dashboard/list

Even dashboard/index will give the error, so maybe you are trying to
access the index in
which case it needs to be added as a right too.

Remember that every method that can be called in a controller needs to
have a right
associated with it, and the role needs to be associated with each right
it my need to
access.

But just to be a little clearer what url are you trying to access, and
maybe an excerpt
from the server log would help.


#5

Ana B. wrote:

i get “You are not authorized to view
the page you requested” and shows again the login form.

Note: if i take of the check_authorization action from the controller
the authentication works perfect.

I had the same problem with that recipe, never solved it so used this
tutorial instead.

http://d-haven.org/modules/news/article.php?storyid=28

Seems to work to some degree but not as good as the recipe would have
been if I could have made it work.


#6

I have also started to work with this role based implementation, but
when I try to have a check_authorization,

def check_authorization
unless user.roles.detect{|role|
role.rights.detect{|right|
right.action == action_name && right.controller ==

“adresse”
}
}
flash[:notice] = “failed”
request.env[“HTTP_REFERER”] ? (redirect_to :back) : (redirect_to
:action => “home”)
return false
end

I have this message

Mysql::Error: #42000You have an error in your SQL syntax; check the
manual that corresponds to your MySQL server version for the right
syntax to use near ‘right INNER JOIN right_role ON right.id =
right_role.right_id WHERE (right_role’ at line 1: SELECT * FROM right
INNER JOIN right_role ON right.id = right_role.right_id WHERE
(right_role.role_id = 1 )

And I am sure I have correctly entered the data in the tables and join
tables.

I wanted to know if it were the actions that caused trouble but it
actually fails when I just enter :

def check_authorization
user = User.find(session[:user])
user.roles.detect{|role|
role.rights.detect{|right|
}
}
end

Anyone has an idea of what I did wrong ?
Thanks for the reply


#7

i think it may have something to do with the fact that you’re using the
word ‘right’.
considering one can do left and right joins.
try renaming your model.

d.


#8

that is, rename your table name, this is a mysql thing.