Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Role Based Access Control #160

Closed
btbonval opened this issue Jul 23, 2013 · 11 comments
Closed

Role Based Access Control #160

btbonval opened this issue Jul 23, 2013 · 11 comments

Comments

@btbonval
Copy link
Collaborator

Find an implement a Rails-friendly RBAC system.

@btbonval
Copy link
Collaborator Author

Most of the info I'm finding for this is extremely outdated (e.g. stackoverflow answers from 2008). All references to the ActiveRBAC project are 2008 and earlier.

Here's an article from 2011 advising a combination of cancan and devise; it seems to support true RBAC but looks like an awful lot of steps and integration to get it working:
http://felixhanley.info/articles/rails-role-based-access-with-cancan/

Here's a railscast for cancan (2009):
http://railscasts.com/episodes/192-authorization-with-cancan?view=comments

CanCan on ohloh indicates it is still mildly developed:
http://www.ohloh.net/p/cancan

Devise appears to be more supported and active:
http://www.ohloh.net/p/devise

It's almost like Rails shuns standard web practices like RBAC >:-/

@jywarren
Copy link
Owner

Devise is fairly well-known in the railsverse; i think railscasts has
covered it a bit. So that might be the biggest bandwagon out there right
now. What are some RBAC solutions for other languages/frameworks -- we can
search for "blabla for Rails" to cast a wider net.

On Wed, Oct 16, 2013 at 1:51 PM, Bryan Bonvallet
notifications@github.comwrote:

Most of the info I'm finding for this is extremely outdated (e.g.
stackoverflow answers from 2008). All references to the ActiveRBAC project
are 2008 and earlier.

Here's an article from 2011 advising a combination of cancan and devise;
it seems to support true RBAC but looks like an awful lot of steps and
integration to get it working:
http://felixhanley.info/articles/rails-role-based-access-with-cancan/

Here's a railscast for cancan (2009):
http://railscasts.com/episodes/192-authorization-with-cancan?view=comments

CanCan on ohloh indicates it is still mildly developed:
http://www.ohloh.net/p/cancan

Devise appears to be more supported and active:
http://www.ohloh.net/p/devise

It's almost like Rails shuns standard web practices like RBAC >:-/


Reply to this email directly or view it on GitHubhttps://github.com//issues/160#issuecomment-26441489
.

@btbonval
Copy link
Collaborator Author

Most pythonic web platforms have RBAC support built in, so there isn't a
name for external RBAC moduless/gems/plugins.

Maybe Django has an RBAC plugin that might help cast that wider net. I feel
like "RBAC" should be a pretty wide net tho...
On Oct 16, 2013 2:16 PM, "Jeffrey Warren" notifications@github.com wrote:

Devise is fairly well-known in the railsverse; i think railscasts has
covered it a bit. So that might be the biggest bandwagon out there right
now. What are some RBAC solutions for other languages/frameworks -- we can
search for "blabla for Rails" to cast a wider net.

On Wed, Oct 16, 2013 at 1:51 PM, Bryan Bonvallet
notifications@github.comwrote:

Most of the info I'm finding for this is extremely outdated (e.g.
stackoverflow answers from 2008). All references to the ActiveRBAC
project
are 2008 and earlier.

Here's an article from 2011 advising a combination of cancan and devise;
it seems to support true RBAC but looks like an awful lot of steps and
integration to get it working:
http://felixhanley.info/articles/rails-role-based-access-with-cancan/

Here's a railscast for cancan (2009):

http://railscasts.com/episodes/192-authorization-with-cancan?view=comments

CanCan on ohloh indicates it is still mildly developed:
http://www.ohloh.net/p/cancan

Devise appears to be more supported and active:
http://www.ohloh.net/p/devise

It's almost like Rails shuns standard web practices like RBAC >:-/


Reply to this email directly or view it on GitHub<
https://github.com/jywarren/plots2/issues/160#issuecomment-26441489>
.


Reply to this email directly or view it on GitHubhttps://github.com//issues/160#issuecomment-26443354
.

@btbonval
Copy link
Collaborator Author

Since the system is not written in a resource-centric way (although CRUD is theoretically supported for resources routes), RBAC might be difficult to shoe-horn in even if there is found to be a useful Ruby gem.

It might be faster and easier to design the permission system by hand. First cut:

Role Table: id, name

UserRole Table: user_id, role_id

Summary:

Instead of permissions, implement minimum required role. Minimum required role should be defined in its own Controller or in a Helper. Minimum required roles are embedded directly into Controller functions and/or possibly mapped using routes.rb.

Details:

Since there are no decorators in Ruby, it might be painstaking to write clear, explicit permissions checks into each Controller function. ApplicationController would need to implement something fancy to inherit the Minimum Required Role capability throughout all the Controllers to ease burden. Then each Controller itself might have a default minimum required role (e.g. AdminController has an 'admin' minimum requirement, which would mean we want to break Moderator-based controls into ModeratorController). Functions would then need a way to override the minimum required role (to elevate or reduce required level).

Instead of writing, within a function, "if this permission, do this code, else do that code", it might be possible to redirect functions from routes.rb based on role. Hard to say how doable this is. The current routes.rb file does not really follow standards laid out in this link:
http://guides.rubyonrails.org/routing.html

@btbonval
Copy link
Collaborator Author

The more I think about it, the less I like using routes.rb.

The minimum required role needs to have some action to perform if the minimum is not met. This would probably end up forwarding to some other action. By default, this would be a 304 Unauthorized (or, since we don't use proper HTTP responses, forward to / with a flash[] message). But it could be overridden on a per-function basis.

This would allow fine-grained action-controls. Example:

class SpamController << ApplicationController
  minreq UserRole.verified # shortcut for UserRole.find_by_name('verified')

  def spam
    # require at least moderator for code herein
    minreq UserRole.moderator, :fallback => spam_verified
    # ... usual code ... maybe it deletes spam
  end

  def spam_verified
    # require at least verified for code herein. the following line would be redundant based on the Controller's minreq.
    minreq UserRole.verified # default :fallback is front page with a notice "you can't do that"
    # ... usual code ... maybe it marks the spam for moderators/admin to review
  end

@jywarren
Copy link
Owner

You can define filter functions to be run before each controller method on
a whitelist/blacklist basis:
https://github.com/jywarren/spectral-workbench/blob/master/webserver/app/controllers/spectrums_controller.rb#L3

On Wed, Nov 13, 2013 at 12:57 PM, Bryan Bonvallet
notifications@github.comwrote:

Since the system is not written in a resource-centric way (although CRUD
is theoretically supported for resources routes), RBAC might be difficult
to shoe-horn in even if there is found to be a useful Ruby gem.

It might be faster and easier to design the permission system by hand.
First cut:

Role Table: id, name

UserRole Table; user_id, role_id

Summary:

Instead of permissions, implement minimum required role. Minimum required
role should be defined in its own Controller or in a Helper. Minimum
required roles are embedded directly into Controller functions and/or
possibly mapped using routes.rb.

Details:

Since there are no decorators in Ruby, it might be painstaking to write
clear, explicit permissions checks into each Controller function.
ApplicationController would need to implement something fancy to inherit
the Minimum Required Role capability throughout all the Controllers to ease
burden. Then each Controller itself might have a default minimum required
role (e.g. AdminController has an 'admin' minimum requirement, which would
mean we want to break Moderator-based controls into ModeratorController).
Functions would then need a way to override the minimum required role (to
elevate or reduce required level).

Instead of writing, within a function, "if this permission, do this code,
else do that code", it might be possible to redirect functions from
routes.rb based on role. Hard to say how doable this is. The current
routes.rb file does not really follow standards laid out in this link:
http://guides.rubyonrails.org/routing.html


Reply to this email directly or view it on GitHubhttps://github.com//issues/160#issuecomment-28417596
.

@btbonval
Copy link
Collaborator Author

Filter functions are probably the better way to work this than the example I wrote.

Define a filter function that applies minimum required role filtering to all functions in the controller, then override it specifically at the top of the controller where needed.

I like things that modify code to be close to where the original code is, but maybe it isn't as easy. The pasted link shows a bunch of functions being modified at the top of the file. If one were to look at some particular function definition, one could easily miss the filter function at the top that is also relevant to the definition being reviewed.

@btbonval
Copy link
Collaborator Author

@btbonval
Copy link
Collaborator Author

Unsure sure how to specify parameters to the filter given the Rails syntax for overriding the fallback action.

There'd need to be require_basic, require_verified, require_moderator, and require_admin functions defined in ApplicationController, with no ability to dynamically override the default fallback location. If params could be passed, then require_role could be a single filter which takes parameters of minimum role and fallback.

@btbonval
Copy link
Collaborator Author

The second way is to use a class (actually, any object that responds to the right methods will do) to handle the filtering.

Assuming the current user info can be snatched from the controller, this creates an object which takes parameters and then passes that into before_action:

class ApplicationController < ActionController::Base
  before_action RequireRole.new('admin') :only => [:some_action]
  before_action RequireRole.new('moderator', some_fallback_action)
end

class RequireRole
  def initialize(role, fallback)
    @role = role
    if fallback !== undefined
      @fallback = fallback
    else
      @fallback = some_action_with_warning_and_redirect
  end
  def filter(controller)
     # extract current user from controller?
     # run the "at least" logic against @role and possibly run action @fallback
  end
end

There's got to be a better way. This looks horrific.

@btbonval
Copy link
Collaborator Author

So this ticket was a lot of exploration with very little climactic discovery. Basically I was looking for a system to implement and support roles, not just user permissions or group permissions. My searches turned up nothing.

At this point, if you can find a gem that supports users belonging to groups, and either or both users and groups being allowed access to this table or that element id, it's a win.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants