What is the purpose of Rolify? - ruby-on-rails

Hi I'm using rolify and have just realized that I'm not actually taking advantage of it's full potential.
At present I am doing things in my controller like re-routing users if current_user.has_role? :whatever_role, and allowing users if they have whatever other role...
Someone asked a question on stackoverflow about rolify and when I got to trying to answer it, I realized that I'm doing it wrong.
Now, here is where my confusion starts... Inside of ability.rb I have:
user ||= User.new # guest user (not logged in)
if user.has_role? :consumer
can :manage, Review
else
can :read, Review
end
Now let's say I add the consumer role to a user:
x=User.last
x.add_role :consumer
# => #<Role id: 10, name: "consumer", resource_id: nil, resource_type: nil, created_at: "2013-04-18 23:00:46", updated_at: "2013-04-18 23:00:46">
Right, so the role is created. I can check this by doing:
x.has_role? :consumer
=> true
Now I would expect this to give management ability for reviews...
x.has_role? :consumer, Review
=> true
but not for other models... here I try products
x.has_role? :consumer, Product
=> true
Further, when I look at "resource roles querying" and try to query the applied roles for reviews I find no applied roles:
Review.first.applied_roles
=> []
Can someone please explain rolify to me. Thanks

My answer, garnishing the question from this reddit post:
Authentication is establishing a User is who they claim to be.
Authorization is establishing that a User can perform a given action, be it reading or writing, after they've established their identity.
Roles are just common patterns of authorization across users: this User can be authorized as such, that User can be authorized like this instead.
The ingredient you're missing here is Permissions: a relationship between an established Role and some controller action.
Roles themselves make no promises about what action a User can perform. And remember--authorization is all about actions. Roles generalize what kind of User you're dealing with. They exist to keep you from having to query every User for a giant laundry list of Permissions. They declare: this User is a Role! Of course they have Permission to do that!
There are many types of Permission. You can store them in a database if you want your sufficiently authorized Users to be able to edit them, along with your Roles if those too ought to be configurable. Or, if your User's Roles are sufficiently static, you can manage Permissions in advance with Ruby code:
When I want to have configurable Roles and Permissions, i.e. for a client application you're handing off to someone at completion of contract, I implement a User :has_many Roles and a Role :has_many Permissions with my own custom models, and then add a before_filter :authorize hook into my ApplicationController, and write an authorize method on it that knows how to martial these expectations, or render a 403 page for those people who insist upon manually entering urls to things they hope expose actions to things they oughtn't have access to.
When I want to just have configurable Roles, I use Ryan Bates' CanCan gem.
When I want to have predetermined Roles and Permissions, I use Rolify in conjunction with Nathan Long's Authority, to get delightfully flexible Class-based Permissions via Authorizer classes.
Both Roles and Permissions can be either class-based or instance-based, depending on your use-case. You can, say, with the abilities of rolify you've just discovered, decide that Users may only act as a Role in certain, instance-based circumstances. Or, general Roles of User may only be able to execute an action given the object they are trying to action is of a certain type.
To explore the permutation of these, assuming a blog application, following the formula
a User who is a/an Role class/instance can action a/an/all/any/that (class/instance) Permission:
Role class and Permission class:
A User who is an Admin can delete any Post.
Role class and Permission instance:
A User who is an Admin can edit all Posts that they approved to be published
This would be easier if published posts had an approved_by field pointing to a User id. (Use a state machine gem for this sort of situation.
Role instance and Permission class:
A User who is an Author of a Post can comment on any Post
Note that this sort of situation is rare, which is why there are no gems I've mentioned above to handle this situation, except for perhaps the ability to manage predetermined circumstances like Rolify and Authority in conjunction; or, if you must pass this decision on to your client, your own custom solution.
Role instance and Permission instance:
A User who is an Author of a Post can edit that Post.
TL;DR:
Rolify is just for roles: grouping Users by Permission: access to a controller action. You have yet to decide how you are going to manage Permissions.
I hope this helps your understanding of Rolify's position in the grand scheme of authentication and authorization!

Related

Rails 4 - Rolify with renewal date for role

I'm trying to setup roles in my rails app with Rolify.
I have a CRUD model setup for roles. I'm about to start exploring how certain users can assign scoped roles to other users.
Is there a way I can allow users who are permitted to assign roles, to specify a renewal date, by which they need to confirm that the user is continuing in that role?
At the moment, my roles table only has associations to resource and user, and a string attribute called :name (for the name of the role).
Can I add a boolean for true/false on whether the role has an expiry date, and if it does, when a renewal notice should be issued?
Is there a better way to go about this?
This can be good idea:
Create a table for roles and permission.
add a field has_expired in that table.
When you save permission set expiry date.
When user logins test expire date.
Then set has_expired to true
If you are using cancancan gem then in ability.rb model:
if user.role.has_expired?
cannot :manage, Role
end
Hope it helps

Cancan : User can see its backoffice show view

(Using rails 4, Cancan 1.6.10)
Hello all,
I have two UsersController: one for the front, the other under /backoffice for the back, and both are using the same User model.
I defined abilities for a "normal user" like this :
can(:manage, User) do |u|
u == user
end
whereas an admin user will be able to manage all users:
can :manage, User
I also have two "show" views, one in the front: /users/:id and one in the backoffice: /backoffice/users/:id
My problem is that a limited user can today see its profile through the backoffice URL, as he "can Manage this user". (And of course this is not acceptable)
I know this should not be too difficult to correct, but what solution would you use?
There seems to be a way to namespace the abilities. See the Wiki entry of the continued project CanCanCan here: https://github.com/CanCanCommunity/cancancan/wiki/Authorization-for-Namespaced-Controllers
What it basically does is override the Ability class to pass a namespace that is determined by the ApplicationController. The Ability class has two different rulesets depending on the namespace it is initialized with.

How to add a new role in Spree?

I currently have two roles in my system, the defaults, 'User' and 'Admin'.
I would like to add a new role called 'Supplier'.
At the moment the supplier role needs to be the same as a normal user. I have 'frontend' profile edit page. The only difference between the user and supplier is that the supplier has a few more fields they can fill out. I plan on permissioning these extra fields by checking their role against spree_has_role?('supplier')
So what's the best way of adding the role to the database (do I add this to an initializer)?
How do I then add permissions to this role to be the same as the 'user' role?
At some point I'll want to extend the permissions, but one thing at a time.
I can't find any clear guide that shows how to do any of this (or at least anything that's been updated in the last year or two). I appreciate if any one can help me out with some instructions / examples.
P.s. I'm using Spree 2.2 Stable with Devise Auth.
Regular users have not any particular permission as you can see into the ability model (https://github.com/spree/spree/blob/master/core/app/models/spree/ability.rb) . You can just create the role in the database from the console using:
Spree::Role.create(name: 'Supplier')
If you need to be sure you have this role in the database and you want to put it into an initializer be sure to check if the role is not yet been created. You can use something like:
Spree::Role.find_or_create_by_name('Supplier')
At this point you can just use in the profile edit view something like:
<% if #user.has_spree_role?('Supplier') %>
...
additional fields here
...
<% end %>

I want to implement group permissions in my rails app. What is the most efficient way?

I want to be able to allow my admin users to be able to control almost every action that their standard users on the account can do. When creating group permissions for them to manage, is it better to have a giant table with over one hundred rows of booleans, or is it better to store all the permissions in a hash stored in a text field on the database? Maybe only store the things they can't do? or the things they can do? (whichever list is most often smaller?)
Is there a standard approach to doing this in webapps?
Some examples of what I'd store:
can_delete_object?
can_edit_object?
can_create_object?
can_delete_minions_object?
can_delete_managers_object?
I really like the can_? syntax that can-can uses.
Can-can would be great if it were anything other than defining functions for doing things. Which I still might end up doing in addition to storing all these booleans.. because there are account level permissions that will override the group level permissions.
[edit] - clarified the code a bit
I think you should really check out CanCan again if there is any kind of grouping of permissions (ie group users into managers, minions... with similar permissions and just save that field to the db instead of a whole hash of abilities)
heres an example of what the Ability class might look like in your situation:
class Ability
include CanCan::Ability
def initialize(user)
# All registered users can edit their own objects
can :manage, [Object], :user_id => user.id
# Different roles
if user.moderator?
can :delete, [Object], :user_id => user.minion.id
elsif user.admin?
can :delete, [Object], :user_id => user.manager.id
end
end
end
Here is a nice list of Ruby authentication gems.
I've used CanCan and acl9 in depth, and have reviewed several of the others. I agree with the recommendation to use CanCan, but I also had decent success with the acl9 gem on a complex app requiring user, role, and group assigned rights management.
It depends on what the permissions are for exactly, perhaps something like CanCan is what you're after?
https://github.com/ryanb/cancan
Would you be able to describe a few of the permissions otherwise?

Dynamic roles and permissions system in Rails app

I need to create roles based permissions systems in my Rails app. I would be totally happy with CanCan, but the main problem - it has to be dynamic, so that Admin has to be able to assign permissions and to create new roles. The permissions can be simple controller/action restrictions, and can be data related, for example some users can edit only their own profiles, and some of them can edit the profiles of all the users in the particular group. And it would be really nice to allow Admin to create new permissions.
What I'm thinking about is to store in db a controller/action, and some data related restrictions (I'm really confused here about the way to define them). So could you please give me some advice, what would be the best way to organize permissions?
Any thoughts are much appreciated
If you like CanCan, then I think is best to use it. Here is a short tutorial about storing abilities in database so non-programmers can update them:
https://github.com/ryanb/cancan/wiki/Abilities-in-Database
If you really, really want to implement such system yourself. Depending on your needs, I will suggest for you to implement it as simple as possible.
In the case you need only users to have access to modules(certain controllers). You can do:
Store all users permissions in just like serialized fields -> http://apidock.com/rails/ActiveRecord/Base/serialize/class
class User
serialize :permissions, Array
def access_to?(module)
permissions.include? module.to_s
end
end
some check when setting this field would be nice.
Just make a check on top of every controller if the current user have access to this controller(section)
class ApplicationController
private
def self.require_access_to(module)
before_filter do |c|
unless c.send(:current_user).try :access_to?(module)
c.send :render_no_presmissions_page
end
end
end
end
class AdminNewsController
require_access_to :news
end
Of course this is just a start position, from where you can easily evolve.
[EDIT The link given by #RadoslavStankov is a better answer than this.]
You can do it with CanCan easily. Just make a model for permissions (which has_and_belongs_to_many :users), and in your Ability#initialize load the permissions appropriate to the user from the model and say that the user can do them. Then make appropriate user interface for administrating that model.
Something like this:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
user.permissions.each do |permission|
can permission.symbol, permission.scope
end
user.prohibitions.each do |permission|
cannot permission.symbol, permission.scope
end
end
end
where scope returned something like :all for nil scope, or Object.const_get(#scope_name) otherwise... Play with it. Anyway, it's doable.
More complex CanCan things are likely to be more complex (duh) - for example conditional permissions - but that would be a bitch to administer as well, so I think this should be enough for most applications.

Resources