Object oriented authorization for ruby. It provides helper to protect method call's via Policy-Classes.
Inspired by https://github.com/elabs/pundit, but without Rails and with a threat local storage for the current user or role.
Add this line to your application's Gemfile:
gem 'access_policy'
And then execute:
$ bundle
Or install it yourself as:
$ gem install access_policy
class ToGuard
def method_to_guard
end
end
ToGuardPolicy = Struct.new(:current_user_or_role, :object_of_kind_to_guard) do
attr_accessor :error_message # optional
def method_to_guard?
if current_user_or_role.is_allowed?
true
else
self.error_message = "you'r not allowed to do this" # optional
false
end
end
end
object_to_guard = ToGuard.new
policy_checker = AccessPolicy::PolicyCheck.new
policy_checker.current_user_or_role_for_policy = current_user
policy_checker.with_user_or_role(current_user) do
begin
policy_checker.authorize(object_to_guard, 'method_to_guard')
object_to_guard.method_to_guard
rescue AccessPolicy::NotAuthorizedError
...
rescue AccessPolicy::NotDefinedError
...
end
end
Or
class ToGuard
include AccessPolicy
policy_guarded_method 'method_to_guard' do
# do some stuff
end
policy_guarded_method 'publish', 'create?' do
# do some stuff
end
end
ToGuardPolicy = Struct.new(:current_user_or_role, :object_of_kind_to_guard) do
def method_to_guard?
current_user_or_role.is_allowed?
end
end
object_to_guard = ToGuard.new
object_to_guard.with_user_or_role(current_user) do
begin
object_to_guard.method_to_guard
rescue AccessPolicy::NotAuthorizedError
...
rescue AccessPolicy::NotDefinedError
...
end
end
object_to_guard.with_user_or_role(current_user) do
begin
object_to_guard.method_to_guard
object_to_guard.with_user_or_role(current_user.as_root) do
object_to_guard.method_to_guard_for_root
end
rescue AccessPolicy::NotAuthorizedError
...
rescue AccessPolicy::NotDefinedError
...
end
end
Test policies with rspec:
require 'spec_helper'
require 'access_policy/rspec_matchers'
module MatcherExampleSpec
DummyPolicy = Struct.new(:current_user, :object_to_guard) do
def read?
true
end
def write?
current_user && current_user.allowed?
end
def destroy?
write? && object_to_guard && !object_to_guard.locked?
end
end
end
describe "PolicyMatchers", type: :policy do
subject(:policy){
MatcherExampleSpec::DummyPolicy
}
context 'for a visitor' do
let(:visitor){nil}
it 'permits read' do
expect(policy).to permit(:read).to(visitor)
end
it 'forbids write' do
expect(policy).not_to permit(:write).to(visitor)
end
end
context 'for a admin' do
let(:admin){double('admin', allowed?: true)}
let(:locked_object_to_guard){double('object to guard', locked?: true)}
let(:unlocked_object_to_guard){double('object to guard', locked?: false)}
it 'permits read' do
expect(policy).to permit(:read).to(admin)
end
it 'permits write' do
expect(policy).to permit(:write).to(admin)
end
it 'permits destroy for unlocked objects' do
expect(policy).to permit(:destroy).on(unlocked_object_to_guard).to(admin)
end
it 'forbids destroy for locked objects' do
expect(policy).to forbid(:destroy).on(locked_object_to_guard).to(admin)
end
end
end
- Fork it ( http://github.com/slowjack2k/access_policy/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request