access-granted 0.2.1 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +11 -12
- data/access-granted.gemspec +1 -1
- data/lib/access-granted/permission.rb +3 -2
- data/lib/access-granted/policy.rb +3 -3
- data/lib/access-granted/role.rb +4 -4
- data/lib/generators/access_granted/policy_generator.rb +16 -0
- data/lib/generators/templates/access_policy.rb +40 -0
- data/spec/controller_methods_spec.rb +1 -1
- data/spec/permission_spec.rb +3 -3
- data/spec/policy_spec.rb +50 -10
- data/spec/role_spec.rb +5 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1655a3217918c74b918dc7f52cf474a554fe3857
|
4
|
+
data.tar.gz: e589678196a86628ae844a6fa920824311a4025a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e4091466b976765cd9486124cc1daff3339918c985e02c76fe33093456c98cf41e842444e000a591b2262dc9210c0ae828f3f7bd6078b7a875462cb00ab9400b
|
7
|
+
data.tar.gz: c984daf5257a27d91c025b9b5e6955b1442da76f452f3344fa7d9d9f7036ebb6c4e25aab3c6cf3230ccd5fe61f02a0174e42d04aca0024516608c33668d583f3
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -26,7 +26,7 @@ AccessGranted is meant as a replacement for CanCan to solve major problems:
|
|
26
26
|
2. Roles
|
27
27
|
|
28
28
|
Adds support for roles, so no more `if`'s and `else`'s in your Policy file. This makes it extremely easy to maintain and read the code.
|
29
|
-
|
29
|
+
|
30
30
|
3. white-lists
|
31
31
|
|
32
32
|
This means that you define what the user **can** do, which results in clean, readable policies regardless of app complexity.
|
@@ -58,8 +58,7 @@ Let's start with a complete example of what can be achieved:
|
|
58
58
|
class AccessPolicy
|
59
59
|
include AccessGranted::Policy
|
60
60
|
|
61
|
-
def configure
|
62
|
-
|
61
|
+
def configure
|
63
62
|
# The most important admin role, gets checked first
|
64
63
|
|
65
64
|
role :admin, { is_admin: true } do
|
@@ -77,8 +76,8 @@ class AccessPolicy
|
|
77
76
|
role :member do
|
78
77
|
can :create, Post
|
79
78
|
|
80
|
-
can [:update, :destroy], Post do |post|
|
81
|
-
post.
|
79
|
+
can [:update, :destroy], Post do |post, user|
|
80
|
+
post.author == user && post.comments.empty?
|
82
81
|
end
|
83
82
|
end
|
84
83
|
end
|
@@ -133,12 +132,12 @@ end
|
|
133
132
|
|
134
133
|
#### Block conditions
|
135
134
|
|
136
|
-
|
137
|
-
|
135
|
+
Sometimes you may need to dynamically check for ownership or other conditions,
|
136
|
+
this can be done using a block condition in `can` method, like so:
|
138
137
|
|
139
138
|
```ruby
|
140
139
|
role :member do
|
141
|
-
can :update, Post do |post|
|
140
|
+
can :update, Post do |post, user|
|
142
141
|
post.author_id == user.id
|
143
142
|
end
|
144
143
|
end
|
@@ -157,7 +156,7 @@ role :admin, { is_admin: true } do
|
|
157
156
|
end
|
158
157
|
|
159
158
|
role :member do
|
160
|
-
can :update, Post do |post|
|
159
|
+
can :update, Post do |post, user|
|
161
160
|
post.author_id == user.id
|
162
161
|
end
|
163
162
|
end
|
@@ -284,7 +283,7 @@ Below you can see an extracted `:member` role:
|
|
284
283
|
class AccessPolicy
|
285
284
|
include AccessGranted::Policy
|
286
285
|
|
287
|
-
def configure
|
286
|
+
def configure
|
288
287
|
role :administrator, is_admin: true do
|
289
288
|
can :manage, User
|
290
289
|
end
|
@@ -301,9 +300,9 @@ And roles should look like this
|
|
301
300
|
# app/roles/member_role.rb
|
302
301
|
|
303
302
|
class MemberRole < AccessGranted::Role
|
304
|
-
def configure
|
303
|
+
def configure
|
305
304
|
can :create, Post
|
306
|
-
can :destroy, Post do |post|
|
305
|
+
can :destroy, Post do |post, user|
|
307
306
|
post.author == user
|
308
307
|
end
|
309
308
|
end
|
data/access-granted.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "access-granted"
|
7
|
-
spec.version = "0.
|
7
|
+
spec.version = "1.0.1"
|
8
8
|
spec.authors = ["Piotrek Okoński"]
|
9
9
|
spec.email = ["piotrek@okonski.org"]
|
10
10
|
spec.description = %q{Role based authorization gem}
|
@@ -2,8 +2,9 @@ module AccessGranted
|
|
2
2
|
class Permission
|
3
3
|
attr_reader :action, :subject, :granted, :conditions
|
4
4
|
|
5
|
-
def initialize(granted, action, subject, conditions = {}, block = nil)
|
5
|
+
def initialize(granted, action, subject, user = nil, conditions = {}, block = nil)
|
6
6
|
@action = action
|
7
|
+
@user = user
|
7
8
|
@granted = granted
|
8
9
|
@subject = subject
|
9
10
|
@conditions = conditions
|
@@ -20,7 +21,7 @@ module AccessGranted
|
|
20
21
|
|
21
22
|
def matches_conditions?(subject)
|
22
23
|
if @block
|
23
|
-
@block.call(subject)
|
24
|
+
@block.call(subject, @user)
|
24
25
|
else
|
25
26
|
matches_hash_conditions?(subject)
|
26
27
|
end
|
@@ -5,10 +5,10 @@ module AccessGranted
|
|
5
5
|
def initialize(user)
|
6
6
|
@user = user
|
7
7
|
@roles = []
|
8
|
-
configure
|
8
|
+
configure
|
9
9
|
end
|
10
10
|
|
11
|
-
def configure
|
11
|
+
def configure
|
12
12
|
end
|
13
13
|
|
14
14
|
def role(name, conditions_or_klass = nil, conditions = nil, &block)
|
@@ -25,7 +25,7 @@ module AccessGranted
|
|
25
25
|
r
|
26
26
|
end
|
27
27
|
|
28
|
-
def can?(action, subject)
|
28
|
+
def can?(action, subject = nil)
|
29
29
|
roles.each do |role|
|
30
30
|
next unless role.applies_to?(@user)
|
31
31
|
permission = role.find_permission(action, subject)
|
data/lib/access-granted/role.rb
CHANGED
@@ -12,14 +12,14 @@ module AccessGranted
|
|
12
12
|
if @block
|
13
13
|
instance_eval(&@block)
|
14
14
|
else
|
15
|
-
configure
|
15
|
+
configure
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
def configure
|
19
|
+
def configure
|
20
20
|
end
|
21
21
|
|
22
|
-
def can(action, subject, conditions = {}, &block)
|
22
|
+
def can(action, subject = nil, conditions = {}, &block)
|
23
23
|
add_permission(true, action, subject, conditions, block)
|
24
24
|
end
|
25
25
|
|
@@ -53,7 +53,7 @@ module AccessGranted
|
|
53
53
|
def add_permission(granted, action, subject, conditions, block)
|
54
54
|
prepare_actions(action).each do |a|
|
55
55
|
raise DuplicatePermission if permission_exists?(a, subject)
|
56
|
-
@permissions << Permission.new(granted, a, subject, conditions, block)
|
56
|
+
@permissions << Permission.new(granted, a, subject, @user, conditions, block)
|
57
57
|
@permissions_by_action[a] ||= []
|
58
58
|
@permissions_by_action[a] << @permissions.size - 1
|
59
59
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rails/generators/base'
|
2
|
+
|
3
|
+
module Accessgranted
|
4
|
+
module Generators
|
5
|
+
class PolicyGenerator < Rails::Generators::Base
|
6
|
+
source_root File.expand_path("../../templates", __FILE__)
|
7
|
+
|
8
|
+
namespace "access_granted:policy"
|
9
|
+
desc "Creates an Access Granted policy."
|
10
|
+
|
11
|
+
def copy_policy
|
12
|
+
template "access_policy.rb", "app/policies/access_policy.rb"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class AccessPolicy
|
2
|
+
include AccessGranted::Policy
|
3
|
+
|
4
|
+
def configure(user)
|
5
|
+
# Example policy for AccessGranted.
|
6
|
+
# For more details check the README at
|
7
|
+
#
|
8
|
+
# https://github.com/chaps-io/access-granted/blob/master/README.md
|
9
|
+
#
|
10
|
+
# Roles inherit from less important roles, so:
|
11
|
+
# - :admin has permissions defined in :member, :guest and himself
|
12
|
+
# - :member has permissions from :guest and himself
|
13
|
+
# - :guest has only its own permissions since it's the first role.
|
14
|
+
#
|
15
|
+
# The most important role should be at the top.
|
16
|
+
# In this case an administrator.
|
17
|
+
#
|
18
|
+
# role :admin, proc { |user| user.admin? } do
|
19
|
+
# can :destroy, User
|
20
|
+
# end
|
21
|
+
|
22
|
+
# More privileged role, applies to registered users.
|
23
|
+
#
|
24
|
+
# role :member, proc { |user| user.registered? } do
|
25
|
+
# can :create, Post
|
26
|
+
# can :create, Comment
|
27
|
+
# can [:update, :destroy], Post do |post|
|
28
|
+
# post.author == user
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
|
32
|
+
# The base role with no additional conditions.
|
33
|
+
# Applies to every user.
|
34
|
+
#
|
35
|
+
# role :guest do
|
36
|
+
# can :read, Post
|
37
|
+
# can :read, Comment
|
38
|
+
# end
|
39
|
+
end
|
40
|
+
end
|
data/spec/permission_spec.rb
CHANGED
@@ -11,7 +11,7 @@ describe AccessGranted::Permission do
|
|
11
11
|
|
12
12
|
it "matches proc conditions" do
|
13
13
|
sub = double("Element", published?: true)
|
14
|
-
perm = subject.new(true, :read, sub.class, {}, proc {|el| el.published? })
|
14
|
+
perm = subject.new(true, :read, sub.class, nil, {}, proc {|el| el.published? })
|
15
15
|
expect(perm.matches_conditions?(sub)).to eq(true)
|
16
16
|
end
|
17
17
|
end
|
@@ -24,13 +24,13 @@ describe AccessGranted::Permission do
|
|
24
24
|
|
25
25
|
it "matches when conditions given" do
|
26
26
|
sub = double("Element", published: true)
|
27
|
-
perm = subject.new(true, :read, sub, { published: true })
|
27
|
+
perm = subject.new(true, :read, sub, nil, { published: true })
|
28
28
|
expect(perm.matches_hash_conditions?(sub)).to eq(true)
|
29
29
|
end
|
30
30
|
|
31
31
|
it "does not match if one of the conditions mismatches" do
|
32
32
|
sub = double("Element", published: true, readable: false)
|
33
|
-
perm = subject.new(true, :read, sub, { published: true, readable: true })
|
33
|
+
perm = subject.new(true, :read, sub, nil, { published: true, readable: true })
|
34
34
|
expect(perm.matches_hash_conditions?(sub)).to eq(false)
|
35
35
|
end
|
36
36
|
end
|
data/spec/policy_spec.rb
CHANGED
@@ -12,11 +12,32 @@ describe AccessGranted::Policy do
|
|
12
12
|
@banned = double("banned", id: 4, is_moderator: false, is_admin: true, is_banned: true)
|
13
13
|
end
|
14
14
|
|
15
|
+
it "passes user object to permission block" do
|
16
|
+
post_owner = double(id: 123)
|
17
|
+
other_user = double(id: 5)
|
18
|
+
post = FakePost.new(post_owner.id)
|
19
|
+
|
20
|
+
klass = Class.new do
|
21
|
+
include AccessGranted::Policy
|
22
|
+
|
23
|
+
def configure
|
24
|
+
role :member do
|
25
|
+
can :destroy, FakePost do |post, user|
|
26
|
+
post.user_id == user.id
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
expect(klass.new(post_owner).can?(:destroy, post)).to eq(true)
|
33
|
+
expect(klass.new(other_user).can?(:destroy, post)).to eq(false)
|
34
|
+
end
|
35
|
+
|
15
36
|
it "selects permission based on role priority" do
|
16
37
|
klass = Class.new do
|
17
38
|
include AccessGranted::Policy
|
18
39
|
|
19
|
-
def configure
|
40
|
+
def configure
|
20
41
|
role :administrator, { is_admin: true } do
|
21
42
|
can :destroy, String
|
22
43
|
end
|
@@ -48,28 +69,47 @@ describe AccessGranted::Policy do
|
|
48
69
|
klass = Class.new do
|
49
70
|
include AccessGranted::Policy
|
50
71
|
|
51
|
-
def configure
|
72
|
+
def configure
|
52
73
|
role :administrator, { is_admin: true } do
|
53
74
|
can :destroy, FakePost
|
54
75
|
end
|
55
76
|
|
56
77
|
role :member do
|
57
|
-
can :destroy, FakePost,
|
78
|
+
can :destroy, FakePost do |post, user|
|
79
|
+
post.user_id == user.id
|
80
|
+
end
|
58
81
|
end
|
59
82
|
end
|
60
83
|
end
|
61
84
|
|
62
|
-
expect(klass.new(@admin).can?(:destroy, user_post)).to
|
63
|
-
expect(klass.new(@
|
64
|
-
|
85
|
+
expect(klass.new(@admin).can?(:destroy, user_post)).to eq(true)
|
86
|
+
expect(klass.new(@admin).can?(:destroy, other_post)).to eq(true)
|
87
|
+
|
88
|
+
expect(klass.new(@member).can?(:destroy, user_post)).to eq(true)
|
89
|
+
expect(klass.new(@member).cannot?(:destroy, other_post)).to eq(true)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
it "resolves permissions without subject" do
|
94
|
+
klass = Class.new do
|
95
|
+
include AccessGranted::Policy
|
96
|
+
|
97
|
+
def configure
|
98
|
+
role :member do
|
99
|
+
can :vague_action
|
100
|
+
end
|
101
|
+
end
|
65
102
|
end
|
103
|
+
|
104
|
+
expect(klass.new(@member).can?(:vague_action)).to eq(true)
|
66
105
|
end
|
106
|
+
|
67
107
|
describe "#cannot" do
|
68
108
|
it "forbids action when used in superior role" do
|
69
109
|
klass = Class.new do
|
70
110
|
include AccessGranted::Policy
|
71
111
|
|
72
|
-
def configure
|
112
|
+
def configure
|
73
113
|
role :banned, { is_banned: true } do
|
74
114
|
cannot :create, String
|
75
115
|
end
|
@@ -89,13 +129,13 @@ describe AccessGranted::Policy do
|
|
89
129
|
Class.new do
|
90
130
|
include AccessGranted::Policy
|
91
131
|
|
92
|
-
def configure
|
132
|
+
def configure
|
93
133
|
role(:member) { can :create, String }
|
94
134
|
end
|
95
135
|
end
|
96
136
|
end
|
97
137
|
|
98
|
-
it "raises AccessDenied if
|
138
|
+
it "raises AccessDenied if action is not allowed" do
|
99
139
|
expect { klass.new(@member).authorize!(:create, Integer) }.to raise_error AccessGranted::AccessDenied
|
100
140
|
end
|
101
141
|
|
@@ -108,7 +148,7 @@ describe AccessGranted::Policy do
|
|
108
148
|
describe "#role" do
|
109
149
|
it "allows passing role class" do
|
110
150
|
klass_role = Class.new AccessGranted::Role do
|
111
|
-
def configure
|
151
|
+
def configure
|
112
152
|
can :read, String
|
113
153
|
end
|
114
154
|
end
|
data/spec/role_spec.rb
CHANGED
@@ -42,6 +42,11 @@ describe AccessGranted::Role do
|
|
42
42
|
@role = AccessGranted::Role.new(:member)
|
43
43
|
end
|
44
44
|
|
45
|
+
it "allows adding permission without subject" do
|
46
|
+
@role.can :vague_action
|
47
|
+
expect(@role.find_permission(:vague_action, nil)).to_not be_nil
|
48
|
+
end
|
49
|
+
|
45
50
|
it "forbids creating actions with the same name" do
|
46
51
|
@role.can :read, String
|
47
52
|
expect { @role.can :read, String }.to raise_error AccessGranted::DuplicatePermission
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: access-granted
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotrek Okoński
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-11-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -62,6 +62,8 @@ files:
|
|
62
62
|
- lib/access-granted/policy.rb
|
63
63
|
- lib/access-granted/rails/controller_methods.rb
|
64
64
|
- lib/access-granted/role.rb
|
65
|
+
- lib/generators/access_granted/policy_generator.rb
|
66
|
+
- lib/generators/templates/access_policy.rb
|
65
67
|
- spec/controller_methods_spec.rb
|
66
68
|
- spec/permission_spec.rb
|
67
69
|
- spec/policy_spec.rb
|