role based route authentication - devise

I have been using devise and cancancan for authentication and authorisation resp., resque for background jobs. I have been following Ryans screencast number 271 and saw below code snippet for routes.rb file.
authenticate :admin do
mount Resque::Server, :at => "/resque"
end
to authenticated user, but in my case I have only users table and admin is also users separated by role column, Now I would like to authenticate and authorise the route for resque server path based on users role, How can I achieve solution for this problem ?
authenticate :user do
mount Resque::Server, :at => "/resque"
end
works fine for logged in user but i want it to be accessible only to admin user. Any help will be heartly appreciated.

# config/initializers/admin.rb
class CanAccessResque
def self.matches?(request)
current_user = request.env['warden'].user
return false if current_user.blank?
Ability.new(current_user).can? :manage, Resque
end
end
# routes.rb
namespace :admin do
constraints CanAccessResque do
mount Resque::Server, at: 'resque'
end
end
# ability.rb
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
if user.is_admin?
can :manage, Resque
end
end
end
# user.rb
class User < ActiveRecord::Base
def is_admin?
# your admin logic here for example:
self.role == "admin"
end
end
OR for more information, check this blog out: resque-admin-in-rails-routes-with-cancan
Hope this helps you.

Related

Rails Admin config.authorize_with redirect user if not admin

I have a Rails 3.2.x app using the rails_admin gem on the back end. I'm also using Devise for authentication and have a role field on the User model to say whether or not the user is an admin or employee.
What I'm trying to do is setup an authorization for rails_admin so if you visit http://domain.com/admin it will only allow it if the current_user.role == "admin" otherwise redirect to my home controller index path home_index_path
I've setup an initializer that should do this, and it does deny admin access if the role is not admin, but I get the following error: No route matches {:controller=>"home"}. I'm thinking it might have to do with the routes.rb and where I have the RailsAdmin line mounted in routes.rb but am not sure. Ultimately this should check the role to make sure it's equal to admin if not, redirect_to home_index_path and flash a message.
Any help is greatly appreciated.
rails_admin.rb
RailsAdmin.config do |config|
config.authorize_with do |controller|
unless current_user.role == 'admin'
flash[:error] = "You are not an admin"
redirect_to home_index_path
end
end
end
After some google searching I found an issue that addresses this. It looks like the namespace is different so redirecting to `main_app.root_path did the trick. I still cannot get the flash message to work. Any thoughts on this?
RailsAdmin.config do |config|
config.authorize_with do |controller|
unless current_user.role == 'admin'
redirect_to main_app.root_path
flash[:error] = "You are not an admin"
end
end
end

CanCan denies authorization when can :create is called

My CanCan implementation is denying access when I have called the can method with :create specified. Here is my ability implementation:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # User is not logged in (Guest)
if user.id == nil # Guest user
can [:create, :update], Device
else
if user.admin?
can :manage, :all
else
can :manage, Spot, :user_id => user.id
end
end
end
end
Basically I want non-authenticated users to be able to submit POST and PUT requests to the create and update actions of my Devices controller. However, when I try to submit a POST request the request is denied by CanCan (I'm asked to log in).
At the top of my devices controller I simply call load_and_authorize_resouce.
Does anyone see why CanCan would be raising an AccessDenied exception on this?

Rails 3 - Can Active_admin use an existing user model?

Can Active Admin use my current Devise user model? It already has a column named admin, and if it's true, I'd like to bypass the Active admin login, when going to /admin.
Is this possible?
Current routes:
#Active admin
ActiveAdmin.routes(self)
#Devise
devise_for :admin_users, ActiveAdmin::Devise.config
devise_for :users, :path => "account"
The rest is basically standard Devise + Active admin
Yes you can do that, when running the generator skip the user model creation:
rails generate active_admin:install --skip-users
Then in your config/initializers/active_admin.rb :
# == User Authentication
#
# Active Admin will automatically call an authentication
# method in a before filter of all controller actions to
# ensure that there is a currently logged in admin user.
#
# This setting changes the method which Active Admin calls
# within the controller.
config.authentication_method = :authenticate_admin!
uncomment config.authentication_method and provide your authentication method for your admin, for example:
# app/controllers/application_controller.rb
def authenticate_admin!
redirect_to new_user_session_path unless current_user.is_admin?
end
Restart your server and It should be working. Also Take a look to Active Admin Configuration
Hope this helps.
As stated earlier, you will need to update your config/initializers/active_admin.rb to reflect the correct auth method.
Additionally, however, you will want to update the following settings as well:
# This setting changes the method which Active Admin calls
# to return the currently logged in user.
config.current_user_method = :current_admin_user
to
config.current_user_method = :current_user
and
# This setting changes the path where the link points to. If it's
# a string, the strings is used as the path. If it's a Symbol, we
# will call the method to return the path.
#
# Default:
config.logout_link_path = :destroy_admin_user_session_path
to
config.logout_link_path = :destroy_user_session_path
Of course, you don't HAVE to update these (or the method mentioned in the post), and just over-ride the methods elsewhere, but this seems to be the easiest / cleanest approach. You will obviously need to substitute "user" in each setting (current_USER) with the name of the model using devise authentication.
I would also recommend updating the following setting as well while you are in there:
# This setting changes the http method used when rendering the
# link. For example :get, :delete, :put, etc..
#
# Default:
config.logout_link_method = :get
to
config.logout_link_method = :delete
This last change is required if the default HTTP method used by your devise config is set to :delete, which it is unless you changed it. It matters that they are now synced because if you follow these instructions, you will be using destroy_user_session_path which is a path already defined by devise. Otherwise you will get a message stating that [GET] /users/sign_out route does not exist.
Here's the process if you have already installed ActiveAdmin with default settings, and you want to authenticate users with User.is_admin field on your existing model, and remove admin_user table:
Rollback admin_user migrations (if you didn't use --skip-users when installing Active Admin):
rake db:migrate:down VERSION=20141205110842 # create_active_admin_comments.rb
rake db:migrate:down VERSION=20141205110831 # add_devise_to_admin_users.rb
rake db:migrate:down VERSION=20141205110820 # devise_create_admin_users.rb
Then remove those 3 files.
In routing, remove the line devise_for :admin_users, ActiveAdmin::Devise.config
In application_controller.rb, add:
def authenticate_admin!
if current_user && current_user.is_admin
# fine
else
redirect_to new_user_session_path
end
end
In active_admin.rb:
config.authentication_method = :authenticate_admin!
config.current_user_method = :current_user
config.logout_link_path = :destroy_user_session_path
config.allow_comments = false
config.logout_link_method = :get # couldn't get active_admin to sign out via :delete. So I configure devise to sign out via :get.
To configure devise to sign out via :get, add in devise.rb:
config.sign_out_via = :get
# And for every occurrence of destroy_user_session_path, remove the option method: delete.
Create is_admin migration:
rails g migration add_is_admin_to_user is_admin:boolean
Edit the migration like so:
class AddIsAdminToUser < ActiveRecord::Migration
def change
add_column :users, :is_admin, :boolean, default: false
end
end
And migrate:
rake db:migrate
If in rails 4, don't forget to add is_admin in permit_params. In app/admin/user.rb:
permit_params ....., :is_admin
Add rights to admin users, in a console:
u = User.find(42); u.is_admin = true; u.save
Enjoy
All of what everyone else has said as well as in conjunction with the guide laid out at
http://dan.doezema.com/2012/02/how-to-implement-a-single-user-model-with-rails-activeadmin-and-devise/
that adds some additional bits on information if you are choosing to revert back to the option to have a single user model when you have already implemented an admin_user model (ie right now you have a 'user' as well as an 'admin_user' model).
The additional steps included
remove devise_for :admin_users, ActiveAdmin::Devise.config from routes.rb
copy code from app/admin/admin_user.rb to app/admin/user.rb (only use what is required)
delete app/admin/admin_user.rb (or you will get an Uninitialized constant error on AdminUser) like this guy had (and me as well).

Active Admin Login slow

I'm using active admin in my rails 3.0.9 app with the default setup.i.e I have User model with devise authentication for customer login and Active Admin is running on AdminUser model. All Ok apart from the active admin login page. When I try to access http://localhost:3000/admin I get the active admin login page very quickly. But after I enter the username/password correctly/incorrectly the authentication process takes nearly 3-5 minutes. Because of this reason I can't even deploy the app on heroku, and I get timeout errors on heroku logs.
But how ever in development mode after I logged in to active admin, everything works perfectly. I'm assuming this is happening due an issue with routing. So I'm pasting my routes file here with fully.
http://pastie.org/3153643
Can some one help me on this please? Thanks
UPDATE 09-Jan: Its seems like the issue is not related to the routes I think. I removed all the other models/controllers/views/routes leaving only User and AdminUser stuffs. But I still experiencing the slowness.
Never mind I've found the issue and the probably the solution as well. I'm posting it here so it will help someone else with a similar issue.
In my application I was originally using authlogic gem for authentication but recently I've switched over this to devise for better support. But I still wanted to allow old users to login to the app with same passwords. So I've overridden the devise encryption from Bcrypt to Authlogic's sha512 as below.
config/initializers/devise.rb
config.encryptor = :authlogic_sha512
But I never change the AdminUser model to fit with the above change.
So the fix should be in my model I should use the :encryptable and :encryptor => :authlogic_sha512
class AdminUser < ActiveRecord::Base
devise :database_authenticatable,
:recoverable, :rememberable, :trackable, :validatable,:encryptable, `:encryptor => :authlogic_sha512`
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me
end
And in AdminUser migration file encryptable columns should be enabled
create_table(:admin_users) do |t|
t.database_authenticatable :null => false
t.recoverable
t.rememberable
t.trackable
t.encryptable
# t.confirmable
# t.lockable :lock_strategy => :failed_attempts, :unlock_strategy => :both
# t.token_authenticatable
t.timestamps
end

Devise (or OmniAuth) appending "#_" to URL after sign in

I'm using Devise and OmniAuth (Facebook) in a Rails 3 app. I just started noticing this behavior recently.
When a user signs in, he is redirected to his dashboard, however, the characters "#_" are being appended to the url. The only thing I can think of now is a conflict between the routes created by:
resources :users
and
# User Authentication
devise_for :users,
:singular => :user,
:controllers => {:registrations => 'registrations'} do
get 'logout' => 'devise/sessions#destroy'
end
Is this only happening with Facebook? If so it is probably related to: https://developers.facebook.com/blog/post/552/. Notice how Facebook outlines that they changed the session redirect handling to append a #_=_ to responses. I'm not sure why this was done, however you may be able to fix it by supplying an explicit redirect url.