CanCan Auth issue - ruby-on-rails

Good Afternoon All,
I am trying to sort out my user authentication and causing myself headaches.
I have a :role_type defined in User and my user has two roles, Employer or Developer, now I my user is currently developer and should be able to see jobs#index but it cannot and I get the default cancan message of unauthorized:
class JobsController < ApplicationController
load_and_authorize_resource
before_filter :authenticate_user!
before_action :set_job, only: [:show, :edit, :update, :destroy]
and here is the Ability.rb
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
can :create, :delete, :update, Job if user.role_type == "Employer"
can :read, Job if user.role_type == "Developer"
end
end
Thanks for the help.

As written in the comments: Make sure that you are not having a typo like "Employer" instead of "employer" :-)

I'm assuming the error occurs when the user.role_type == 'Employer'
Looking at your code it looks like the Employer is missing the :read action.
If Employer can manage all jobs (basic crud actions) you might want to consider giving him the :manage ability
Example:
can :manage, Job if user.role_type == "Employer"
can :read, Job if user.role_type == "Developer"
The :manage ability gives the user access to every action within the JobsController. See the following doc for clarification on the :manage ability: https://github.com/ryanb/cancan/wiki/defining-abilities#the-can-method
Otherwise you would need to add the :read action to Employer, as they are not a Developer and will not get the :read action

Related

Cancancan ActiveAdmin: skip authorization for :create

I'm using Cancancan for authorization in ActiveAdmin.
Everything work fine except the :create. When create a new admin, cancancan will check is admin_user.id = id. However, ActiveAdmin make id = nil, so I can't create a new admin.
include CanCan::Ability
def initialize(admin_user)
can :manage, AdminUser, id: admin_user.id
....
end
end
My solution is everyone can skip authorization for create.
My application controller:
class ApplicationController < ActionController::Base
load_and_authorize_resource
skip_authorize_resource :only => :new
end
but it does nothing. Please help!
You can specify what actions need authorization like this...
def initialize(admin_user)
can [:edit, :destroy], AdminUser, id: admin_user.id
end
Just replace/add to [:edit, :destroy] with whatever actions you need that authorization for.
If you want all admin users to be able to perform an action on AdminUser...
can :some_action, AdminUser

CanCan authorization issue index action

I am having an issue trying to use the cancan authorization. I have users with one role per user, so I added user.role column as suggested in the cancan wiki.
I also have an index view for kindergardens and another index view for children.
What I am trying to achieve is to only allow access to the index views to the corresponding users with role kindergarden or parent (for children).
When I now authorize Kindergardens in kindergardens controller nobody is allowed to access the index view, although I defined it in my ability model.
Help would be much appreciated. I have no idea what I am missing...
Ability model:
class Ability
include CanCan::Ability
def initialize(user)
[...]
elsif user.role == 'kindergarden'
can [:update, :destroy], Kiga do |kiga|
kiga.user_id == user.id
end
can :read, Kiga do |kiga|
kiga.user_id == user.id
end
can :index, Kiga
can :create, Kiga
else
end
Kindergardens controller:
class KigasController < ApplicationController
before_action :set_kiga, only: [:show, :edit, :update, :destroy]
# GET /kigas
# GET /kigas.json
def index
#kigas = Kiga.all
authorize! :index, #kiga
end
You define your abilities as blocks and that needs to have instances. In index actions you have only Active Record scopes, not actual instances.
Btw you have a typo in controller code:
def index
#kigas = Kiga.all
authorize! :index, #kigas # was #kiga that is nil probably
end
See the docs:
The block is only evaluated when an actual instance object is present. It is not evaluated when checking permissions on the class (such as in the index action).
In this case you can use hashes of conditions
can [:update, :destroy], Kiga, user_id: user.id
Got solution
def index
#kigas = Kiga.all
authorize! :index, Kinga
end

Rails controller and permissions for users

I'm stuck with a very simple Rails problem.
I have a blog controller which has these lines:
skip_before_action :check_admin, only: [:index, :show], raise: false
...
private
...
def check_admin
redirect_to(root_path) unless current_user && current_user.admin?
end
I want the behavior to be the following:
if a user is not logged in or is logged in and its role is not admin, and tries to access other actions rather than :index and :show, it should redirect to the root path.
But right now, it shows the user login page for every action when a user is not logged in, whereas it allows every action for any logged in user, even not admin ones.
I am using Devise and CanCanCan. My ability.rb looks like this:
def initialize(user)
can :read, :all # allow everyone to read everything
if user && user.admin?
can :access, :rails_admin # only allow admin users to access Rails Admin
can :dashboard # allow access to dashboard
can :manage, :all
end
end
Where am I failing?
EDIT: I changed the action call in the controller to this:
before_action :check_admin, except: [:index, :show]
Now, the desired behavior is showing for logged users, whereas for unlogged users it is still redirecting to the user login page for every action including index and show.
EDIT 2: I have before_action :authenticate_user! in application_controller.rb while some other controllers are set with skip_before_action :authenticate_user!, :only => [:index]. But this shouldn't interfer with the blog controller in my opinion...
Also, I have the following in config/initializers/rails_admin.rb:
RailsAdmin.config do |config|
### Popular gems integration
## == Devise ==
config.authenticate_with do
warden.authenticate! scope: :user
end
config.current_user_method(&:current_user)
The problem is you have before_action :authenticate_user! in your application controller. if you see your controller definition,:
class BlogController< ApplicationController
'<' operator means BlogController inherits from ApplicationController, therefore all your controllers (except those with skip_before_action) will require authentication.
you'll need
Class BlogController < ApplicationController
skip_before_action :authenticate_user!, :only => [:index, :show]

Is there any way to access the parent object in a Cancan nested resource ability?

I have a nested resource for which I'm using Cancan to do authorization. I need to be able to access the parent object in order to be able to authorize the :index action of the child (since no child instance is passed for an :index action).
# memberships_controller.rb
class MembershipsController < ApplicationController
...
load_and_authorize_resource :org
load_and_authorize_resource :membership, through: :org
..
end
ability.rb
can [:read, :write], Membership do |membership|
membership.org.has_member? user
end
This doesn't work for the :index action
Unfortunately the index action doesn't have any membership instance associated with it and so you can't work your way back up to check permissions.
In order to check the permissions, I need to interrogate the parent object (the org) and ask it whether the current user is a member e.g.
# ability.rb
...
can :index, Membership, org: { self.has_member? user }
Cancan almost lets me do this...
Cancan states that you can access the parent's attributes using the following mechanism:
https://github.com/ryanb/cancan/wiki/Nested-Resources#wiki-accessing-parent-in-ability
# in Ability
can :manage, Task, :project => { :user_id => user.id }
However this just works by comparing attributes which doesn't work for my case.
How can I access the parent object itself though?
Is there any way to access the parent object itself within the permissions?
I recently faced the same problem and ended up with the following (assuming you have Org model):
class MembershipsController < ApplicationController
before_action :set_org, only: [:index, :new, :create] # if shallow nesting is enabled (see link at the bottom)
before_action :authorize_org, only: :index
load_and_authorize_resource except: :index
# GET orgs/1/memberships
def index
#memberships = #org.memberships
end
# ...
private
def set_org
#org = Org.find(params[:org_id])
end
def authorize_org
authorize! :access_memberships, #org
end
end
ability.rb:
can :access_memberships, Org do |org|
org.has_member? user
end
Useful links
https://github.com/ryanb/cancan/issues/301
http://guides.rubyonrails.org/routing.html#shallow-nesting
Can't you do something like this?
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
can :index, Membership, org: {id: user.memberships.map(&:org_id)}
end
end

use cancan and devise in my application

I want to use cancan in order to limit the users that want to view some pages in my application.
so I try to do it by this tutorial:
http://www.roberthuberdeau.com/articles/9-Blog-tutorial-part-3
I have two roles: Admin and Worker, and I have two controllers: Tasksadmins and Workers.
I want to define the next thing:
1) Workers can manage and see all the things of the Workerscontroller.
2) Admins can manage and see all the things of the Tasksadminscontroller.
I'm not sure if I defined it correctly:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user
if user.role? :Admin
can :manage, :tasksadmins
elsif user.role? :Worker
can :manage, :workers
end
end
end
the next thing that I think I don't need to implement is: "the def initialize user bit is for guest users." I force the users to sign_in with: before_filter :authenticate_user
the next thing is: start restricting access to the blog application based on user role:
I don't know what and where I should write.
in the example, he wrote:
authorize! :edit, #article
so I tried to write the next followings in the tasksadmins controller:
authorize! :edit, #tasksadmins
authorize! :new, #tasksadmins
authorize! :index, #tasksadmins
authorize! :create, #tasksadmins
authorize! :show, #tasksadmins
authorize! :destroy, #tasksadmins
but I got an error: undefined method 'authorize!' for TasksadminsController:Class
please help me, I'm in the end of the definition of cancan.
This article is pretty dated, I would suggest looking at the CanCan docs on the github page, particularly this one. This looks like what you want to do but as shown in the doc, you do not have to authorize every action individually. Also, this should help with your second issue with devise. If you are specifying the version for devise like as shown in the article I would highly recommend upgrading your gems if possible. Good luck!

Resources