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 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
- - Subject: Object that is going to be managed (Profile, Posts)
8
- - Actor: Entity that wants to perform an action on a subject (User, Admin)
9
- - Policy: A set of rules that tells if the Actor can perform the desired action on the Subject
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
- - Walruz::Subject
16
- Module that provides the interface to associate policies to an action in the subject
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
- - Walruz::Actor
19
- Module that provides the interface to perform queries to validate if an action can be done between the
20
- actor and the subject
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
- - Walruz::Policy
23
- Class that provides the interface to implement authorization logic
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, you may specify the :default action, or just specify the Policy class.
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. This are:
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
- - `can?(action, subject)`
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
- - `authorize(action, subject)`
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
- - `satisfies?(policy_label, subject)`
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, a default Policy will be executed (if given), if no default policy is given then a Walruz::ActionNotFound exception will be raised.
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?(:actor_is_admin, nil) do
84
- # execute some admin logic
85
- end
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, it is necessary to inherit from the Walruz::Policy class. This class provides a method called `authorized?` 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.
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 `set_policy_label` method on the class context and specify the label that you want for it. This label is used on the `satisfies?` method.
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 `any` and `not`, to create combinations of policies.
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 `all` method, the parameters of each policy will be merged together, if you are using the `any` method, the parameters of the first policy that returns true will be returned.
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, every policy 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
+ 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 `UserAllowsDisclosureOfPictures` 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 policy as:
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 `params` method.
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, but to the association of a subject. 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
+ 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, but that policy only works when the subject is of class User; given that you have a subject of class Picture you can not re-use this policy.
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 `PolicyClass.for_subject` method:
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 `but_for` is the name of the subject's method that will return a new subject, this new subject is then passed through the policy. Pretty neat eh?
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 `authorized?` method passing a hash with a :error_message key on the false return. If you use the `can!` method on the actor model, this will become the `Walruz::NotAuthorized` error message.
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, the policy class name should start with the Actor word (e.g. ActorIsAdmin)
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 `UserDeletePolicy = any(ActorIsSubject, ActorIsAdmin`))
259
- - Use `PolicyClass.but_for` when you are combining the PolicyClass with other policies, if you are not doing this, consider checking authorizations on parents of the subject instead of the subject (e.g. current_user.can?(:see_pictures_of, picture.owner))
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 "walruz-rails":http://walruz-rails.rubyforge.com gem
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
- Copyright (c) 2009 Noomii inc. <http://www.noomii.com>
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
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :major: 0
3
3
  :minor: 0
4
- :patch: 6
4
+ :patch: 7
data/lib/walruz/actor.rb CHANGED
@@ -1,23 +1,36 @@
1
1
  module Walruz
2
2
 
3
3
  #
4
- # Actors have the role to use subjects, so they are the ones
5
- # who can or cannot do something with a given subject
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
- # Allows an actor to check if he can do some action on a given
11
- # subject. It is normally used with a block that get's executed if the
12
- # actor can execute the given action on the subject.
13
- #
14
- # Params:
15
- # - label: The label of the action
16
- # - subject: The subject which the actor wants to interact with
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
- # Allows an actor to check if he can do some action on a given
39
- # subject.
40
- #
41
- # Params:
42
- # - label: The label of the action
43
- # - subject: The subject which the actor wants to interact with
44
- #
45
- # Returns:
46
- # Returns a a Hash with parameters given from the policy.
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
- # Params:
80
- # - label: The label of the action
81
- # - subject: The subject which the actor wants to interact with
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
- # Returns:
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 given policy applies to him and the given subject.
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
- # - policy: label of the Policy the actor wants to check
106
- # - subject: The subject which the actor wants to interact with
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
- # block |policy_hash|:
109
- # If the actor can access the subject, then the block will be executed;
110
- # this will receive the policy hash as a parameter.
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
- # Returns:
113
- # It returns a boolean indicating that the actor is authorized to
114
- # access (or not) the subject with the given Policy.
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?(policy_label, subject, &block)
117
- policy_clz = Walruz.policies[policy_label]
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
- if result[0]
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