Forum: Ruby on Rails DoubleRender Question: who can answer?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Joe P. (Guest)
on 2007-04-03 21:37
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?
Zack C. (Guest)
on 2007-04-03 21:46
(Received via mailing list)
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
Lionel B. (Guest)
on 2007-04-03 21:51
(Received via mailing list)
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
Joe P. (Guest)
on 2007-04-03 22:39
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
Zack C. (Guest)
on 2007-04-04 00:09
(Received via mailing list)
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
Joe P. (Guest)
on 2007-04-04 00:30
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.
This topic is locked and can not be replied to.