Class: AnnotationSecurity::AbstractPolicy
- Defined in:
- lib/annotation_security/policy/abstract_policy.rb
Overview
Abstract superclass for all policies
For each resource type there is a corresponding policy class. In its entire lifetime, a policy object is responsible for a single user. A policy object can validate the rights for only one resource object at a time (it is not thread safe!).
Direct Known Subclasses
Class Method Summary collapse
-
.add_rule(symbol, *args, &block) ⇒ Object
Add a rule *
symbol
rule name *args
additional arguments *block
code block See AnnotationSecurity::Rule#initialize for details. -
.all_resources_policy ⇒ Object
Rules that are defined for all resource types can be found here.
-
.classname_suffix ⇒ Object
Suffix that is appended to the camlized resource type to generate a class name.
-
.copy_rule_from(symbol, source_policy) ⇒ Object
If possible, copies a rule from another policy class.
-
.forbidden_rule_names ⇒ Object
List of strings that are not allowed as rule names (maybe incomplete).
-
.get_rule(symbol) ⇒ Object
Get a rule object *
symbol
Name of the rule. -
.has_dynamic_rule?(symbol) ⇒ Boolean
Return true iif the rule can be evaluated dynamically *
symbol
Name of the rule. -
.has_rule?(symbol) ⇒ Boolean
Returns true iif this policy can evaluate the rule *
symbol
Name of the rule. -
.has_static_rule?(symbol) ⇒ Boolean
Returns true iif the rule can be evaluated statically *
symbol
Name of the rule. -
.initialize(resource_type) ⇒ Object
Initializes a subclass of AbstractPolicy.
-
.load_rule(symbol) ⇒ Object
The rule
symbol
was requested, try to find and load it. -
.new_subclass(resource_type) ⇒ Object
Creates a new policy class for a resource type.
-
.reset ⇒ Object
(Re-)Initializes the policy class.
-
.resource_type ⇒ Object
Symbol representing the resource type this policy is responsible for.
-
.rule_set ⇒ Object
Rule set for this classes resource type.
-
.static? ⇒ Boolean
Returns true iif this is policy class is responsible for static rules.
-
.static_policy_class ⇒ Object
The corresponding static policy class.
-
.use_static_rule(symbol) ⇒ Object
If possible, redirects the rule to the static side.
Instance Method Summary collapse
-
#add_method_for_rule(symbol) ⇒ Object
Return true if it was possible to create a method for the rule *
symbol
Name of the method. -
#all_for_role(user, role_name) ⇒ Object
Return objects for the requested role.
-
#allowed?(right, resource_obj, *args) ⇒ Boolean
Returns true iif the user has the
right
forresource_obj
*right
symbol *resource_obj
resource object to test the right for *args
(optional) additional arguments passed when evaluating the right This is not thread safe! Don’t share policy objects between different threads (should be no problem though). -
#evaluate(rules) ⇒ Object
Evalutates all rules.
-
#evaluate_dynamically(rules) ⇒ Object
Evaluate the rules in dynamic mode.
-
#evaluate_rule(symbol, user, args) ⇒ Object
Evaluate a rule that is defined with a proc *
symbol
Name of the rule *user
user object that has to fulfill the rule *args
List of additional arguments. -
#evaluate_statically(rules) ⇒ Object
Evaluate the rules in static mode.
-
#get_rule(symbol) ⇒ Object
Returns a rule object or nil if it does not exist *
symbol
Name of the rule. -
#get_rule!(symbol) ⇒ Object
Returns a rule object or raises an exception.
-
#has_rule?(symbol) ⇒ Boolean
Returns true iif this policy can evaluate this rule *
symbol
Name of the rule. -
#initialize(user, resource = nil) ⇒ AbstractPolicy
constructor
Initialize the instance for a user *
user
user object this policy object is responsible for *resource
(optional) usually the resource object will be set using #allowed? or #with_resource. -
#method_missing(symbol, *args) ⇒ Object
Invoked by ruby when this object recieved a message it cannot handle.
-
#raise_access_denied(rule) ⇒ Object
:nodoc:.
-
#raise_rule_missing(symbol) ⇒ Object
Raises an error saying that a rule could not be found this policy class *
symbol
Name of the rule. -
#resource_type ⇒ Object
Symbol representing the resource type this policy is responsible for.
-
#static_policy ⇒ Object
Static policy object to evaluate the static rules.
-
#user_roles(symbol, require_user) ⇒ Object
Returns a list of user wrappers for a role.
-
#with_resource(resource_obj) ⇒ Object
Sets the resource object and returns self ==== Example policy.with_resource(obj).show? #=> true or false.
Constructor Details
#initialize(user, resource = nil) ⇒ AbstractPolicy
Initialize the instance for a user
-
user
user object this policy object is responsible for -
resource
(optional) usually the resource object will be set using#allowed? or #with_resource
169 170 171 172 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 169 def initialize(user,resource=nil) @user = user @resource = resource end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(symbol, *args) ⇒ Object
Invoked by ruby when this object recieved a message it cannot handle.
-
symbol
Name of the method -
args
Any arguments that were passed
302 303 304 305 306 307 308 309 310 311 312 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 302 def method_missing(symbol,*args) # :nodoc: # If possible, create the missing method and send it again if add_method_for_rule(symbol) # method was created, try again return __send__(symbol,*args) end # this will fail and an exception will be raised get_rule!(symbol) end |
Class Method Details
.add_rule(symbol, *args, &block) ⇒ Object
Add a rule
-
symbol
rule name -
args
additional arguments -
block
code block
See AnnotationSecurity::Rule#initialize for details
161 162 163 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 161 def self.add_rule(symbol,*args,&block) #:nodoc: rule_set.add_rule(symbol,*args,&block) end |
.all_resources_policy ⇒ Object
Rules that are defined for all resource types can be found here. (Overwritten by static policy)
72 73 74 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 72 def self.all_resources_policy # :nodoc: AllResourcesPolicy end |
.classname_suffix ⇒ Object
Suffix that is appended to the camlized resource type to generate a class name.
42 43 44 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 42 def self.classname_suffix # :nodoc: static? ? 'StaticPolicy' : 'Policy' end |
.copy_rule_from(symbol, source_policy) ⇒ Object
If possible, copies a rule from another policy class.
-
symbol
Name of the rule -
source_policy
policy class to copy from
Returns a rule object or nil.
142 143 144 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 142 def self.copy_rule_from(symbol,source_policy) # :nodoc: rule_set.copy_rule_from(symbol,source_policy.rule_set,static?) end |
.forbidden_rule_names ⇒ Object
List of strings that are not allowed as rule names (maybe incomplete).
66 67 68 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 66 def self.forbidden_rule_names # :nodoc: instance_methods end |
.get_rule(symbol) ⇒ Object
Get a rule object
-
symbol
Name of the rule
120 121 122 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 120 def self.get_rule(symbol) #:nodoc: @my_rules[symbol] end |
.has_dynamic_rule?(symbol) ⇒ Boolean
Return true iif the rule can be evaluated dynamically
-
symbol
Name of the rule
114 115 116 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 114 def self.has_dynamic_rule?(symbol) # :nodoc: @has_dynamic[symbol] end |
.has_rule?(symbol) ⇒ Boolean
Returns true iif this policy can evaluate the rule
-
symbol
Name of the rule
102 103 104 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 102 def self.has_rule?(symbol) # :nodoc: @has_rule[symbol] end |
.has_static_rule?(symbol) ⇒ Boolean
Returns true iif the rule can be evaluated statically
-
symbol
Name of the rule
108 109 110 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 108 def self.has_static_rule?(symbol) # :nodoc: static_policy_class.has_rule? symbol end |
.initialize(resource_type) ⇒ Object
Initializes a subclass of AbstractPolicy
24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 24 def self.initialize(resource_type) #:nodoc: @resource_type = resource_type.to_s.underscore.to_sym # register the class as constant name = resource_type.to_s.camelize + classname_suffix Object.const_set name, self unless static? # Each policy has a static partner @static_policy_class = AnnotationSecurity::AbstractStaticPolicy.new_subclass(@resource_type) @static_policy_class.belongs_to self reset end end |
.load_rule(symbol) ⇒ Object
The rule symbol
was requested, try to find and load it. Returns a rule object or nil.
126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 126 def self.load_rule(symbol) #:nodoc: # 1. Have a look in the rule set # 2. Maybe the rule is defined for all resources # 3. Redirect the rule to the static side r = rule_set.get_rule(symbol,static?) || copy_rule_from(symbol,all_resources_policy) || use_static_rule(symbol) # Create a method for the rule r.extend_class(self) if r r end |
.new_subclass(resource_type) ⇒ Object
Creates a new policy class for a resource type.
16 17 18 19 20 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 16 def self.new_subclass(resource_type) #:nodoc: Class.new(self).tap do |c| c.initialize(resource_type) end end |
.reset ⇒ Object
(Re-)Initializes the policy class. Removes all generated methods and clears the rule set.
49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 49 def self.reset # :nodoc: instance_methods(false).each { |m| remove_method m } @has_rule = Hash.new {|h,k| h[k] = !get_rule(k).nil?} @my_rules = Hash.new {|h,k| h[k] = load_rule(k)} unless static? # set of all rule objects available for this policy @rule_set = AnnotationSecurity::RuleSet.new(self) # {:rule => boolean} if true, the rule can be evaluated statically only @static_only = Hash.new(false) # {:rule => boolean} if true, the rule can be evaluated dynamically @has_dynamic = Hash.new {|h,k| h[k] = has_rule?(k) && !@static_only[k]} @static_policy_class.reset end end |
.resource_type ⇒ Object
Symbol representing the resource type this policy is responsible for.
78 79 80 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 78 def self.resource_type # :nodoc: @resource_type end |
.rule_set ⇒ Object
Rule set for this classes resource type
96 97 98 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 96 def self.rule_set # :nodoc: @rule_set end |
.static? ⇒ Boolean
Returns true iif this is policy class is responsible for static rules.
90 91 92 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 90 def self.static? # :nodoc: false end |
.static_policy_class ⇒ Object
The corresponding static policy class.
84 85 86 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 84 def self.static_policy_class # :nodoc: @static_policy_class end |
.use_static_rule(symbol) ⇒ Object
If possible, redirects the rule to the static side. Returns a rule object or nil.
148 149 150 151 152 153 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 148 def self.use_static_rule(symbol) #:nodoc: if has_static_rule?(symbol) @static_only[symbol] = true rule_set.create_dynamic_copy(symbol) end end |
Instance Method Details
#add_method_for_rule(symbol) ⇒ Object
Return true if it was possible to create a method for the rule
-
symbol
Name of the method
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 316 def add_method_for_rule(symbol) # :nodoc: # Check if symbol is a known rule. If available, it will be loaded and # a method will be created automatically. if has_rule?(symbol) # method was created return true else # Remove prefix or suffix if available cleaned = AnnotationSecurity::Utils.method_body(symbol) if cleaned # Redirect to the cleaned method self.class.class_eval "def #{symbol}(*args); #{cleaned}(*args); end" return true end end # Hopeless false end |
#all_for_role(user, role_name) ⇒ Object
Return objects for the requested role. The role(s) will be determined with sending user.as_’role’. (Normally a user has a role only once, however it will work when he has many roles of the same kind as well)
281 282 283 284 285 286 287 288 289 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 281 def all_for_role(user,role_name) # :nodoc: return [] if user.nil? # is it possible that user is a role? if so, implement conversion to user return [user] if role_name.nil? roles = user.__send__("as_#{role_name}") return [] if roles.blank? roles = [roles] unless roles.is_a?(Array) roles.compact end |
#allowed?(right, resource_obj, *args) ⇒ Boolean
Returns true iif the user has the right
for resource_obj
-
right
symbol -
resource_obj
resource object to test the right for -
args
(optional) additional arguments passed when evaluating the right
This is not thread safe! Don’t share policy objects between different threads (should be no problem though).
Example
policy.allowed? :show, obj #=> true or false
193 194 195 196 197 198 199 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 193 def allowed?(right,resource_obj,*args) @resource = resource_obj __send__(right,*args) # rescue # raise "#{$!} in #{resource_type} policy " + # "during rule #{right} of #{resource_obj} with args [#{args.join(", ")}]" end |
#evaluate(rules) ⇒ Object
Evalutates all rules.
-
rules
array of symbols
Throws a SecurityViolationError if a rule fails, returns true if all rules succeed.
236 237 238 239 240 241 242 243 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 236 def evaluate(rules) #:nodoc: rules.each do |rule| unless __send__(rule) raise_access_denied(rule) end end true end |
#evaluate_dynamically(rules) ⇒ Object
Evaluate the rules in dynamic mode. Rules that cannot be evaluated are skipped.
-
rules
array of symbols
Throws a SecurityViolationError if a rule fails, returns true if all rules succeed.
223 224 225 226 227 228 229 230 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 223 def evaluate_dynamically(rules) #:nodoc: rules.each do |rule| if self.class.has_dynamic_rule?(rule) && !__send__(rule) raise_access_denied(rule) end end true end |
#evaluate_rule(symbol, user, args) ⇒ Object
Evaluate a rule that is defined with a proc
-
symbol
Name of the rule -
user
user object that has to fulfill the rule -
args
List of additional arguments
295 296 297 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 295 def evaluate_rule(symbol,user,args) # :nodoc: get_rule!(symbol).evaluate(self,user,@resource,*args) end |
#evaluate_statically(rules) ⇒ Object
Evaluate the rules in static mode. Rules that cannot be evaluated are skipped.
-
rules
array of symbols
Throws a SecurityViolationError if a rule fails, returns true if all rules succeed.
214 215 216 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 214 def evaluate_statically(rules) #:nodoc: static_policy.evaluate_statically(rules) end |
#get_rule(symbol) ⇒ Object
Returns a rule object or nil if it does not exist
-
symbol
Name of the rule
259 260 261 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 259 def get_rule(symbol) # :nodoc: self.class.get_rule(symbol) end |
#get_rule!(symbol) ⇒ Object
Returns a rule object or raises an exception.
-
symbol
Name of the rule
253 254 255 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 253 def get_rule!(symbol) # :nodoc: get_rule(symbol) or raise_rule_missing(symbol) end |
#has_rule?(symbol) ⇒ Boolean
Returns true iif this policy can evaluate this rule
-
symbol
Name of the rule
247 248 249 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 247 def has_rule?(symbol) self.class.has_rule? symbol end |
#raise_access_denied(rule) ⇒ Object
:nodoc:
341 342 343 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 341 def raise_access_denied(rule) #:nodoc: SecurityContext.raise_access_denied(rule,resource_type,@resource) end |
#raise_rule_missing(symbol) ⇒ Object
Raises an error saying that a rule could not be found this policy class
-
symbol
Name of the rule
337 338 339 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 337 def raise_rule_missing(symbol) # :nodoc: raise AnnotationSecurity::RuleNotFoundError.for_rule(symbol,self.class) end |
#resource_type ⇒ Object
Symbol representing the resource type this policy is responsible for.
181 182 183 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 181 def resource_type # :nodoc: self.class.resource_type end |
#static_policy ⇒ Object
Static policy object to evaluate the static rules
175 176 177 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 175 def static_policy # :nodoc: @static_policy ||= self.class.static_policy_class.new(@user) end |
#user_roles(symbol, require_user) ⇒ Object
Returns a list of user wrappers for a role. See #all_for_role for details.
-
symbol
Name of the role -
require_user
(boolean) Indicating if the rule that requested the roles requires a user for evaluation. If @user is nil andrequire_user
is true, an empty array is returned, which will make the rule fail immediately. Ifrequire_user
is false, an array containing nil is returned and the rule will be evaluated once (withnil
as current user).
271 272 273 274 275 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 271 def user_roles(symbol,require_user) # :nodoc: return [nil] if @user.nil? && !require_user # AnnotationSecurity::UserWrapper.all_for_role(@user,symbol) all_for_role(@user,symbol) end |
#with_resource(resource_obj) ⇒ Object
Sets the resource object and returns self
Example
policy.with_resource(obj).show? #=> true or false
204 205 206 207 |
# File 'lib/annotation_security/policy/abstract_policy.rb', line 204 def with_resource(resource_obj) @resource = resource_obj self end |