access-granted 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 990382c04aeeeb43c67adcd3adc1fc0e4ac6b7ac
4
+ data.tar.gz: d9970ae5c29e073953f41ec55c3f19b8a0d18225
5
+ SHA512:
6
+ metadata.gz: 6ddcadc2b5e812ae350e91479047c344d705e6cb7f3011f35e695aab0ca545402a550c1e9f8c45661e64cce0228b0f44334c384615721eb2eca38938d0ea501e
7
+ data.tar.gz: 9060e6c5d8243a43f33dfe9a4b6274a68edd748d1e32930939c5c7097db0679be03f21a168ae98f031806696da654a4806c3844f866ac2aadc4ccde6f5102b51
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in access-granted.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'simplecov', require: false
8
+ gem 'rake'
9
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Piotrek Okoński
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,120 @@
1
+ # AccessGranted [![Build Status](https://travis-ci.org/pokonski/access-granted.png?branch=master)](https://travis-ci.org/pokonski/access-granted) [![Code Climate](https://codeclimate.com/github/pokonski/access-granted.png)](https://codeclimate.com/github/pokonski/access-granted)
2
+
3
+ Multi-role and whitelist based authorization gem for Rails. And it's lightweight (~300 lines of code)!
4
+
5
+ # Summary
6
+
7
+ AccessGranted is meant as replacement for CanCan to solve three major problems:
8
+
9
+ 1. built-in support for roles
10
+
11
+ Easy to read acess policy code where permissions are cleanly grouped into roles which may or may not apply to a user.
12
+ Additionally permissions are forced to be unique in the scope a role greatly simplifying the
13
+ permission resolving and extremely reducing the code-base.
14
+
15
+ 2. white-list based
16
+
17
+ This means that you define what a role **can** do,
18
+ not overidding permissions with `cannot` in a specific order which results in an ugly and unmaintainable code.
19
+
20
+ 3. Permissions can work on basically any object and AccessGranted is framework-agnostic,
21
+ (the only Rails-specific methods are `can?`/`cannot?`/`authorize!` helpers injected
22
+ into the framework only when it's present).
23
+
24
+ See [Usage](#usage) for an example of a complete AccessPolicy file.
25
+
26
+ ## Compatibility
27
+
28
+ This gem was created as a replacement for CanCan and therefore it requires minimum work to switch.
29
+
30
+ 1. Both `can?`/`cannot?` and `authorize!` methods work in Rails controllers and views, so
31
+ **you don't have to adjust your views at all**.
32
+ 2. Syntax for defining permissions in AccessPolicy file (Ability in CanCan) is exactly the same,
33
+ with added roles on top. See [Usage](#usage) below.
34
+ 3. **Main difference**: AccessGranted does not extend ActiveRecord in any way, so it does not have the `accessible_by?`
35
+ method to keep the code as simple as possible.
36
+ That is because `accessible_by?` was very limited making it useless in most cases (complex permissions with lambdas).
37
+
38
+
39
+ ## Installation
40
+
41
+ Add this line to your application's Gemfile:
42
+
43
+ gem 'access-granted'
44
+
45
+ And then execute:
46
+
47
+ $ bundle
48
+
49
+ Or install it yourself as:
50
+
51
+ $ gem install access-granted
52
+
53
+ ## Usage
54
+
55
+ Roles are defined using blocks (or by passing custom classes to keep things tidy).
56
+ Order of the roles is important, because they are being traversed in the top-to-bottom order. Generally at the top you will have
57
+ an admin or other important role giving the user top permissions, and as you go down you define less-privileged roles.
58
+
59
+ See full example:
60
+
61
+ ```ruby
62
+ class Policy
63
+ include AccessGranted::Policy
64
+
65
+ def configure(user)
66
+ # The most important role prohibiting banned
67
+ # users from doing anything.
68
+ # (even if they are moderators or admins)
69
+ role :banned, { is_banned: true } do
70
+ cannot [:create, :update, :destroy], Post
71
+
72
+ # same as above, :manage is just a shortcut for
73
+ # `[:create, :update, :destroy]`
74
+ cannot :manage, Comment
75
+ end
76
+
77
+ # Takes precedences over roles placed lower
78
+ # and explicitly lets admin mamange everything.
79
+ role :admin, { is_admin: true } do
80
+ can :manage, Post
81
+ can :manage, Comment
82
+ end
83
+
84
+ # You can also use Procs to determine
85
+ # if the role should apply to a given user.
86
+ role :moderator, proc {|u| u.moderator? } do
87
+ # overwrites permission that only allows removing own content in :member
88
+ # and lets moderators edit and delete all posts
89
+ can [:update, :destroy], Post
90
+
91
+ # and a new permission which lets moderators
92
+ # modify user accounts
93
+ can :update, User
94
+ end
95
+
96
+ # Applies to everyone logged in.
97
+ # The basic role.
98
+ role :member do
99
+ can :create, Post
100
+
101
+ # For more advanced permissions
102
+ # you must use blocks. Hash
103
+ # conditions should be used for
104
+ # simple checks only.
105
+ can [:update, :destroy], Post do |post|
106
+ post.user_id == user.id && post.comments.empty?
107
+ end
108
+ end
109
+ end
110
+ end
111
+ ```
112
+
113
+
114
+ ## Contributing
115
+
116
+ 1. Fork it
117
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
118
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
119
+ 4. Push to the branch (`git push origin my-new-feature`)
120
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ task :default => [:spec]
4
+ desc 'run Rspec specs'
5
+ task :spec do
6
+ sh 'rspec spec'
7
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'access-granted/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "access-granted"
8
+ spec.version = AccessGranted::VERSION
9
+ spec.authors = ["Piotrek Okoński"]
10
+ spec.email = ["piotrek@okonski.org"]
11
+ spec.description = %q{Whitelist and role based authorization gem}
12
+ spec.summary = %q{Elegant whitelist and role based authorization with ability to prioritize roles.}
13
+ spec.homepage = "https://github.com/pokonski/access-granted"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^spec/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency "pry"
25
+ spec.add_development_dependency "text-table"
26
+ end
@@ -0,0 +1,16 @@
1
+ require "access-granted/version"
2
+ require "access-granted/exceptions"
3
+ require "access-granted/policy"
4
+ require "access-granted/permission"
5
+ require "access-granted/controller_methods"
6
+ require "access-granted/role"
7
+
8
+ module AccessGranted
9
+
10
+ end
11
+
12
+ if defined? ActionController::Base
13
+ ActionController::Base.class_eval do
14
+ include AccessGranted::ControllerMethods
15
+ end
16
+ end
@@ -0,0 +1,24 @@
1
+ module AccessGranted
2
+ module ControllerMethods
3
+ def current_policy
4
+ @current_policy ||= ::Policy.new(current_user)
5
+ end
6
+
7
+ def self.included(base)
8
+ base.helper_method :can?, :cannot?, :current_ability
9
+ end
10
+
11
+ def can?(*args)
12
+ current_policy.can?(*args)
13
+ end
14
+
15
+ def cannot?(*args)
16
+ current_policy.cannot?(*args)
17
+ end
18
+
19
+ def authorize!(*args)
20
+ current_policy.authorize!(*args)
21
+ end
22
+ end
23
+ end
24
+
@@ -0,0 +1,7 @@
1
+ module AccessGranted
2
+ class Error < StandardError; end
3
+
4
+ class DuplicatePermission < Error; end;
5
+ class DuplicateRole < Error; end;
6
+ class AccessDenied < Error; end;
7
+ end
@@ -0,0 +1,47 @@
1
+ module AccessGranted
2
+ class Permission
3
+ attr_reader :action, :subject, :granted, :conditions
4
+
5
+ def initialize(granted, action, subject, conditions = {}, block = nil)
6
+ @action = action
7
+ @granted = granted
8
+ @subject = subject
9
+ @conditions = conditions
10
+ @block = block
11
+ end
12
+
13
+ def matches_action?(action)
14
+ @action == action
15
+ end
16
+
17
+ def matches_subject?(subject)
18
+ @subject == subject || subject.class == @subject
19
+ end
20
+
21
+ def matches_conditions?(subject)
22
+ if @block
23
+ @block.call(subject)
24
+ else
25
+ matches_hash_conditions?(subject)
26
+ end
27
+ end
28
+
29
+ def matches_hash_conditions?(subject)
30
+ @conditions.each_pair do |name, value|
31
+ return false if subject.send(name) != value
32
+ end
33
+ true
34
+ end
35
+
36
+ def eql?(other)
37
+ other.class == self.class &&
38
+ @action == other.action &&
39
+ @subject == other.subject &&
40
+ @granted == other.granted
41
+ end
42
+
43
+ def ==(other)
44
+ eql?(other)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,56 @@
1
+ module AccessGranted
2
+ module Policy
3
+ attr_accessor :roles
4
+
5
+ def initialize(user)
6
+ @user = user
7
+ @roles = []
8
+ @last_priority = 0
9
+ configure(@user)
10
+ end
11
+
12
+ def configure(user)
13
+ end
14
+
15
+ def role(name, conditions_or_klass = nil, conditions = nil, &block)
16
+ name = name.to_sym
17
+ if roles.select {|r| r.name == name }.any?
18
+ raise DuplicateRole, "Role '#{name}' already defined"
19
+ end
20
+ @last_priority += 1
21
+ r = if conditions_or_klass.is_a?(Class) && conditions_or_klass <= AccessGranted::Role
22
+ conditions_or_klass.new(name, @last_priority, conditions, @user, block)
23
+ else
24
+ Role.new(name, @last_priority, conditions_or_klass, @user, block)
25
+ end
26
+ roles << r
27
+ roles.sort_by! {|r| r.priority }
28
+ r
29
+ end
30
+
31
+ def can?(action, subject)
32
+ match_roles(@user).each do |role|
33
+ permission = role.find_permission(action, subject)
34
+ return permission.granted if permission
35
+ end
36
+ false
37
+ end
38
+
39
+ def cannot?(*args)
40
+ !can?(*args)
41
+ end
42
+
43
+ def match_roles(user)
44
+ roles.select do |role|
45
+ role.applies_to?(user)
46
+ end
47
+ end
48
+
49
+ def authorize!(action, subject)
50
+ if cannot?(action, subject)
51
+ raise AccessDenied
52
+ end
53
+ subject
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,91 @@
1
+ module AccessGranted
2
+ class Role
3
+ attr_reader :name, :user, :priority, :conditions, :permissions
4
+
5
+ def initialize(name, priority, conditions = nil, user = nil, block = nil)
6
+ @user = user
7
+ @name = name
8
+ @priority = priority
9
+ @conditions = conditions
10
+ @block = block
11
+ @permissions = []
12
+ @permissions_by_action = {}
13
+ if @block
14
+ instance_eval(&@block)
15
+ else
16
+ configure(@user)
17
+ end
18
+ end
19
+
20
+ def configure(user)
21
+ end
22
+
23
+ def can(action, subject, conditions = {}, &block)
24
+ add_permission(true, action, subject, conditions, block)
25
+ end
26
+
27
+ def cannot(action, subject, conditions = {}, &block)
28
+ add_permission(false, action, subject, conditions, block)
29
+ end
30
+
31
+ def can?(action, subject)
32
+ permission = find_permission(action, subject)
33
+ permission ? permission.granted : false
34
+ end
35
+
36
+ def find_permission(action, subject)
37
+ relevant_permissions(action, subject).detect do |permission|
38
+ permission.matches_conditions?(subject)
39
+ end
40
+ end
41
+
42
+ def applies_to?(user)
43
+ case @conditions
44
+ when Hash
45
+ matches_hash(user, @conditions)
46
+ when Proc
47
+ @conditions.call(user)
48
+ else
49
+ true
50
+ end
51
+ end
52
+
53
+
54
+ def relevant_permissions(action, subject)
55
+ permissions_by_action(action).select do |perm|
56
+ perm.matches_subject?(subject)
57
+ end
58
+ end
59
+
60
+ def matches_hash(user, conditions = {})
61
+ conditions.all? do |name, value|
62
+ user.send(name) == value
63
+ end
64
+ end
65
+
66
+ def add_permission(granted, action, subject, conditions, block)
67
+ prepare_actions(action).each do |a|
68
+ raise DuplicatePermission if relevant_permissions(a, subject).any?
69
+ @permissions << Permission.new(granted, a, subject, conditions, block)
70
+ @permissions_by_action[a] ||= []
71
+ @permissions_by_action[a] << @permissions.size - 1
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ def prepare_actions(action)
78
+ if action == :manage
79
+ actions = [:create, :update, :destroy]
80
+ else
81
+ actions = [action].flatten
82
+ end
83
+ end
84
+
85
+ def permissions_by_action(action)
86
+ (@permissions_by_action[action] || []).map do |index|
87
+ @permissions[index]
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,3 @@
1
+ module AccessGranted
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,42 @@
1
+ require "spec_helper"
2
+
3
+ describe AccessGranted::ControllerMethods do
4
+ before(:each) do
5
+ @current_user = double("User")
6
+ @controller_class = Class.new
7
+ @controller = @controller_class.new
8
+ @controller_class.stub(:helper_method).with(:can?, :cannot?, :current_ability)
9
+ @controller_class.send(:include, AccessGranted::ControllerMethods)
10
+ @controller.stub(:current_user).and_return(@current_user)
11
+ end
12
+
13
+ it "should have current_policy method returning Policy instance" do
14
+ @controller.current_policy.should be_kind_of(AccessGranted::Policy)
15
+ end
16
+
17
+ it "provides can? and cannot? method delegated to current_policy" do
18
+ @controller.can?(:read, String).should be_false
19
+ @controller.cannot?(:read, String).should be_true
20
+ end
21
+
22
+ describe "#authorize!" do
23
+ it "raises exception when authorization fails" do
24
+ expect { @controller.authorize!(:read, String) }.to raise_error(AccessGranted::AccessDenied)
25
+ end
26
+
27
+ it "returns subject if authorization succeeds" do
28
+ klass = Class.new do
29
+ include AccessGranted::Policy
30
+
31
+ def configure(user)
32
+ role :member, 1 do
33
+ can :read, String
34
+ end
35
+ end
36
+ end
37
+ policy = klass.new(@current_user)
38
+ @controller.stub(:current_policy).and_return(policy)
39
+ @controller.authorize!(:read, String).should == String
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ describe AccessGranted::Permission do
4
+ subject { AccessGranted::Permission }
5
+
6
+ describe "#matches_conditions?" do
7
+ it "matches when no conditions given" do
8
+ perm = subject.new(true, :read, String)
9
+ perm.matches_conditions?(String).should be_true
10
+ end
11
+
12
+ it "matches proc conditions" do
13
+ sub = double("Element", published?: true)
14
+ perm = subject.new(true, :read, sub.class, {}, proc {|el| el.published? })
15
+ perm.matches_conditions?(sub).should be_true
16
+ end
17
+ end
18
+
19
+ describe "#matches_hash_conditions?" do
20
+ it "matches condition hash is empty" do
21
+ perm = subject.new(true, :read, String)
22
+ perm.matches_hash_conditions?(String).should be_true
23
+ end
24
+
25
+ it "matches when conditions given" do
26
+ sub = double("Element", published: true)
27
+ perm = subject.new(true, :read, sub, { published: true })
28
+ perm.matches_hash_conditions?(sub).should be_true
29
+ end
30
+
31
+ it "does not match if one of the conditions mismatches" do
32
+ sub = double("Element", published: true, readable: false)
33
+ perm = subject.new(true, :read, sub, { published: true, readable: true })
34
+ perm.matches_hash_conditions?(sub).should be_false
35
+ end
36
+ end
37
+
38
+ describe "#matches_action?" do
39
+ it "matches if actions are identical" do
40
+ perm = subject.new(true, :read, String)
41
+ perm.matches_action?(:read).should be_true
42
+ end
43
+ end
44
+
45
+ describe "#matches_subject?" do
46
+ it "matches if subjects are identical" do
47
+ perm = subject.new(true, :read, String)
48
+ expect(perm.matches_subject? String).to be_true
49
+ end
50
+
51
+ it "matches if class is equal to subject" do
52
+ perm = subject.new(true, :read, String)
53
+ expect(perm.matches_subject? "test").to be_true
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,105 @@
1
+ require 'spec_helper'
2
+
3
+ describe AccessGranted::Policy do
4
+ before :each do
5
+ @policy = Class.new do
6
+ include AccessGranted::Policy
7
+ end.new(nil)
8
+ end
9
+
10
+ describe "#configure" do
11
+ before :each do
12
+ @member = double("member", is_moderator: false, is_admin: false, is_banned: false)
13
+ @mod = double("moderator", is_moderator: true, is_admin: false, is_banned: false)
14
+ @admin = double("administrator", is_moderator: false, is_admin: true, is_banned: false)
15
+ @banned = double("banned", is_moderator: false, is_admin: true, is_banned: true)
16
+ end
17
+
18
+ it "selects permission based on role priority" do
19
+ klass = Class.new do
20
+ include AccessGranted::Policy
21
+
22
+ def configure(user)
23
+ role :member do
24
+ can :read, String
25
+ end
26
+
27
+ role :moderator, { is_moderator: true } do
28
+ can :edit, String
29
+ end
30
+
31
+ role :administrator, { is_admin: true } do
32
+ can :destroy, String
33
+ end
34
+ end
35
+ end
36
+ klass.new(@member).cannot?(:destroy, String).should be_true
37
+ klass.new(@admin).can?(:destroy, String).should be_true
38
+ klass.new(@admin).can?(:read, String).should be_true
39
+ klass.new(@mod).cannot?(:destroy, String).should be_true
40
+ end
41
+
42
+ describe "#cannot" do
43
+ it "forbids action when used in higher role" do
44
+ klass = Class.new do
45
+ include AccessGranted::Policy
46
+
47
+ def configure(user)
48
+ role :banned, { is_banned: true } do
49
+ cannot :create, String
50
+ end
51
+
52
+ role :member do
53
+ can :create, String
54
+ end
55
+ end
56
+ end
57
+ klass.new(@member).can?(:create, String).should be_true
58
+ klass.new(@banned).can?(:create, String).should be_false
59
+ end
60
+ end
61
+ end
62
+
63
+ describe "#role" do
64
+ it "allows passing role class" do
65
+ klass_role = Class.new AccessGranted::Role do
66
+ def configure(user)
67
+ can :read, String
68
+ end
69
+ end
70
+ @policy.role(:member, klass_role)
71
+ @policy.roles.first.class.should == klass_role
72
+ end
73
+
74
+ it "allows defining a default role" do
75
+ @policy.role(:member)
76
+ @policy.roles.map(&:name).should include(:member)
77
+ end
78
+
79
+ it "does not allow duplicate role names" do
80
+ @policy.role(:member)
81
+ expect { @policy.role(:member) }.to raise_error AccessGranted::DuplicateRole
82
+ end
83
+
84
+ it "allows nesting `can` calls inside a block" do
85
+ role = @policy.role(:member) do
86
+ can :read, String
87
+ end
88
+
89
+ role.can?(:read, String).should be_true
90
+ end
91
+ end
92
+
93
+ describe "#match_roles" do
94
+ it "returns all matching roles in the order of priority" do
95
+ user = double("User", is_moderator: true, is_admin: true)
96
+
97
+ @policy.role(:administrator, { is_admin: true })
98
+ @policy.role(:moderator, { is_moderator: true })
99
+ @policy.role(:member)
100
+
101
+ @policy.match_roles(user).map(&:name).should == [:administrator, :moderator, :member]
102
+ end
103
+ end
104
+
105
+ end
data/spec/role_spec.rb ADDED
@@ -0,0 +1,95 @@
1
+ require 'spec_helper'
2
+
3
+ describe AccessGranted::Role do
4
+ subject { AccessGranted::Role }
5
+
6
+ it "requires a role name" do
7
+ expect { subject.new }.to raise_error
8
+ end
9
+
10
+ it "requires priority" do
11
+ expect { subject.new(:member) }.to raise_error
12
+ end
13
+
14
+ it "creates a default role without conditions" do
15
+ subject.new(:member, 1).conditions.should be_nil
16
+ end
17
+
18
+ describe "#relevant_permissions?" do
19
+ it "returns only matching permissions" do
20
+ role = subject.new(:member, 1)
21
+ role.can :read, String
22
+ role.can :read, Hash
23
+ role.relevant_permissions(:read, String).should == [AccessGranted::Permission.new(true, :read, String)]
24
+ end
25
+ end
26
+
27
+ describe "#applies_to?" do
28
+ it "matches user when no conditions given" do
29
+ role = subject.new(:member, 1)
30
+ user = double("User")
31
+ role.applies_to?(user).should be_true
32
+ end
33
+
34
+ it "matches user by hash conditions" do
35
+ role = subject.new(:moderator, 1, { is_moderator: true })
36
+ user = double("User", is_moderator: true)
37
+ role.applies_to?(user).should be_true
38
+ end
39
+
40
+ it "doesn't match user if any of hash conditions is not met" do
41
+ role = subject.new(:moderator, 1, { is_moderator: true, is_admin: true })
42
+ user = double("User", is_moderator: true, is_admin: false)
43
+ role.applies_to?(user).should be_false
44
+ end
45
+
46
+ it "matches user by Proc conditions" do
47
+ role = subject.new(:moderator, 1, proc {|user| user.is_moderator? })
48
+ user = double("User", is_moderator?: true)
49
+ role.applies_to?(user).should be_true
50
+ end
51
+ end
52
+
53
+ describe "#can" do
54
+ before :each do
55
+ @role = AccessGranted::Role.new(:member, 1)
56
+ end
57
+
58
+ it "forbids creating actions with the same name" do
59
+ @role.can :read, String
60
+ expect { @role.can :read, String }.to raise_error AccessGranted::DuplicatePermission
61
+ end
62
+
63
+ it "accepts :manage shortcut for CRUD actions" do
64
+ @role.can :manage, String
65
+ @role.permissions.map(&:action).should include(:create, :update, :destroy)
66
+ end
67
+
68
+ describe "when action is an Array" do
69
+ it "creates multiple permissions" do
70
+ @role.can [:read, :create], String
71
+ @role.permissions.should have(2).items
72
+ end
73
+ end
74
+
75
+ describe "when no conditions given" do
76
+ it "should be able to read a class" do
77
+ @role.can :read, String
78
+ @role.can?(:read, String).should be_true
79
+ end
80
+
81
+ it "should be able to read instance of class" do
82
+ @role.can :read, String
83
+ @role.can?(:read, "text").should be_true
84
+ end
85
+ end
86
+
87
+ describe "when conditions given" do
88
+ it "should be able to read when conditions match" do
89
+ sub = double("Element", published: true)
90
+ @role.can :read, sub.class, { published: true }
91
+ @role.can?(:read, sub).should be_true
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,26 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'simplecov'
4
+ SimpleCov.start
5
+ require 'pry'
6
+
7
+ RSpec.configure do |config|
8
+ config.treat_symbols_as_metadata_keys_with_true_values = true
9
+ config.run_all_when_everything_filtered = true
10
+ config.filter_run :focus
11
+
12
+ config.order = 'random'
13
+ end
14
+
15
+ module ActionController
16
+ class Base
17
+ def self.helper_method(*args)
18
+ end
19
+ end
20
+ end
21
+ require 'access-granted'
22
+
23
+ class Policy
24
+ include AccessGranted::Policy
25
+ end
26
+
metadata ADDED
@@ -0,0 +1,141 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: access-granted
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Piotrek Okoński
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-11-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: text-table
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Whitelist and role based authorization gem
84
+ email:
85
+ - piotrek@okonski.org
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - .gitignore
91
+ - .rspec
92
+ - .travis.yml
93
+ - Gemfile
94
+ - LICENSE.txt
95
+ - README.md
96
+ - Rakefile
97
+ - access-granted.gemspec
98
+ - lib/access-granted.rb
99
+ - lib/access-granted/controller_methods.rb
100
+ - lib/access-granted/exceptions.rb
101
+ - lib/access-granted/permission.rb
102
+ - lib/access-granted/policy.rb
103
+ - lib/access-granted/role.rb
104
+ - lib/access-granted/version.rb
105
+ - spec/controller_methods_spec.rb
106
+ - spec/permission_spec.rb
107
+ - spec/policy_spec.rb
108
+ - spec/role_spec.rb
109
+ - spec/spec_helper.rb
110
+ homepage: https://github.com/pokonski/access-granted
111
+ licenses:
112
+ - MIT
113
+ metadata: {}
114
+ post_install_message:
115
+ rdoc_options: []
116
+ require_paths:
117
+ - lib
118
+ required_ruby_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - '>='
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ required_rubygems_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - '>='
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ requirements: []
129
+ rubyforge_project:
130
+ rubygems_version: 2.0.3
131
+ signing_key:
132
+ specification_version: 4
133
+ summary: Elegant whitelist and role based authorization with ability to prioritize
134
+ roles.
135
+ test_files:
136
+ - spec/controller_methods_spec.rb
137
+ - spec/permission_spec.rb
138
+ - spec/policy_spec.rb
139
+ - spec/role_spec.rb
140
+ - spec/spec_helper.rb
141
+ has_rdoc: