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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d6d610eeb4a1e57538d942c6f1cd0bfe6958a852
4
- data.tar.gz: 50ce2232aa01528cb8478a38e578a8424ca0e801
3
+ metadata.gz: 1655a3217918c74b918dc7f52cf474a554fe3857
4
+ data.tar.gz: e589678196a86628ae844a6fa920824311a4025a
5
5
  SHA512:
6
- metadata.gz: 0768c9dd24d77292180d8574f9155312c3a4028b2259d8125d8db36754e8a26c7bb448f88452f2b7588fa72edd9e46d68522ea1a3eb6e3a2b185ef766ecc292d
7
- data.tar.gz: 7852d05613d5afa58e5cf6aa23a0432efab48ba0b7badc812047a107543e1c9784492ed591547e5f3cb649a0f58e2f53f75b8c1f964741451053eaea72111c49
6
+ metadata.gz: e4091466b976765cd9486124cc1daff3339918c985e02c76fe33093456c98cf41e842444e000a591b2262dc9210c0ae828f3f7bd6078b7a875462cb00ab9400b
7
+ data.tar.gz: c984daf5257a27d91c025b9b5e6955b1442da76f452f3344fa7d9d9f7036ebb6c4e25aab3c6cf3230ccd5fe61f02a0174e42d04aca0024516608c33668d583f3
@@ -1,4 +1,4 @@
1
- Copyright (c) 2013 Piotrek Okoński
1
+ Copyright (c) 2015 Chaps sp. z o.o.
2
2
 
3
3
  MIT License
4
4
 
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(user)
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.user_id == user.id && post.comments.empty?
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
- "But wait! User should also be able to edit his posts, and only his posts!", you are wondering.
137
- This can be done using a block condition in `can` method, like so:
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(user)
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(user)
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
@@ -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.2.1"
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(@user)
8
+ configure
9
9
  end
10
10
 
11
- def configure(user)
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)
@@ -12,14 +12,14 @@ module AccessGranted
12
12
  if @block
13
13
  instance_eval(&@block)
14
14
  else
15
- configure(@user)
15
+ configure
16
16
  end
17
17
  end
18
18
 
19
- def configure(user)
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
@@ -28,7 +28,7 @@ describe AccessGranted::Rails::ControllerMethods do
28
28
  klass = Class.new do
29
29
  include AccessGranted::Policy
30
30
 
31
- def configure(user)
31
+ def configure
32
32
  role :member, 1 do
33
33
  can :read, String
34
34
  end
@@ -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
@@ -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(user)
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(user)
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, user_id: user.id
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 eq(true)
63
- expect(klass.new(@member).can?(:destroy, user_post)).to eq(true)
64
- expect(klass.new(@member).cannot?(:destroy, other_post)).to eq(true)
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(user)
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(user)
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 actions is not allowed" do
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(user)
151
+ def configure
112
152
  can :read, String
113
153
  end
114
154
  end
@@ -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.2.1
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-08-13 00:00:00.000000000 Z
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