DoubleRender Question: who can answer?


#1

Hello.

In my application controller, I have a function like this:

def is_owner_or_admin(user_id)
if cur_user.role != “Admin” && cur_user.id != Integer(user_id)
flash[:error] = “Access denied”
redirect_to(:controller => :users, :action => :account) and return
false
end
end

I call it in my users controller like so:
def show
is_owner_or_admin(params[:id])
@user = User.find_by_id(params[:id])
unless @user
flash[:error] = “User not found”
redirect_to :action => :account
end
end

If @user ends up being nil, however, then I get a DoubleRender error.
My question is, what can I put in “is_owner_or_admin” that will redirect
and not complete the “show” action?


#2

Joe,

You want to call this method as a before_filter. Then returning false
will stop further request processing.

before_filter :is_owner_or_admin

You’ll also need to pull out the param user_id and just locate this
within the method as you can’t pass params to filters.


Zack C.
http://depixelate.com


#3

Joe P. wrote the following on 03.04.2007 19:37 :

end

If @user ends up being nil, however, then I get a DoubleRender error.
My question is, what can I put in “is_owner_or_admin” that will redirect
and not complete the “show” action?

I ended with throwing a SecurityError instead of redirecting, makes it
more DRY: I catch the exception and do what I want with it.

In your ApplicationController :

# 1/ save the original exception handling
alias_method :rescue_action_without_security_error, :rescue_action

# 2/ handle the SecurityError case
def rescue_action(exception)
    return rescue_action_without_security_error(exception) unless

exception.is_a?(SecurityError)
log_url_hacking(exception)
reset_session
render :file => “#{RAILS_ROOT}/public/403.html”, :status => 403
end

My personal choice has demonstrated above is to:

  • log the hacking attempt,
  • destroy the session,
  • render a default 403 page with the corresponding HTTP Response code.

Lionel


#4

Zack C. wrote:

Joe,

You want to call this method as a before_filter. Then returning false
will stop further request processing.

before_filter :is_owner_or_admin

You’ll also need to pull out the param user_id and just locate this
within the method as you can’t pass params to filters.


Zack C.
http://depixelate.com

Zack,

How could I check the user_id if I can’t pass in params to the filter?
That’s basically what I am checking.

Joe


#5

Joe,

There is actually a lot wrong here. First of all you can never trust
params with anything as important as access control. What happens
when a user passes in param[:id] equal to an admins? They have admin
access under your code. You need to do some sort of user
authentication, store the user_id in the session and then check that
in your code. Example:

application.rb


def current_user
@current_user ||= (session[:user_id] ? User.find(session[:user_id]) :
nil)
end
helper_method :current_user

private

def authenticate
redirect_to(login_url) and return false unless current_user
end

So now you can write the authorization check as a before_filter:

def is_owner_or_admin
if current_user.role != “Admin” || [ownership check here]
flash[:error] = “Access denied”
redirect_to(:controller => :users, :action => :account) and return
false
end
end


Zack C.
http://depixelate.com


#6

Zack C. wrote:

Joe,

There is actually a lot wrong here. First of all you can never trust
params with anything as important as access control. What happens
when a user passes in param[:id] equal to an admins? They have admin
access under your code. You need to do some sort of user
authentication, store the user_id in the session and then check that
in your code. Example:

application.rb


def current_user
@current_user ||= (session[:user_id] ? User.find(session[:user_id]) :
nil)
end
helper_method :current_user

private

def authenticate
redirect_to(login_url) and return false unless current_user
end

So now you can write the authorization check as a before_filter:

def is_owner_or_admin
if current_user.role != “Admin” || [ownership check here]
flash[:error] = “Access denied”
redirect_to(:controller => :users, :action => :account) and return
false
end
end


Zack C.
http://depixelate.com
def is_owner_or_admin(user_id)
if cur_user.role != “Admin” && cur_user.id != Integer(user_id)
flash[:error] = “Access denied”
redirect_to(:controller => :users, :action => :account) and return
false
end
end

Actually, “cur_user” returns the current user based on session data
already, so whatever user_id they pass in, it won’t affect their access.