Comparison of different access controls
-
Upload
rashmi-nair -
Category
Technology
-
view
295 -
download
0
description
Transcript of Comparison of different access controls
Comparison of Different Access Controls in Rails
By Rashmi Nair
About Me
I am Team Lead at Icicle Technologies.
I am working in ROR for past 5 years.
On twitter you can find me - @rashmignair
Authentication
❏ Allowing users to sign in and identify themselves is called authentication(Identifies a user)
eg: same as you need to swap in order to enter your office. ❏ It can be implemented using Devise or Omniauth
❏ It a flexible authentication solution for Rails based on Warden.
❏ Its encrypts and stores a password in the database to validate the authenticity of a user while signing in.
Authorization
❏ Controls what a user is allowed to do.
❏ Once a user logins, need to check what the user is allowed to access and perform.
❏ These checks are on the basis of different roles mentioned in the application and the functions that the role can perform
Role-Based Authorization
❏ Role-based authorization is suitable for simple applications without complex access rules.
❏ A big advantage is easy conceptualization; it is easy to imagine personas, each with different (but uniform) privileges.
Implementing Role-Based Authorization
❏ Implement using CanCan (cancancan)
❏ Implement using Pundit
Implement using CanCan
❏ Simple and powerful
❏ Authorization library for Ruby on Rails
❏ All permissions are defined in a single location (the Ability class)
Implementation
❏ Add gem to your Gemfile and run the bundle command. >> gem "cancan"
❏ Define Abilities
>> rails g cancan:ability
app/models/ability.rb
class Ability include CanCan::Ability
def initialize(user) endend
Advantage
❏ Check Abilities & Authorization
❏ Handle Unauthorized Access
❏ Manage authorization in a single file
Disadvantage
❏ Ability files quickly become too big to manage, and there is no built in strategy for splitting up abilities across multiple files.
Disadvantage
❏ Even worse, there is no natural way to structure ability files. We usually resort to comments to divide the file into sections for different models.
❏ All ability rules need to be evaluated for every request. While not a huge performance hit, it seems like a built in wastefulness.
❏ The test suite depends on ActiveRecord < 3.1
Implement using Pundit
❏ It provides a set of helpers which guide you in leveraging regular Ruby classes and object oriented design patterns.
❏ It helps to build a simple, robust and scalable authorization system.
Installation
❏ gem "pundit"
❏ Add the following in Application controller
class ApplicationController < ActionController::Base
include Pundit
protect_from_forgeryend
❏ rails g pundit:install
❏ It focusses on Policies
❏ Mention the policies to be followed for the model in a class which has the same name as the model followed by policy for eg: TaskPolicy
class TaskPolicy < ApplicationPolicy def initialize(user, task) @user = user @task = task end
def create? user.role?(:project_manager) || user.role?(:team_lead) end
def update? user.role?(:project_manager) || user.role?(:team_lead) || user.id == @task.user_id end
end
class TasksController < ApplicationController
def index @tasks = policy_scope(Task) end
def create @task = Task.new(params[:task]) authorize @task, :create? @task.save redirect_to @task end
def show @task = Task.where(params[:id]) authorize @task, :show? end
end
Implementing Scopes
❏ Define a class called a policy scope
❏ The class has the name Scope and is nested under the Policy class
❏ Instances of this class respond to the method resolve, which should return some kind of result which can be iterated over.
class TaskPolicy < ApplicationPolicy class Scope attr_reader :user, :scope
def initialize(user, scope) @user = user @scope = scope end
def resolve if user.role?(:project_manager) scope.all else scope.where(:published => true) end end end
def update? user.role?(:project_manager) || user.role?(:team_lead) || user.id == scope.user_id endend
Advantage
❏ segregating access rules into a central location.❏ policy objects are lightweight❏ keeps your authorization logic out of controllers and models.
Disadvantage❏ Passing new parameter to the policy_scoped method is difficult
Use Case
❏ Considering an example for a system, with the following roles - Project Manager, Team Lead, Team Members
❏ Rules to be defined are as follows:1. Project Manager can do everything(Creating Milestone, Adding
Tasks, Add Members to Project)2. Team Lead(Add Task, Update Task, Delete Task )3. Members(Can only view all the task, but can update only the task
assigned to them)
Project Manager
class Ability include CanCan::Ability
def initialize(user) # Define abilities for the passed in user here. For example: if user.role?(:project_manager) can :manage, :all else ……. end end end
class TaskPolicy < ApplicationPolicy class Scope end def create? user.role?(:project_manager) end def update? user.role?(:project_manager) endend
Team Lead
class Ability include CanCan::Ability
def initialize(user) # Define abilities for the passed in user here. For example: if user.role?(:project_manager) can :manage, :all else can :read, :all if user.role?(:team_lead) can :update, Task can :delete, Task end end end end
class TaskPolicy < ApplicationPolicy class Scope end def create? user.role?(:project_manager) || user.role?(:team_lead) end def update? user.role?(:project_manager) || user.role?(:team_lead) endend
Team Member
class Ability include CanCan::Ability
def initialize(user) if user.role?(:project_manager) can :manage, :all else can :read, :all can :update, Task do |task| task.try(:user) == user || user.role?(:team_lead) end if user.role?(:team_lead) can :delete, Task end end endend
class TaskPolicy < ApplicationPolicy def initialize(current_user, model) @user = current_user @task = model end def create? user.role?(:project_manager) || user.role?(:team_lead) end def update? user.role?(:project_manager) || user.role?(:team_lead) || @user == @task.user endend
View File (Cancan)
views/tasks/index.html.erb
<% if can? :create, Task -%> <%= link_to 'Add Task', new_task_path -%><% end -%>
<% @task.each do |task| -%> <p> Task Name: <% @task.task_name -%></p> <p><%= link_to 'Show', task_path(@task) %></p>end
<% if policy(@task).show? %> <%= link_to 'Task', task_path(@task) %><% end %>
<% policy_scope(@user.tasks).each do |task| %> <li> <h2><%= task.task_name %></h2> <p><%= link_to "Edit", [:edit, task] if policy(task).edit? %></p> </li><% end %>
View File (Pundit)
Comparison
Cancan
❏ simple approach is to isolate all authorization logic into a single Ability class.
❏ single user role
Pundit
❏ provides a set of helpers to build your own authorization system using plain Ruby classes.
❏ supports complex
application with multiple roles
CanCan Pundit ❏ drawback is that all abilities
for that user’s role needs to be evaluated for each request
❏ Become difficult to use when there are complex roles
❏ No support for Rails 4
❏ only evaluates the ability for the requested resource’s action
❏ can be leveraged in building your own authorization system that meets your project’s needs
❏ Has support for Rails 4
References
http://www.elabs.se/blog/52-simple-authorization-in-ruby-on-rails-apps
https://github.com/elabs/pundit
http://www.distilnetworks.com/cancan-vs-pundit-choose-pundit-authorization/
Thank You