How to secure access to restricted pages using devise - ruby-on-rails

I want to restrict the access to some pages to only logged users.
Those pages have an attribute `area = restricted``
So in my controller i am restricting the access as following:
before_action find_page # Where we instantiate #page
before_action authenticate_user! only: [:show], :if => :restricted? , :unless => :logged_in?
and farther in the controller i have
def restricted?
#page.area == "restricted" ? true : false
end
def logged_in?
current_user ? true : false
end
But for some reason, it didn't work...
Do you see something obvious in the code ?
Thanks !
UPDATE:
I simplified the code above by mixing the 2 conditions into one method as following:
before_action find_page # Where we instantiate #page
before_action authenticate_user!, only: [:show], :if => :must_be_authenticated
And my method us defined as following
def must_be_authenticated
puts "must_be_athenticated call"
return false if #page.area != "restricted" # If the area is not restricted no need for athentication
return false if user_signed_in? # If user is signed_in no need for athentication
return true
end
The problem persists, and even the string "must_be_athenticated call" is not written in the log. So it seems that the before_action :authenticate_user!, :if => :must_be_authenticatedis just ignored since no print out in the log of the debug string, neither the page is restricted...
UPDATE:
The show method is defined as following:
def show
authorize! :show, #page
render template: "pages/show"
end

Related

How to use before_action with :unless and params

I have an authorization module that I built to authorize user actions. Everything is working great, except now I want to skip the action if the user requesting the page is the current user. The resource is nested below user so passes a :user_id as part of the params.
From what I've been able to find out, the simplest way to do this is to use a lambda, but it doesn't appear that I have access to the passed params from the before filter.
This is my controller
class Certifications::FitnessController < ApplicationController
prepend_before_action :authenticate_user!
before_action :authorize, unless: -> { params[:user_id] == current_user.id }
end
The problem is that the :authorize before_action is never called so all actions are allowed (I assume because the unless statement is always evaluating to true), but I can't examine what is going on because if I stop execution there, no params seem to be there (which I would think should make it always evaluate to false, not true).
If anyone can tell me either what I'm doing wrong or a better way to implement, I would really appreciate it.
EDIT: The code above actually works if you convert the params to an integer to match the current_user.id
before_action :authorize, unless: -> { params[:user_id].to_i == current_user.id }
before_action do |controller|
unless params[:user_id].to_i == current_user.id
controller.authorize
end
end
Alternatively you can do so like:-
before_action :authorize
def authorize
unless params[:user_id].to_i == current_user.id
#do your stuff..
end
end
2nd Alternative
before_action :authorize, unless: -> { params[:user_id].to_i == current_user.id }

how to make devise admin see everything?

I normally have everything scoped with current_user
eg:
#integrations = current_user.integrations.all
For trouble shooting, I want the admin to see everything for all users. I currently have a boolean on the user model that is admin: true
To get around the admin seeing everything, I keep doing this:
def index
if current_user.admin?
#integrations = Integration.all.includes(:user)
#reports = Report.all
else
#integrations = current_user.integrations
#reports = current_user.reports
end
end
I feel like there is an easier way... suggestions?
Thanks!
You could maybe abstract the admin check to a protected/private method in your User controller:
def is_admin
current_user.admin?
end
And then at the top of the controller, place a before action to catch whatever methods you want:
class UsersController < ApplicationController
before_action :is_admin, only: [:index, :show]
# rest of your code
end
OR
class UsersController < ApplicationController
before_action :is_admin, except: [:destroy]
# rest of your code
end
You could make a protected method in the application_controller.rb file. As stated above it will check to see if the current_user is and admin. Then you can use conditional statements to set privileges.
assuming that admin is a boolean value
def is_admin?
current_user.admin == true
end
In a view you can then say
if current_user.is_admin?
........
end

before_filter in application controller for only get requests

I need to set up a before_filter in my ApplicationController that redirects a user if they have not yet agreed to a new terms of service. However, I want to restrict the filter to only run based on the type of request.
I'd like to write something like this:
class ApplicationController
before_filter :filter, :only => {:method => :get}
Is something like this possible?
before_filter :do_if_get
private
def do_if_get
return unless request.get?
# your GET only stuff here.
end
Or more simply
before_filter :get_filter, if: Proc.new {|c| request.get? }
private
def get_filter
# your GET only stuff here.
end
Compliments to deefours answer, this also work with Sinatra::Request
before do
something if request.get?
end

require_owner code to limit controller actions not recognizing current user as owner [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
before_filter :require_owner
I am trying to restrict access to certain actions using a before_filter which seems easy enough. Somehow the ApplicationController is not recognizing that the current_user is the owner of the user edit action. When I take the filter off the controller correctly routes the current_user to their edit view information. Here is the code.
Link to call edit action from user controller (views/questions/index.html.erb):
<%= link_to "Edit Profile", edit_user_path(:current) %>
ApplicationController (I am only posting the code that I think is affecting this but can post the whole thing if needed).
class ApplicationController < ActionController::Base
def require_owner
obj = instance_variable_get("##{controller_name.singularize.camelize.underscore}") # LineItem becomes #line_item
return true if current_user_is_owner?(obj)
render_error_message("You must be the #{controller_name.singularize.camelize} owner to access this page", root_url)
return false
end
end
and the before_filter
class UsersController < ApplicationController
before_filter :require_owner, :only => [:edit, :update, :destroy]
#...
end
I simply get the rendering of the error message from the ApplicationController#require_owner action.
UPDATE: the link_to provides this address: localhost:3000/users/current/edit
Ok, this is the second bounty question that I have posted and then answered myself. Both times I have found the answer within an hour of my bounty post. Ha.
I simply changed the before filter method to get this to work. I left the application controller as it is in the code above but in the UsersController (the only one that wasn't cooperating) I did the following:
before_filter :require_user, :only => [:edit, :update, :destroy] # all actions require user to be logged in
before_filter :init_data # create a member variable called #post, initialized based on the action
before_filter :require_user_owner, :only => [:edit, :update, :destroy] #edit, update, and destroy actions require ownership
and then
private
def require_user_owner
obj = instance_variable_get("##{controller_name.singularize.camelize.underscore}") # LineItem becomes #line_item
return true if current_user.id == #user.id
render_error_message("You must be the #{controller_name.singularize.camelize} owner to access this page", root_url)
return false
end
That seemed to do it.
Seems to me that the current_user_is_owner?(obj) call have an issue. To prove it, modify the code to:
def require_owner
# LineItem becomes #line_item
obj = instance_variable_get("##{controller_name.singularize.camelize.underscore}")
if current_user_is_owner?(obj)
return true
else
render_error_message("You must be the #{controller_name.singularize.camelize} owner to access this page", root_url)
return false
end
end
You might want to paste the current_user_is_owner? method.
Hopefully it helps.

Ruby on Rails :before_filter => :only_when_user_is_logged_in

Using Ruby on Rails, I want to before filter an action but only when users are logged in.
How is this possible?
before_filter :only_when_user_is_logged_in, :only => :the_action
Or for multiple
before_filter :only_when_user_is_logged_in, :only => [:the_action, :another_action]
On the flip side, you can also provide an :except => :this_action option
I think you're asking how to run a before filter only if a user is logged in. There is no built-in semantic for this, but it's easy enough to inline:
class SomeController < ApplicationController
before_filter :do_something
def do_something
if logged_in?
# the stuff you want to do
end
end
end
Before filters take an optional block which is passed the current controller instance
so you could do something like this:
before_filter :do_stuff, lambda { |controller| controller.logged_in? }
If you really don't want the before_filter executing for anyone other than logged in users consider using #skip_before_filter in your authentication filter. For instance if when you're checking if users are logged in in your authentication filter, if authentication fails, merely call skip_before_filter :filter_for_logged_in_users_only.
Other than that you can simply test if the user is logged in before executing the member only filter. For example:
def filter_for_logged_in_users_only
return true unless current_user && logged_in?
#rest of the logic
end
If you're using restful authentication, it's just before_filter :login_required. If you are using your own authentication framework, you can create a method in application.rb that returns true if the user is logged in or redirects to the login page otherwise.
class LoginsController < ApplicationController
skip_before_filter :require_login, :only => [:new, :create]
end

Resources