How do you restrict access to a certain webpage? - ruby-on-rails

I am trying to allow access to the log-in/sign-up page for a admin user only from my computer or any other way that lets me only see the web page for an admin sing-up-log-in.
Or what do typical web applications do to restrict access to the public towards a certain web page? If there is a bets-practice way, I would like to implement that.
I currently have Devise installed.

You can use the authenticate_user! Devise helper, adding it as callback within the needed controller and specifying the methods you want to control.
For instance if you have a Post model, then adding the authenticate_user! in the PostController it'll ask the user to be logged to have access to the methods in that specific controller:
class PostsController < ApplicationController
before_action :authenticate_user!
If you want to restrict just some specific methods then you can play with only and/or except.
See: Devise will create some helpers to use inside your controllers
and views. To set up a controller with user authentication, just add
this before_action (assuming your devise model is 'User')
Devise - Controller filters and helpers
According to your comment then you can create a method in the ApplicationController in order to restrict all of your controllers and methods.
This way you can define an array of addresses, and if the remote_ip coming from the request is in the array then you give access, if isn't then perform any other action:
ApplicationController < ActionController::Base
before_action :protect
private
def protect
addresses = ['127.0.0.1', ...]
if addresses.include?(request.remote_ip)
# give access
else
# restrict access
end
end
end
But if you need something more sophisticated then you'd have to see on your Nginx or Apache, whatever you're using to deploy your project.

I normally restrict webpage access through controller methods. My recent use case was going to a webpage only when payment was successful but redirecting when it was not, if any body issued a get request for that page directly, it would result in 404.
In your case, there can be multiple option for setup.
You can use cookies to see users credentials using Action Dispatcher
Use Devise for users and then you can fix a certain role to a user through adding a new migration and assign roles yourself after registering or let them choose.
I will expect you followed Devise route. In the controller action check for current user's role.
If User Not signed in (using current_user == nil)
redirect to home page and then return
else
if
its admin you go ahead and use the success page as partial and let them see the page using `<%= render 'pages/mypage'%>` and use return to end
else
just redirect back to home page with a notice "Don't try this".
redirect_to root_path, notice: 'Don't try this' and then use
return to end
end
(Just for fun, to see how many times a user did this wrong action, you can also have a table which stores current_user and number_of_wrong_attempt, and store their email whenever they try to go that page without permission before redirect in controller. After that you can email them with a background rake task which checks for a certain false attempt threshold that: "Hey! Your registration is being removed because you are doing unprohibited actions")

Related

Pundit AuthorizationNotPerformedError/PolicyScopingNotPerformedError

I'm new with the Pundit gem and I'm stuck on something.
I try to show a list with multiple records but I always get the error AuthorizationNotPreformedError.
What do I do wrong?
Controller:
def planning
#plans = Order.all
authorize #plans
end
Policy:
def planning?
user.present?
end
Planning.html.haml
%h1 test
When I add this: after_action :verify_policy_scoped, :only => planning, if: verify_policy_scoped?
I get the PolicyScopingNotPerformedError.
From the README:
Pundit tracks whether you have called authorize anywhere in your controller action. Pundit also adds a method to your controllers called verify_authorized
...
Pundit also adds verify_policy_scoped to your controller. This will raise an exception similar to verify_authorized. However, it tracks if policy_scope is used instead of authorize.
You have mixed the two methods up. You've called authorize, but are checking whether policy_scope was called.
policy_scope is typically used for collections of record (such as your example, or more typically index actions), whereas authorize is typically used for individual records (such as show/edit/update/destroy actions).
In your case, however, what you've got currently doesn't necessarily warrant a policy at all - all you're checking is whether the user is signed in!
If you require a user to be signed in, but they are not, then your application should respond with a 401 error, not 403. You may do this with, for example, before_action :authorize in your controller. (It depends how you have implemented authorization -- see the documentation on whatever library you're using, e.g. devise).

How to create a separate admin interface for blogs in rails

I need to create some routes for my blog website such that normal user can only read the posts and products. while super admin creates admins to moderate posts. How can i achieve that in rails?
I want
myapp.com/admin to bring me to log in page for admins.
Only super admin can manage moderators.
So far, I have a controller in 'app/controller/admin/home_controller'
which has index action for viewing all posts and users for admin.
Try adding a before filter before your action so that each time a admin try to hit that url he/she should get redirected to admin_login_url
before_filter :check_role
private
def check_role
unless current_user.role=='super_admin'
redirect_to admin_login_url
end
end
I am going to share what i actually did after reading tons of approaches just in case if anyone is stuck where i was. Hopefully helps:
Create a new controller in 'app/controllers/'. This controller is only responsible for GET requests.
Remove Create, Update, Delete methods from the controllers in 'app/controllers/', as these will be only accessible to admins.
Create a new admin_controller.rb in 'app/controllers/admin/'. Add authentications here.
Create new controllers(inherited from AdminsController) per model in the same directory and put the admin operations there.
class AdminPostsController < AdminsController

What are the best practices for authorization?

Situation: rails 3.2 app with a demo period, after which users must start paying for the service.
Question: If a user does not add a payment method, or does not choose a payment plan, what is the recommended way of restricting user access to the 'paid' part of the web app?
I need something that sorts users as follows:
if user.admin? || user.in_demo || user.has_all_payment_data
# carry on
elsif user.should_add_payment_method
# send them to add payment method page
elsif user.should_choose_plan
# send them to add plan
else
# redirect to home page or whatever
end
I've started off with a before_filter on the application controller that checks the payment status of the user on every request and redirects them accordingly (skipping this in places like the homepage/profile editing etc.), but I'm thinking there must be a better way, as it's rapidly getting too complicated and it just feels wrong having all that complexity in the application controller. I've been looking at user roles libraries like cancan but I can't find anything that fits.
There is a post by Jonas Nicklas (creator of Capybara and CarrierWave) in which he explains in some detail how to take a simpler approach than CanCan's. His approach is based on an additional plain Ruby class for each model you want to create authorization rules for.
Simple authorization in Ruby on Rails apps (Elabs blog)
They have offloaded that solution into a gem named Pundit, but it really seems simple enough to be able to implement from scratch.
Pundit gem (GitHub)
I would suggest a before_filter in the application controller, then using skip_filter in individual controllers to bypass it for actions that non-paid users can access, e.g:
class ApplicationController < ActionController::Base
before_filter :check_payment
...
end
class UserController < ApplicationController
skip_filter :check_payment, :only => [:login, :logout, ...]
...
end
This keeps the access contained to the relevant controllers, rather than needing an increasingly large :except => ... on the filter itself.

Redirect users by the tables that they belong to

I have two tables: workers_table and admins_table.
I have two controllers and I use devise (sign_in, sign_up...).
I use:
before_filter :authenticate_user!
in the controllers of workers and admins.
assume I have the email of the user that signed in:
#email = current_user.email
I want to check where #email is found:
if it's found in the workers table, so redirect him to the index.html.erb of workers (and he can't enter to index.html.erb of the admins).
if it's found in the admins table, so redirect him to the index.html.erb of admins (and he can't enter to index.html.erb of the workers).
I know how to check if the user belongs to workers_table or admins_table.
But where should I check which table the user belongs to? should I define another controller?
Please guide me.
application_controller.rb would be a good place to define the authenticate_user functionality
another place could be a sessions_controller.rb if you have it
at the very least you could have an ensure_admin method for your admins_controller to add to the before_filter, and if they are not an admine, you could redirect_to workers#index
I'm new to rails, so i'm unsure as to the conventional way to do this, but the above is how I might do it.

restful_authentication applied to only an action within a controller?

I have installed and implemented the plugin restful_authentication from technoweenie.
My application is, for the most part, intended to be open, except for the case of say, writing a review.
So I have a reviews_controller.rb, but the only time I want to care whether the user is logged in or not is when they are submitting a specific action add_review.
add_review is an action on the vendor_controller.rb because the form is displayed on vendors/show. Then it redirects back to vendor/show to show the update (thinking of changing this to ajax).
If the person is NOT logged in, I want it to redirect to the login/signup page.
The instructions for restful_authentication show applying the include AuthenticatedSystem at the controller level, but I don't want to be authenticating with other actions in that controller.
How do I do this?
Include the AuthenticatedSystem module in the controller you need it for (or ApplicationController if you need it for more than one), and then use the before_filter applied only to the actions you want, e.g.:
class VendorsController < ApplicationController
include AuthenticatedSystem
before_filter :login_required, :only => [:add_review]
end
I implore you to use the restful create action rather than your own add_review action. Read more about restful routing at: http://guides.rubyonrails.org/routing.html

Resources