user policies

This commit is contained in:
Mark Moser 2016-09-20 14:22:20 -05:00
parent 12c7e9e77c
commit ead9564fe8
8 changed files with 160 additions and 2 deletions

View File

@ -2,14 +2,16 @@
module Admin module Admin
class UserController < AdminController class UserController < AdminController
def index def index
@users = User.order(:name) @users = policy_scope User.order(:name)
end end
def new def new
@user = User.new @user = User.new
authorize @user
end end
def create def create
authorize User
default_passwd = SecureRandom.urlsafe_base64(12) default_passwd = SecureRandom.urlsafe_base64(12)
@user = User.create({ password: default_passwd }.merge(user_params.to_h)) @user = User.create({ password: default_passwd }.merge(user_params.to_h))
@ -24,14 +26,17 @@ module Admin
def view def view
@user = User.find(params[:user_id]) @user = User.find(params[:user_id])
authorize @user
end end
def edit def edit
@user = User.find(params[:user_id]) @user = User.find(params[:user_id])
authorize @user
end end
def update def update
@user = User.find(params[:user_id]) @user = User.find(params[:user_id])
authorize @user
if @user.update_attributes(user_params) if @user.update_attributes(user_params)
redirect_to admin_user_path(@user.to_i), redirect_to admin_user_path(@user.to_i),

View File

@ -4,8 +4,12 @@ class AdminController < ApplicationController
layout 'admin' layout 'admin'
before_action :authorize_user before_action :authorize_user
# TODO: after_action :verify_authorized, except: :index
# TODO: after_action :verify_policy_scoped, only: :index
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
# TODO: move to DashboardController#index
def dashboard def dashboard
authorize :admin, :dashboard? authorize :admin, :dashboard?
@quizzes = Quiz.includes(:questions).all @quizzes = Quiz.includes(:questions).all
@ -25,6 +29,6 @@ class AdminController < ApplicationController
def user_not_authorized def user_not_authorized
flash[:error] = "You are not authorized to perform this action." flash[:error] = "You are not authorized to perform this action."
redirect_to(request.referer || root_path) redirect_to(request.referer || admin_login_path)
end end
end end

View File

@ -15,6 +15,12 @@ class User < ApplicationRecord
save save
end end
# TODO: move to mixin: UserRoles
# define remaining helpers
def admin?
role == 'admin'
end
private private
def gen_reset_token def gen_reset_token

View File

@ -0,0 +1,60 @@
# frozen_string_literal: true
class ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
raise Pundit::NotAuthorizedError, "Must be logged in." unless user
@user = user
@record = record
end
def index?
false
end
def show?
scope.where(id: record.id).exists?
end
def view?
show?
end
def create?
false
end
def new?
create?
end
def update?
false
end
def edit?
update?
end
def destroy?
false
end
def scope
Pundit.policy_scope!(user, record.class)
end
class Scope
attr_reader :user, :scope
def initialize(user, scope)
@user = user
@scope = scope
end
def resolve
# This is a closed system.
raise Pundit::NotAuthorizedError, "No access to resource."
end
end
end

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
class UserPolicy < ApplicationPolicy
def view?
user.admin? && show?
end
def create?
user.admin?
end
def update?
user.admin?
end
class Scope < Scope
def resolve
return scope if user.admin?
raise Pundit::NotAuthorizedError, "No access to resource."
end
end
end

View File

@ -0,0 +1,30 @@
# frozen_string_literal: true
require 'test_helper'
class ApplicationPolicyTest < PolicyAssertions::Test
# Verify default policies are most restrictive
test 'should require a user' do
assert_raise Pundit::NotAuthorizedError do
ApplicationPolicy.new(nil, User.new)
end
end
test 'should not allow collections' do
assert_raise Pundit::NotAuthorizedError do
ApplicationPolicy::Scope.new(users(:admin), User).resolve
end
end
test 'should not permit by default' do
admin = users(:admin)
refute ApplicationPolicy.new(admin, User.new).view?
refute ApplicationPolicy.new(admin, User.new).show?
refute ApplicationPolicy.new(admin, nil).index?
refute ApplicationPolicy.new(admin, nil).create?
refute ApplicationPolicy.new(admin, nil).new?
refute ApplicationPolicy.new(admin, nil).update?
refute ApplicationPolicy.new(admin, nil).edit?
refute ApplicationPolicy.new(admin, nil).destroy?
end
end

View File

@ -0,0 +1,31 @@
# frozen_string_literal: true
require 'test_helper'
class UserPolicyTest < PolicyAssertions::Test
test 'should allow admin to scope' do
scope = UserPolicy::Scope.new(users(:admin), User).resolve
assert_equal User.count, scope.count
end
test 'should not allow non_admin' do
assert_raise Pundit::NotAuthorizedError do
UserPolicy::Scope.new(users(:manager), User).resolve
end
end
test 'should require current_user' do
assert_raise Pundit::NotAuthorizedError do
UserPolicy.new(nil, User.first).view?
end
end
def test_view
refute_permit users(:manager), User.first
assert_permit users(:admin), User.first
end
def test_create_and_update
refute_permit users(:manager), User
assert_permit users(:admin), User
end
end

View File

@ -7,6 +7,7 @@ SimpleCov.start 'rails' do
add_group 'Models', %w(app/models app/validators) add_group 'Models', %w(app/models app/validators)
add_group 'Services & Workers', %w(app/workers app/services) add_group 'Services & Workers', %w(app/workers app/services)
add_group "Jobs", 'app/jobs' add_group "Jobs", 'app/jobs'
add_group "Policies", 'app/policies'
end end
require File.expand_path('../../config/environment', __FILE__) require File.expand_path('../../config/environment', __FILE__)