Alternative for CanCan? [closed] - ruby-on-rails

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 7 years ago.
Improve this question
I use rspec, devise and cancan at the moment. To be honest, I find cancan to be very confusing and I am encountering a lot difficulties in picking it up and using it effectively. The docs are not very in depth making this extremely difficult for me to debug (check my past questions).
Is there an alternative to CanCan that's also easily integratable in the other tools I am using?

As of early 2014, Pundit is a popular alternative to CanCan (and the successor CanCanCan). Pundit matches each controller with a policy object. Unlike CanCan, there's no central rule file for all access control. It's simpler than CanCan. There's an example app from the RailsApps project:
Rails Pundit Example
I've also written a tutorial on Rails Authorization with Pundit.
Another alternative is the Authority gem from Nathan Long. All your rules logic goes in Ruby classes called "authorizers" that are associated with models.

Some guys are continuing the development of cancan. Check it out:
https://github.com/CanCanCommunity/cancancan

For the same reason i've done this: http://mcasimir.github.com/checkin/.
Checkin is an authorization gem that is independent from the role/authentication library you use.
You can express even complex rules rather simply with a declarative/cascading permissions DSL.
I found it very handy. The debug is also supported via the explain method that will log the authorization process on every request.
Here are some of the features:
Handy DSL to define roles and permissions with a declarative approach
Check authorization for CRUD operations automatically
Standard way to rescue from Authorization errors
Authorization subject decoupled from model (compatible with any autentication system)
Role-based authorization decoupled from role system (compatible with any role
system)
Decorator for current_user and other subject objects
Scoped authorization rules
Cascading authorization rules
Simple: even complex authorization behaviour is understandable at glimpse and
easily predictable
Support for controller based mass assignment protection
Here is a very simple example of the DSL:
class UserSubject < Checkin::Subject
role :guest, :alias => :anonymous do
!subject_model
end
role :logged_in, :alias => [:connected] do
!!subject_model
end
role :owner, :require => [:logged_in], :method => :own do |object|
object && ( object.respond_to?(:author) && ( subject_model == object.author ) ) || ( object.respond_to?(:owner) && ( subject_model == object.owner ) )
end
role :administrator, :require => :logged_in, :alias => :admin do
subject_model.has_role?(:administrator)
end
#
# Permissions
#
permissions :for => :comments do
allow :administrators
allow :logged_in, :to => [:create]
deny
end
# Admin
scope :admin do
permissions do
allow :administrators
allow :owners, :to => [:edit, :update]
deny
end
end
end
Checking roles and permissions:
subject = UserSubject.new(User.first, :scope => :admin)
subject.logged_in?
subject.guest?
subject.own?(Post.first)
subject.can_edit?(Post.first)
I apologize for being so wordy.

I found https://github.com/stffn/declarative_authorization to be rather complete. And it's logical to use.

Sounds like Pundit may be coming up strong. It has a less 'magic', more straightforward approach.
https://github.com/elabs/pundit

I am currently exploring Heimdallr. The one feature it has that most of these cancan alternatives don't are restricted scopes for index actions.

You also might want to check out this "ultra lite authorization library" - six

Check TheRole gem. very interesting alternative for cancan

I'd recommend Action Access, it's much simpler and straightforward, has seamless integration with Rails and it's very lightweight. It boils down to this:
class ArticlesController < ApplicationController
let :admin, :all
let :user, [:index, :show]
# ...
end
This will automatically lock the controller, allowing admins to access every action, users only to show or index articles and anyone else will be rejected and redirected with an alert.
If you need more control, you can use not_authorized! inside actions to check and reject access.
This makes controllers to be self contained, everything related to the controller is within the controller. This also makes it very modular and avoids leaving forgotten trash anywhere else when you refactor.
It's completely independent of the authentication system and it can work without User models or predefined roles. All you need is to set the clearance level for the current request:
class ApplicationController < ActionController::Base
def current_clearance_level
session[:role] || :guest
end
end
You may return whatever your app requires, like current_user.role for example.
It also bundles a set of handy model additions that allow to extend user models and do things like:
<% if current_user.can? :edit, :article %>
<%= link_to 'Edit article', edit_article_path(#article) %>
<% end %>
Here :article refers to ArticlesController, so the link will only be displayed if the current user is authorized to access the edit action in ArticlesController. It supports namespaces too.
It allows to lock controllers by default, customize the redirection path and the alert message, etc. Checkout the documentation for more.

There's also Consul.
You create a Power class with methods that return only those objects the user has access to, instead of loading objects and check permissions on them. Talk by the author.

Related

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.

Rails Authorization on Web Services

My rails app is pretty much a front-end to several web services. I persist my User model, and that's about it. I need to add authorization to my web app, using Devise for authentication. I've noticed CanCan and acl9 seem to work mostly on instances of ActiveRecord models. Would CanCan or acl9 still fit my needs? Any tips on using either of these libraries in my situation?
Should I look for something that works more on actions instead of instances?
Also, these are both Role based systems, and I'm thinking of using a permission based system. Would they still be a good fit?
I can't speak for acl9. However, the cancan wiki does claim that "It is easy to make your own [model] adapter if one is not provided." https://github.com/ryanb/cancan/wiki/Model-Adapter In other words, even though you're not using ActiveRecord, you might still be able to use cancan.
Then again, if you're not planning on having roles, your ability definitions in cancan might be a little redundant looking, eg.:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
can :create, Widget if user.has_permission(:create_widgets)
can :delete, Widget if user.has_permission(:delete_widgets)
can :herp, Derp if user.has_permission(:herp_derp)
end
end
It would be great if you could use cancan just for its controller action authorization methods, but I don't know if that's possible. Good luck.
Just to (finally :) answer for acl9.
Acl9 is composed of two very separate pieces, the Access Control Subsystem which is all the authorizing stuff you put in your controller, and the Role Subsystem which is setting/checking/removing roles from an authenticated user.
The only thing that the Access Control Subsystem ever calls is current_user.has_role?( role, obj=nil). So, the Role Subsystem has zero dependency on ActiveRecord, associations, database, etc. There is a helper (acts_as_authorization_subject) which adds an ActiveRecord-dependent has_role? method to a class, but that's entirely optional and you're free to implement your own has_role? method (which can also fallback to calling super to get the acl9 one) and implement your access checks however you please. So, you said that you do persist your user model, but let's say you want a role for your user to be the admin of a school, but that school is a web service call into some remote system.
## in your model
class User < ActiveRecord::Base
def has_role? role, obj=nil
role == :admin &&
obj == school &&
school[:admin] == id # <-- just making up how we know we're the admin of the remote school
end
end
def school
#school ||= School.get_by_user_id(id)
end
end
## in your controller
class SomeController < ApplicationController
before_action :set_school
access_control do
allow :admin, of: :school
end
private
def set_school
#school = School.get_by_id(params[:school_id])
end
end

Dynamic Role Authorization in Rails using a database. Declarative Authorization the best choice?

I will need to provide dynamic role assignments (Roles/ Privileges) .More clearly, an end user should be able to create a role, assign permissions to a new user. So I was thinking of storing roles and privileges in a table for each user.
Is there a smart way to do this (any other plugin?),or or should I write code to do this with Declarative Authorization . Some light would help.Thanks!
Try answering these to get closer to a solution:
Are the roles themselves dynamic? i.e. Can the privileges assigned various to roles can be changed through the web interface by an Admin? If yes, then you should be storing this information into your database. For a system like a blog, where roles are pre-defined eg. Admin, Guest and Moderator, Declarative Authorization works like a charm.
How strong is the coupling of permissions to the UI? (Sometimes it just a couple of places you need to restrict, in other cases, like a social network, permissions are a lot more complex and coupled tightly with the UI). If its very tightly coupled, i.e. one action is available to all sorts of roles but the actions these roles perform are limited by their definition, then Declarative Authorization (or the likes) won't help much, you need a legacy system.
I've used CanCan recently in a project and think it was pretty cool. You create an Ability class and use it to decide if the user 'can' perform the action... You could check for existence of permissions in a table in the method, or if their ruleset permits the action.
I took all of this sample code from the github readme:
class Ability
include CanCan::Ability
def initialize(user)
if user.admin?
can :manage, :all
else
can :read, :all
end
end
end
Then in your views and your controller you can check authorization levels
<% if can? :update, #article %>
<%= link_to "Edit", edit_article_path(#article) %>
<% end %>
def show
#article = Article.find(params[:id])
authorize! :read, #article
end
Cancan is great for simple/starting projects but you should definitely wrap it if you have a monolithic app. Cancan should be a early solution but not a final one. If your looking at policy objects (pundit) it might be a code smell you need to build your own authorization model. Authorization like integration varies client to client and if your looking for more dynamic solutions or you have too many roles to speak of, cancan is not for you. You may need a more data-driven security model. For example if you can grant someone else access to an entity.

The Rails Way - Namespaces

I have a question about how to do something "The Rails Way". With an application that has a public facing side and an admin interface what is the general consensus in the Rails community on how to do it?
Namespaces, subdomains or forego them altogether?
There's no real "Rails way" for admin interfaces, actually - you can find every possible solution in a number of applications. DHH has implied that he prefers namespaces (with HTTP Basic authentication), but that has remained a simple implication and not one of the official Rails Opinions.
That said, I've found good success with that approach lately (namespacing + HTTP Basic). It looks like this:
routes.rb:
map.namespace :admin do |admin|
admin.resources :users
admin.resources :posts
end
admin/users_controller.rb:
class Admin::UsersController < ApplicationController
before_filter :admin_required
# ...
end
application.rb
class ApplicationController < ActionController::Base
# ...
protected
def admin_required
authenticate_or_request_with_http_basic do |user_name, password|
user_name == 'admin' && password == 's3cr3t'
end if RAILS_ENV == 'production' || params[:admin_http]
end
end
The conditional on authenticate_or_request_with_http_basic triggers the HTTP Basic auth in production mode or when you append ?admin_http=true to any URL, so you can test it in your functional tests and by manually updating the URL as you browse your development site.
In some smaller applications I don't think you need to separate the admin interface. Just use the regular interface and add admin functionality for logged in users.
In bigger projects, I would go with a namespace. Using a subdomain doesn't feel right to me for some reason.
Thanks to everyone that answered my question. Looks like the consensus is to use namespaces if you want to as there is no DHH sponsored Rails Way approach. :)
Again, thanks all!
Its surely late for a reply, but i really needed an answer to this question: how to easily do admin areas?
Here is what can be used these days: Active Admin, with Ryan Bates's great intro.

Backend administration in Ruby on Rails

I'd like to build a real quick and dirty administrative backend for a Ruby on Rails application I have been attached to at the last minute. I've looked at activescaffold and streamlined and think they are both very attractive and they should be simple to get running, but I don't quite understand how to set up either one as a backend administration page. They seem designed to work like standard Ruby on Rails generators/scaffolds for creating visible front ends with model-view-controller-table name correspondence.
How do you create a admin_players interface when players is already in use and you want to avoid, as much as possible, affecting any of its related files?
The show, edit and index of the original resource are not usuable for the administrator.
I think namespaces is the solution to the problem you have here:
map.namespace :admin do |admin|
admin.resources :customers
end
Which will create routes admin_customers, new_admin_customers, etc.
Then inside the app/controller directory you can have an admin directory. Inside your admin directory, create an admin controller:
./script/generate rspec_controller admin/admin
class Admin::AdminController < ApplicationController
layout "admin"
before_filter :login_required
end
Then create an admin customers controller:
./script/generate rspec_controller admin/customers
And make this inhert from your ApplicationController:
class Admin::CustomersController < Admin::AdminController
This will look for views in app/views/admin/customers
and will expect a layout in app/views/layouts/admin.html.erb.
You can then use whichever plugin or code you like to actually do your administration, streamline, ActiveScaffold, whatever personally I like to use resourcecs_controller, as it saves you a lot of time if you use a REST style architecture, and forcing yourself down that route can save a lot of time elsewhere. Though if you inherited the application that's a moot point by now.
Do check out active_admin at https://github.com/gregbell/active_admin.
I have used Streamlined pretty extensively.
To get Streamline working you create your own controllers - so you can actually run it completely apart from the rest of your application, and you can even run it in a separate 'admin' folder and namespace that can be secured with .
Here is the Customers controller from a recent app:
class CustomersController < ApplicationController
layout 'streamlined'
acts_as_streamlined
Streamlined.ui_for(Customer) do
exporters :csv
new_submit_button :ajax => false
default_order_options :order => "created_at desc"
list_columns :name, :email, :mobile, :comments, :action_required_yes_no
end
end
Use https://github.com/sferik/rails_admin.

Resources