2. 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
3. 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.
4. 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
5. 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.
7. Implement using CanCan
❏ Simple and powerful
❏ Authorization library for Ruby on Rails
❏ All permissions are defined in a single location (the Ability class)
8. Implementation
❏ Add gem to your Gemfile and run the bundle command.
>> gem "cancan"
❏ Define Abilities
>> rails g cancan:ability
10. 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.
11. 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
12. 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.
13. Installation
❏ gem "pundit"
❏ Add the following in Application controller
class ApplicationController < ActionController::Base
include Pundit
protect_from_forgeryend
14. ❏ 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
15. 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
16. 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
17. 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.
18. 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
end
end
19. 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
20. 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)
21. 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)
end
end
22. 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)
end
end
23. 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
end
end
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
end
end
24. 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
25. View File (Pundit)
<% 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 %>
26. 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
27. 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