walruz 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +56 -53
- data/Rakefile +1 -0
- data/VERSION.yml +1 -1
- data/lib/walruz/actor.rb +79 -51
- data/lib/walruz/core_ext/array.rb +79 -0
- data/lib/walruz/policy.rb +48 -53
- data/lib/walruz/subject.rb +37 -17
- data/lib/walruz/utils.rb +73 -19
- data/lib/walruz.rb +21 -1
- data/spec/scenario.rb +26 -17
- data/spec/walruz/actor_spec.rb +26 -22
- data/spec/walruz/core_ext/array_spec.rb +84 -0
- data/spec/walruz/utils_spec.rb +4 -6
- data/spec/walruz/walruz_spec.rb +15 -1
- metadata +6 -3
data/README.rdoc
CHANGED
@@ -4,27 +4,27 @@
|
|
4
4
|
|
5
5
|
Walruz facilitates the separation between the authorization process on the business logic and the actions executed after the validation of the authorizations. To understand how it works, we will follow the following terminology:
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
[<b>Subject</b>] Object that is going to be managed (Profile, Posts).
|
8
|
+
[<b>Actor</b>] Entity that wants to perform an action on a <em>subject</em> (User, Admin).
|
9
|
+
[<b>Policy</b>] A set of rules that tells if the <em>actor</em> can perform the desired action on the <em>subject</em>.
|
10
10
|
|
11
11
|
== Walruz Architecture
|
12
12
|
|
13
13
|
Walruz provides modules and classes that help on the implementation of the concepts given previously, this are:
|
14
14
|
|
15
|
-
|
16
|
-
|
15
|
+
[<b><tt>Walruz::Subject</tt></b>]
|
16
|
+
Module that provides the interface to associate policies to an action in the <em>subject</em>.
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
[<b><tt>Walruz::Actor</tt></b>]
|
19
|
+
Module that provides the interface to perform queries to validate if an action can be done between the
|
20
|
+
<em>actor</em> and the <em>subject</em>.
|
21
21
|
|
22
|
-
|
23
|
-
|
22
|
+
[<b><tt>Walruz::Policy</tt></b>]
|
23
|
+
Class that provides the interface to implement authorization logic.
|
24
24
|
|
25
25
|
== Subjects specify which policies are related to which actions
|
26
26
|
|
27
|
-
Subject classes may specify a set of actions that can be performed to them using the check_authorization method
|
27
|
+
Subject classes may specify a set of actions that can be performed to them using the <tt>check_authorization</tt> method
|
28
28
|
|
29
29
|
class User
|
30
30
|
include Walruz::Subject
|
@@ -33,7 +33,7 @@ Subject classes may specify a set of actions that can be performed to them using
|
|
33
33
|
:update => UserUpdatePolicy
|
34
34
|
end
|
35
35
|
|
36
|
-
If there is just one policy to every possible action performed to the subject
|
36
|
+
If there is just one <em>policy</em> to every possible action performed to the <em>subject</em>, you may specify the :default action, or just specify the Policy class.
|
37
37
|
|
38
38
|
Example:
|
39
39
|
|
@@ -63,35 +63,29 @@ You can also specify other flags with the default flag.
|
|
63
63
|
|
64
64
|
== Actors verify if they are able to perform an action on a subject
|
65
65
|
|
66
|
-
Actor classes can use several methods to check if the actor instance can perform the given action on a subject
|
66
|
+
Actor classes can use several methods to check if the <em>actor</em> instance can perform the given action on a <em>subject</em>. This are:
|
67
67
|
|
68
|
-
|
69
|
-
Returns boolean that says if the actor can execute or not the action on the subject.
|
68
|
+
[<b><tt>can?(action, subject)</tt></b>] Returns boolean that says if the <em>actor</em> can execute or not the action on the <em>subject</em>.
|
70
69
|
|
71
|
-
|
72
|
-
In case the actor can execute the action on the subject, it returns the parameters hash from the policy, otherwise it will raise a Walruz::NotAuthorized.
|
70
|
+
[<b><tt>authorize(action, subject)</tt></b>] In case the <em>actor</em> can execute the action on the <em>subject</em>, it returns the parameters hash from the <em>policy</em>, otherwise it will raise a <tt>Walruz::NotAuthorized</tt>.
|
73
71
|
|
74
|
-
|
75
|
-
It behaves just like the `can?` method, but instead of giving an action to be executed to the subject, it receives a policy label.
|
72
|
+
[<b><tt>satisfies?(policy_label, subject)</tt></b>] It behaves just like the <tt>can?</tt> method, but instead of giving an action to be executed to the <em>subject</em>, it receives a <em>policy</em> label.
|
76
73
|
|
77
|
-
In case the given action is not assigned to any policy
|
74
|
+
In case the given action is not assigned to any <em>policy</em>, a default Policy will be executed (if given), if no default <em>policy</em> is given then a <tt>Walruz::ActionNotFound</tt> exception will be raised.
|
78
75
|
|
79
76
|
Examples:
|
80
77
|
|
81
|
-
current_user.can?(:read, friends_profile)
|
82
|
-
|
83
|
-
current_user.satisfies
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
policy_params = current_user.authorize(:read, friends_profile)
|
88
|
-
# all the code executed bellow will be executed when the actor is authorized
|
78
|
+
current_user.can?(:read, friends_profile) #=> true
|
79
|
+
current_user.satisfies?(:actor_is_admin, nil) #=> false
|
80
|
+
current_user.satisfies(:actor_is_admin, nil) #=> nil
|
81
|
+
current_user.authorize(:read, friends_profile) #=> Hash
|
82
|
+
current_user.authorize!(:read, other_person_profile) # => raises Walruz::NotAuthorized
|
89
83
|
|
90
84
|
== Implementing Policies
|
91
85
|
|
92
|
-
To implement a policy
|
86
|
+
To implement a <em>policy</em>, it is necessary to inherit from the Walruz::Policy class. This class provides a method called <tt>authorized?</tt> that return either a Boolean, or an Array of two items, the first one being a Boolean, and the second being a Hash of parameters returned from the Policy.
|
93
87
|
|
94
|
-
Every Policy Class also has a label associated to it, by default the label will be the name of the class in underscore case; if you want to have a custom label for a Policy Class, you can invoke the
|
88
|
+
Every Policy Class also has a label associated to it, by default the label will be the name of the class in underscore case; if you want to have a custom label for a Policy Class, you can invoke the <tt>set_policy_label</tt> method on the class context and specify the label that you want for it. This label is used on the <tt>satisfies?</tt> method.
|
95
89
|
|
96
90
|
Examples:
|
97
91
|
|
@@ -118,19 +112,26 @@ Examples:
|
|
118
112
|
end
|
119
113
|
|
120
114
|
end
|
115
|
+
|
116
|
+
# Examples using this policies with the satisfies method
|
117
|
+
|
118
|
+
current_user.satisfies?(:is_admin, nil)
|
119
|
+
|
120
|
+
# By default, the policy label is the name of the class in underscore case.
|
121
|
+
current_user.satisfies?(:user_is_friend, other_user)
|
121
122
|
|
122
123
|
|
123
124
|
== Composing basic policies to create complex ones
|
124
125
|
|
125
|
-
Sometimes policies can turn really messy, specially when you have a complex business model. The good news is that normally this complex policies are a composition of more simple policies (e.g. ActorCanSeeUserPictures). Instead of creating this new classes that replicates the same logic of basic policies, we could merge them together in the following way:
|
126
|
+
Sometimes policies can turn really messy, specially when you have a complex business model. The good news is that normally this complex policies are a composition of more simple policies (e.g. <tt>ActorCanSeeUserPictures</tt>). Instead of creating this new classes that replicates the same logic of basic policies, we could merge them together in the following way:
|
126
127
|
|
127
|
-
ActorCanSeeUserPictures = Walruz::Utils.all(UserIsFriend, UserAllowsDisclosureOfPictures)
|
128
|
+
ActorCanSeeUserPictures = Walruz::Utils.all(UserIsFriend, UserAllowsDisclosureOfPictures)
|
128
129
|
|
129
|
-
There is also the utility methods
|
130
|
+
There is also the utility methods <tt>any</tt> and <tt>not</tt>, to create combinations of policies.
|
130
131
|
|
131
|
-
If your policy returns a parameters hash, and you are using the
|
132
|
+
If your <em>policy</em> returns a parameters hash, and you are using the <tt>all</tt> method, the parameters of each <em>policy</em> will be merged together, if you are using the <tt>any</tt> method, the parameters of the first <em>policy</em> that returns true will be returned.
|
132
133
|
|
133
|
-
One other thing that the utility methods does for you is that it leaves its track on the returned policy parameters, when you invoke a composite policy
|
134
|
+
One other thing that the utility methods does for you is that it leaves its track on the returned <em>policy</em> parameters, when you invoke a composite <em>policy</em>, every <em>policy</em> will leave in the parameters hash the policy_label with a question mark at the end, that way you can know which policies were successful or not.
|
134
135
|
|
135
136
|
Example:
|
136
137
|
|
@@ -170,7 +171,7 @@ Example:
|
|
170
171
|
|
171
172
|
== Dependencies between Policies
|
172
173
|
|
173
|
-
Sometimes you would like to have a Policy that strictly depends in other policies, on the previous example
|
174
|
+
Sometimes you would like to have a Policy that strictly depends in other policies, on the previous example <tt>UserAllowsDisclosureOfPictures</tt> could have a dependency that says that only the User allows the disclosure of pictures if and only if there is a friend relationship, so we could re-implement this <em>policy</em> as:
|
174
175
|
|
175
176
|
Example:
|
176
177
|
|
@@ -179,7 +180,7 @@ Example:
|
|
179
180
|
# ...
|
180
181
|
end
|
181
182
|
|
182
|
-
Suppose you need the parameters returned by the previous Policy, you can have them with the
|
183
|
+
Suppose you need the parameters returned by the previous Policy, you can have them with the <tt>params</tt> method.
|
183
184
|
|
184
185
|
Example:
|
185
186
|
|
@@ -194,7 +195,7 @@ Example:
|
|
194
195
|
|
195
196
|
== Policy combinators
|
196
197
|
|
197
|
-
Sometimes you would like to execute policies that are not directly related to a subject
|
198
|
+
Sometimes you would like to execute policies that are not directly related to a <em>subject</em>, but to the association of a <em>subject</em>. Given the example above of the friendship relationship and the disclosure of pictures, sometimes you would like to check if a user can see a picture directly on the picture model.
|
198
199
|
|
199
200
|
Suppose we have the following model in our system:
|
200
201
|
|
@@ -202,11 +203,11 @@ Suppose we have the following model in our system:
|
|
202
203
|
belongs_to :owner
|
203
204
|
end
|
204
205
|
|
205
|
-
and we would like to check if the current_user can see (read) the picture using:
|
206
|
+
and we would like to check if the <tt>current_user</tt> can see (read) the picture using:
|
206
207
|
|
207
208
|
current_user.can?(:read, picture_instance)
|
208
209
|
|
209
|
-
If you may recall, we already implemented the logic that checks that authorization in UserAllowsDisclosureOfPictures
|
210
|
+
If you may recall, we already implemented the logic that checks that authorization in <tt>UserAllowsDisclosureOfPictures</tt>, but that <em>policy</em> only works when the <em>subject</em> is of class User; given that you have a <em>subject</em> of class Picture you can not re-use this <em>policy</em>.
|
210
211
|
|
211
212
|
You could solve this issue doing the following:
|
212
213
|
|
@@ -218,7 +219,7 @@ You could solve this issue doing the following:
|
|
218
219
|
|
219
220
|
end
|
220
221
|
|
221
|
-
But as you may see, we are just creating new policies to handle old ones, we are not combining the policies effectively. To avoid this caveat, you can use the
|
222
|
+
But as you may see, we are just creating new policies to handle old ones, we are not combining the policies effectively. To avoid this caveat, you can use the <tt>PolicyClass.for_subject</tt> method:
|
222
223
|
|
223
224
|
PictureReadPolicy = UserAllowsDisclosureOfPictures.for_subject(:owner)
|
224
225
|
|
@@ -229,11 +230,11 @@ But as you may see, we are just creating new policies to handle old ones, we are
|
|
229
230
|
check_authorizations :read => PictureReadPolicy
|
230
231
|
end
|
231
232
|
|
232
|
-
The parameter of
|
233
|
+
The parameter of <tt>but_for</tt> is the name of the <em>subject's</em> method that will return a new <em>subject</em>, this new <em>subject</em> is then passed through the <em>policy</em>. Pretty neat eh?
|
233
234
|
|
234
235
|
== Returning custom errors
|
235
236
|
|
236
|
-
Suppose you want to add an error to the authorization failure that is a more descriptive, you can do so on the
|
237
|
+
Suppose you want to add an error to the authorization failure that is a more descriptive, you can do so on the <tt>authorized?</tt> method passing a hash with a <tt>:error_message</tt> key on the false return. If you use the <tt>can!</tt> method on the <em>actor</em> model, this will become the <tt>Walruz::NotAuthorized</tt> error message.
|
237
238
|
|
238
239
|
Example:
|
239
240
|
|
@@ -250,26 +251,28 @@ Example:
|
|
250
251
|
|
251
252
|
== Conventions
|
252
253
|
|
253
|
-
You'll notice that once you start implementing policies for your system, you'll be lost soon enough asking yourself which type of subject a Policy receives; to avoid such confusions, we suggest that you apply the following rules:
|
254
|
+
You'll notice that once you start implementing policies for your system, you'll be lost soon enough asking yourself which type of <em>subject</em> a Policy receives; to avoid such confusions, we suggest that you apply the following rules of thumb:
|
254
255
|
|
255
|
-
- The first name of the policy should be the Subject class (e.g. UserIsFriend)
|
256
|
-
- If the policy only applies to the actor
|
257
|
-
- You should always have the compositions of policies in just one place in your library folder (e.g. in policies.rb file).
|
258
|
-
- The result of policy compositions should finish with the word Policy (e.g
|
259
|
-
- Use
|
256
|
+
- The first name of the <em>policy</em> should be the Subject class (e.g. <tt>UserIsFriend</tt>)
|
257
|
+
- If the <em>policy</em> only applies to the <em>actor</em>, the <em>policy</em> class name should start with the Actor word (e.g. <tt>ActorIsAdmin</tt>)
|
258
|
+
- You should always have the compositions of policies in just one place in your library folder (e.g. in <tt>policies.rb</tt> file).
|
259
|
+
- The result of <em>policy</em> compositions should finish with the word Policy (e.g <tt>UserDeletePolicy = any(ActorIsSubject, ActorIsAdmin)</tt>)
|
260
|
+
- Use <tt>PolicyClass.but_for</tt> when you are combining the <em>policy</em> class with other policies, if you are not doing this, consider checking authorizations on parents of the <em>subject</em> instead of the <em>subject</em> (e.g. <tt>current_user.can?(:see_pictures_of, picture.owner)</tt>)
|
260
261
|
|
261
262
|
If you follow this rules, it will be much easier for you to merge policies together in an efficient way.
|
262
263
|
|
263
264
|
== Rails Integration
|
264
265
|
|
265
|
-
See
|
266
|
+
See walruz-rails[http://github.com/noomii/walruz-rails] gem.
|
266
267
|
|
267
268
|
== More examples
|
268
269
|
|
269
|
-
You may check the project in the examples/ directory for more info; on the rails project, take a look on the spec/models/beatle_spec.rb file, it's really illustrating.
|
270
|
+
You may check the project in the examples/ directory for more info; on the rails project, take a look on the <tt>spec/models/beatle_spec.rb</tt> file, it's really illustrating.
|
270
271
|
|
271
272
|
== Copyright
|
272
273
|
|
273
|
-
Copyright (c) 2009 Roman Gonzalez <romanandreg@gmail.com>.
|
274
|
-
|
274
|
+
Copyright (c) 2009 Roman Gonzalez <romanandreg@gmail.com>.
|
275
|
+
|
276
|
+
Copyright (c) 2009 Noomii inc. <http://www.noomii.com>.
|
277
|
+
|
275
278
|
All rights reserved.
|
data/Rakefile
CHANGED
@@ -10,6 +10,7 @@ begin
|
|
10
10
|
gem.homepage = "http://github.com/noomii/walruz"
|
11
11
|
gem.authors = ["Roman Gonzalez"]
|
12
12
|
gem.rubyforge_project = "walruz"
|
13
|
+
gem.has_rdoc = 'yard'
|
13
14
|
|
14
15
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
16
|
end
|
data/VERSION.yml
CHANGED
data/lib/walruz/actor.rb
CHANGED
@@ -1,23 +1,36 @@
|
|
1
1
|
module Walruz
|
2
2
|
|
3
3
|
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
4
|
+
# This module provides the methods that enable an <em>actor</em> to check if it is able
|
5
|
+
# to do an action on a <em>subject</em>. It also provides methods to check on specific
|
6
|
+
# Policies given the policy label. The methods mostly used by classes that include this module are:
|
7
|
+
#
|
8
|
+
# [<b><tt>can?(action, subject)</tt></b>] Returns a Boolean indicating if the actor is authorized to do an action on the subject.
|
9
|
+
# [<b><tt>authorize(action, subject)</tt></b>] Returns Either nil if the actor is not authorized or a Hash with the parameters returned from the Policy if the actor is authorized.
|
10
|
+
# [<b><tt>authorize!(action, subject)</tt></b>] Returns a Hash returned by the Policy if the actor is authorized or raises a <tt>Walruz::NotAuthorized</tt> exception otherwise.
|
11
|
+
# [<b><tt>satisfies?(policy_label, subject)</tt></b>] Returns true or false if the Policy is satisfied with the actor and subject given.
|
12
|
+
# [<b><tt>satisfies(policy_label, subject)</tt></b>] Returns Either nil if the actor and subject don't satisfy the policy or a Hash with the parameters returned from the Policy.
|
13
|
+
#
|
7
14
|
module Actor
|
8
15
|
|
16
|
+
# @overload can?(action, subject)
|
17
|
+
# Allows an <em>actor</em> to check if he can perform an <em>action</em> on a given <em>subject</em>.
|
18
|
+
# === Note:
|
19
|
+
# This method will check the authorization the first time, following invocations will return a cached
|
20
|
+
# result unless the third parameter is specified.
|
21
|
+
#
|
22
|
+
# @param [Symbol] The action as it is declared on the <tt>check_authorizations</tt> method on the <em>subject</em> class.
|
23
|
+
# @param [Walruz::Subject] The <em>subject</em> on which the <em>actor</em> wants to execute the <em>action</em>.
|
24
|
+
# @param [Boolean] (optional) A boolean indicating if you want to reset the cached result.
|
25
|
+
# @return [Boolean] A boolean indicating if the <em>actor</em> is authorized to perform the <em>action</em> (or not) on the <em>subject</em>.
|
9
26
|
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
# Returns:
|
19
|
-
# It returns a boolean indicating that the actor is authorized to
|
20
|
-
# access (or not) the subject
|
27
|
+
# @overload can?(action, subject, reload)
|
28
|
+
# Allows an <em>actor</em> to check if he can perform an <em>action</em> on a given <em>subject</em>.
|
29
|
+
#
|
30
|
+
# @param [Symbol] The action as it is declared on the <tt>check_authorizations</tt> method on the <em>subject</em> class.
|
31
|
+
# @param [Walruz::Subject] The <em>subject</em> on which the <em>actor</em> wants to execute the <em>action</em>.
|
32
|
+
# @param [Boolean] A boolean indicating if you want to reset the cached result.
|
33
|
+
# @return [Boolean] A boolean indicating if the <em>actor</em> is authorized to perform the <em>action</em> (or not) on the <em>subject</em>.
|
21
34
|
#
|
22
35
|
def can?(*args)
|
23
36
|
if args.size == 2
|
@@ -34,17 +47,29 @@ module Walruz
|
|
34
47
|
end
|
35
48
|
|
36
49
|
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
50
|
+
# @overload authorize(action, subject)
|
51
|
+
# Allows an actor to check if he can do some action on a given
|
52
|
+
# subject. The main difference between this method and the <tt>can?</tt> method is that
|
53
|
+
# this will return a Hash of values returned by the policies, in case the <em>actor</em> is
|
54
|
+
# not authorized, it will return nil.
|
55
|
+
# === Note:
|
56
|
+
# This method will check the authorization the first time, following invocations will return a cached
|
57
|
+
# result unless the third parameter is specified.
|
58
|
+
#
|
59
|
+
# @param [Symbol] The action as it is declared on the <tt>check_authorizations</tt> method on the <em>subject</em> class.
|
60
|
+
# @param [Walruz::Subject] The <em>subject</em> on which the <em>actor</em> wants to execute the <em>action</em>.
|
61
|
+
# @return [Hash] Parameters returned from the <em>policy</em>.
|
62
|
+
#
|
63
|
+
# @overload authorize(action, subject, reload)
|
64
|
+
# Allows an actor to check if he can do some action on a given
|
65
|
+
# subject. The main difference between this method and the <tt>can?</tt> method is that
|
66
|
+
# this will return a Hash of values returned by the policies, in case the <em>actor</em> is
|
67
|
+
# not authorized, it will return nil.
|
68
|
+
#
|
69
|
+
# @param [Symbol] The action as it is declared on the <tt>check_authorizations</tt> method on the <em>subject</em> class.
|
70
|
+
# @param [Walruz::Subject] The <em>subject</em> on which the <em>actor</em> wants to execute the <em>action</em>.
|
71
|
+
# @param [Boolean] A boolean indicating if you want to reset the cached result.
|
72
|
+
# @return [Hash] Parameters returned from the <em>policy</em>.
|
48
73
|
def authorize(*args)
|
49
74
|
if args.size == 2
|
50
75
|
cached_values_for_can[args] ||= can_without_caching(*args)
|
@@ -62,29 +87,25 @@ module Walruz
|
|
62
87
|
end
|
63
88
|
end
|
64
89
|
|
65
|
-
# :nodoc:
|
66
90
|
def can_without_caching(label, subject)
|
67
91
|
subject.can_be?(label, self)
|
68
92
|
end
|
69
93
|
|
70
|
-
# :nodoc:
|
71
94
|
def cached_values_for_can
|
72
95
|
@_cached_values_for_can ||= {}
|
73
96
|
end
|
74
97
|
|
75
98
|
#
|
76
99
|
# Allows an actor to check if he can do some action on a given
|
77
|
-
# subject.
|
100
|
+
# subject. This method will behave similarly to the <tt>authorize</tt> method, the only difference is that
|
101
|
+
# instead of returning nil when the _actor_ is not authorized, it will raise a <tt>Walruz::NotAuthorized</tt> exception.
|
78
102
|
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
103
|
+
# @param [Symbol] The action as it is declared on the <tt>check_authorizations</tt> method on the <em>subject</em> class.
|
104
|
+
# @param [Walruz::Subject] The <em>subject</em> on which the <em>actor</em> wants to execute the <em>action</em>.
|
105
|
+
# @return [Hash] Parameters returned from the <em>policy</em>.
|
82
106
|
#
|
83
|
-
#
|
84
|
-
# Returns a a Hash with parameters given from the policy.
|
107
|
+
# @raise [Walruz::NotAuthorized] error if the <em>actor</em> is not authorized to perform the specified action on the <em>subject</em>.
|
85
108
|
#
|
86
|
-
# Raises:
|
87
|
-
# Walruz::NotAuthorized error if the actor can't execute the action on the subject
|
88
109
|
#
|
89
110
|
def authorize!(label, subject)
|
90
111
|
result = subject.can_be?(label, self)
|
@@ -99,29 +120,36 @@ module Walruz
|
|
99
120
|
end
|
100
121
|
|
101
122
|
#
|
102
|
-
# Allows an actor to check if he the
|
123
|
+
# Allows an <em>actor</em> to check if he satisfies the condition of a <em>policy</em> with a given <em>subject</em>.
|
103
124
|
#
|
104
125
|
# Params:
|
105
|
-
#
|
106
|
-
#
|
126
|
+
# @param [Symbol] The label of the <em>policy</em>.
|
127
|
+
# @param [Walruz::Subject] The <em>subject</em>.
|
128
|
+
# @return [Boolean] saying if the <em>actor</em> and the <em>subject</em> satisify the <em>policy</em>.
|
107
129
|
#
|
108
|
-
|
109
|
-
|
110
|
-
|
130
|
+
def satisfies?(policy_label, subject)
|
131
|
+
policy_clz = Walruz.fetch_policy(policy_label)
|
132
|
+
result = policy_clz.return_policy.new.safe_authorized?(self, subject)
|
133
|
+
result[0]
|
134
|
+
end
|
135
|
+
|
136
|
+
|
111
137
|
#
|
112
|
-
#
|
113
|
-
#
|
114
|
-
#
|
138
|
+
# Allows an <em>actor</em> to check if he satisfies the condition of a <em>policy</em> with a given <em>subject</em>.
|
139
|
+
#
|
140
|
+
# Params:
|
141
|
+
# @param [Symbol] The label of the <em>policy</em>.
|
142
|
+
# @param [Walruz::Subject] The <em>subject</em>.
|
143
|
+
# @return [Hash] Hash with the parameters returned from the <em>policy</em> if the <em>actor</em> and the <em>subject</em> satisfy the <em>policy</em>, nil otherwise.
|
115
144
|
#
|
116
|
-
def satisfies
|
117
|
-
policy_clz = Walruz.
|
118
|
-
raise ActionNotFound.new(:policy_label, :label => policy_label) if policy_clz.nil?
|
145
|
+
def satisfies(policy_label, subject)
|
146
|
+
policy_clz = Walruz.fetch_policy(policy_label)
|
119
147
|
result = policy_clz.return_policy.new.safe_authorized?(self, subject)
|
120
|
-
|
121
|
-
block.call(result[1]) if block_given?
|
122
|
-
end
|
123
|
-
result[0]
|
148
|
+
result[0] ? result[1] : nil
|
124
149
|
end
|
125
150
|
|
151
|
+
|
152
|
+
protected :can_without_caching, :cached_values_for_can
|
153
|
+
|
126
154
|
end
|
127
155
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Walruz
|
2
|
+
module CoreExt
|
3
|
+
module Array
|
4
|
+
|
5
|
+
# @overload only_authorized_for(actor, options = {})
|
6
|
+
# Filters the +Walruz::Subject+ elements inside an array either by a policy or by an action on the _subject_.
|
7
|
+
# This will execute the authorization policies using specified _actor_ and action/policy.
|
8
|
+
# === Notes:
|
9
|
+
# * If a policy is given, you have to use the policy label.
|
10
|
+
# * If an action is given, you have to use the name of the action declared on the subject.
|
11
|
+
#
|
12
|
+
# @param [Walruz::Actor] actor The _actor_ that is going to be used on the authorization process
|
13
|
+
#
|
14
|
+
# @param [Hash] opts for the filtering process.
|
15
|
+
# @option opts [Symbol] :action The name of the action to be executed on the list of subjects.
|
16
|
+
# @option opts [Symbol] :policy The label of an specific policy that is going to be used.
|
17
|
+
#
|
18
|
+
# @return [Array<Walruz::Subject>] An array with the authorized subjects.
|
19
|
+
#
|
20
|
+
# @raise [Walruz::ActionNotFound] if the opts[:action] is not specified on the subject or
|
21
|
+
# if the opts[:policy] label identifying the policy is not recognized
|
22
|
+
#
|
23
|
+
# @example Filtering a list of Posts by the read action specified on the Post class
|
24
|
+
# Post.all.only_authorized_for(current_user, :action => :read)
|
25
|
+
# # this will execute current_user.can?(:read, post) for each element of the array
|
26
|
+
#
|
27
|
+
# @example Filtering a list of Posts by a policy
|
28
|
+
# Post.all.only_authorized_for(nil, :policy => :public_policy)
|
29
|
+
# # This will execute the Policy with the label ":public_policy" on every post using the given actor
|
30
|
+
#
|
31
|
+
# @overload only_authorized_for(actor, action)
|
32
|
+
# Filters the +Walruz::Subject+ elements inside an array by the action specified.
|
33
|
+
# This will execute the authorization policies using specified actor and action on each _subject_ of the +Array+.
|
34
|
+
#
|
35
|
+
# @param [Walruz::Actor] actor The _actor_ that is going to be used on the authorization process
|
36
|
+
#
|
37
|
+
# @param [Symbol] action to be executed by the _actor_ on each _subject_ in the list.
|
38
|
+
#
|
39
|
+
# @return [Array<Walruz::Subject>] An array with the authorized of _subjects_.
|
40
|
+
#
|
41
|
+
# @raise [Walruz::ActionNotFound] if the _action_ specified is not declaredon the _subject_.
|
42
|
+
#
|
43
|
+
# @example Filtering a list of Posts by the read action specified on the Post class
|
44
|
+
# Post.all.only_authorized_for(current_user, :read)
|
45
|
+
# # this will execute current_user.can?(:read, post) for each element of the array
|
46
|
+
#
|
47
|
+
def only_authorized_for(actor, opts = {})
|
48
|
+
if opts.respond_to?(:[])
|
49
|
+
only_authorized_with_options(actor, opts)
|
50
|
+
else # use the opts
|
51
|
+
only_authorized_on_action(actor, opts)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
|
57
|
+
def only_authorized_with_options(actor, opts)
|
58
|
+
raise ArgumentError.new("You have to specify either the :action or :policy option") if opts[:action] && opts[:policy]
|
59
|
+
if opts[:action]
|
60
|
+
self.select do |subject|
|
61
|
+
actor.can?(opts[:action], subject)
|
62
|
+
end
|
63
|
+
elsif opts[:policy]
|
64
|
+
policy_clz = Walruz.fetch_policy(opts[:policy])
|
65
|
+
self.select(&policy_clz.with_actor(actor))
|
66
|
+
else
|
67
|
+
raise ArgumentError.new("The option hash requires either :action or :policy option")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def only_authorized_on_action(actor, action)
|
72
|
+
self.select do |subject|
|
73
|
+
actor.can?(action, subject)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|