[Rails] Re: Re: acl_system help is needed

Ezra Zygmuntowicz
Mon, 17 Jul 2006 22:16:11 -0000

On Jul 17, 2006, at 5:49 AM, Josh Kieschnick wrote:

>>
>> I think you have the right idea. You need to make sure that a user
>> has authenticated before you let the access_control filter run. So
>> only use access_control on actions in your controller that require
>> user login.  If one of your controller actions doesn''t need a
user to
>> log in to see , then it doesn''t need to perform access_control
>> either.
>>
>>
>> -Ezra
>
> thanks for the reply Ezra. for this particular controller, i need
> all of
> the pages to perform access control. all i have in it now is the code
> that is generated when you create a scaffold, plus this:
>
>   before_filter :authorize
>
>   access_control :DEFAULT => ''customer | csr'',
>                  :authorize => ''!guest''
>

This looks like a problem. the :authorize => ''!guest'' is
not needed.
I think your authorize method might be a slight misnomer as well. I
think you mean authenticate there instead. Authentication is the
process of making sure someone is who they say they are, ie user logs
in with password and is authenticated.  Then the access_control
performs authorization, which is what user roles are allowed to
access certain actions. So maybe change your authorize method to be
authenticate instead.

But all that aside, I don''t think you want to put access_control on
your authorize method. Since it is already a private method it cannot
be called from the web so it doesn''t need to be protected with
access_control.


> the authorize method is in my application.rb file and all it does is
> check to see if there is someone logged in and then sends the user to
> the login controller that i have set up.
>
> i had this in my controller:
>
>   def current_user
>     User.find_by_id(session[:user_id])
>   end
>
> but this was being executed before my authorize method so when the
> acl_system checks my current user, it returns nil. to at least keep
> the
> code from from giving errors i had to change my current_user method
> to:
>
>
>   def current_user
>     User.find_by_id(session[:user_id]) || User.new
>   end
>
> but even by doing that, my authorize method is not getting called and
> the user is not ever being sent to the login screen. if i go
> straight to
> the login screen and login, everything else works great.
>
> also, on a side note, i wanted to add the current user method to the
> base controller file but it''s not pulling up that way. is it
> required to
> have current_user in every single controller?


Ok I think I see what your issue is. You need to realize that to have
a before_filter halt the chain of before filters it needs to return
false. So we need to rewrite your before_filter method that checks if
a user is logged in. Also I think you need a slight change to your
current_user method to make it work a tad better. Lets try something
like this in the bottom of your application controller class:


protected
# I would change this to authenticate instead of authorize to avoid
confusion.
   def authorize
     unless @current_user = User.find_by_id(session[:user_id])
       session[:original_uri] = request.request_uri
       flash[:notice] = ''Please log in''
       redirect_to :controller => ''login''
       return false  # !! this is what was missing!
     end
   end

   def current_user
     @current_user ||= session[:user] ? User.find_by_id(session
[:user]) : nil
   end


Try setting these methods like I have shown and then use a before
filter to protect all actions that require a login. This will make
sure that if an action needs a logged in user that it will try to
authenticate, if it fails then it will redirect to the login action
and access_control will never be called. If the user is successful at
login in the current_user will be set and then access_control gets
called next to see if the user has permission to access the action in
question.

so in the controllers that require login:

before_filter :authorize  # or authenticate if you change the name.

access_control :DEFAULT => ''!guest'',
                  :test_csr => ''csr''


One thing to realize that might help make this all a bit more clear
for you is to realize that access_control sets up a before_filter
itself, thats how it works. So it must happen *after* the before
filter has run that logs the user in and sets current_user. If the
user login fails then the access_control is never run because the
user is redirected to the login screen.


Cheers-
-Ezra