Class: SecurityContext
Overview
SecurityContext
The SecurityContext provides methods for all security concerns of the current request.
For every request, it has to be initialized using #current_user=. It is recommended to do this in a security filter, which can be used to catch AnnotationSecurityExceptions as well.
The SecurityContext is implemented as a singleton for the current thread. Thus, all instance methods can be send to the class as well.
Defined Under Namespace
Classes: SecurityContextDummy
Class Method Summary collapse
-
.current ⇒ Object
Returns current security context.
-
.ignore_security! ⇒ Object
Disables all security checkings.
-
.initialize(controller) ⇒ Object
At the begin of a request, the security context will be initialized for the current controller.
-
.load(sec_context) ⇒ Object
As the security context is a singleton bound to the current thread, it will not be available in other threads.
-
.raise_access_denied(*policy_args) ⇒ Object
Raise a SecurityViolationError.
-
.without_security!(&block) ⇒ Object
Runs a given block with security disabled.
Instance Method Summary collapse
-
#allow_action?(*args) ⇒ Boolean
Checks the rules of an other action.
-
#allowed?(*policy_args) ⇒ Boolean
(also: #is?)
Returns true iif the operation defined by
policy_args
is allowed. -
#apply_context_rules(*res_args) ⇒ Object
(also: #apply_rules)
Applies all rules of the current action to the resource defined by
resource_args
. -
#apply_param_rules ⇒ Object
:nodoc:.
-
#apply_rule(*args) ⇒ Object
Raises a SecurityViolationError if the rule defined by
policy_args
is not allowed. -
#apply_rules_after_action ⇒ Object
:nodoc:.
-
#apply_rules_before_action ⇒ Object
:nodoc:.
-
#apply_static_rules ⇒ Object
Applies all system and pretest rules of the current action.
-
#apply_var_rules ⇒ Object
:nodoc:.
-
#copy ⇒ Object
Creates a copy of the current security context.
-
#credential ⇒ Object
(also: #current_credential)
Get the current credential.
-
#credential=(user) ⇒ Object
(also: #current_credential=)
Sets the current user.
- #enabled? ⇒ Boolean
-
#eval_with_security(rules) ⇒ Object
Evaluates the given block, additionally using the given rules.
-
#initialize(controller) ⇒ SecurityContext
constructor
Initialize context for the given controller.
-
#log!(&proc) ⇒ Object
Activates access logging for the current request.
-
#log_access_denied(policy_args) ⇒ Object
:nodoc:.
-
#observe(*resource_args) ⇒ Object
Call if a resource object was touched during an action.
-
#security_exception ⇒ Object
If the action was aborted due to a security exception, this returns the exception that was raised.
-
#security_exception=(ex) ⇒ Object
Will be set if an security exception was catched by the security filter.
-
#send_with_security(rules, obj, msg, *args, &proc) ⇒ Object
See eval_with_security.
Constructor Details
#initialize(controller) ⇒ SecurityContext
Initialize context for the given controller
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/security_context.rb', line 67 def initialize(controller) # :nodoc: super() @controller = controller # initialize rule # rules that are not bound to any source, # will be triggered by model observer @context_rules = new_rules_hash @valid_objects = new_valid_objects_hash # rules bound to request param @param_rules = new_bound_rules_hash @param_valid_objects = new_bound_valid_objects_hash # rules bound to variable @var_rules = new_bound_rules_hash @var_valid_objects = new_bound_valid_objects_hash # Hash with all required policies @policies = new_policy_hash end |
Class Method Details
.current ⇒ Object
Returns current security context
23 24 25 |
# File 'lib/security_context.rb', line 23 def self.current Thread.current[:security_context] end |
.ignore_security! ⇒ Object
Disables all security checkings. Is only available in development mode.
55 56 57 58 59 |
# File 'lib/security_context.rb', line 55 def self.ignore_security! security_methods.each do |method| class_eval "def self.#{method}(*args); true; end" end end |
.initialize(controller) ⇒ Object
At the begin of a request, the security context will be initialized for the current controller.
30 31 32 |
# File 'lib/security_context.rb', line 30 def self.initialize(controller) # :nodoc: load(new(controller)) end |
.load(sec_context) ⇒ Object
As the security context is a singleton bound to the current thread, it will not be available in other threads. The following example shows how to use the security context inside of a spawn block
copy = SecurityContext.copy
spawn do
SecurityContext.load(copy)
begin
# ...
rescue SecurityViolationError
puts 'Security was violated'
end
end
48 49 50 |
# File 'lib/security_context.rb', line 48 def self.load(sec_context) Thread.current[:security_context] = sec_context end |
.raise_access_denied(*policy_args) ⇒ Object
Raise a SecurityViolationError. See allowed? for details on policy_args
.
322 323 324 325 |
# File 'lib/security_context.rb', line 322 def self.raise_access_denied(*policy_args) log_access_denied(policy_args) raise SecurityViolationError.access_denied(credential,*policy_args) end |
.without_security!(&block) ⇒ Object
Runs a given block with security disabled. Inside the block, the context will be disabled for the current thread.
564 565 566 567 568 569 570 571 |
# File 'lib/security_context.rb', line 564 def self.without_security!(&block) old_current = current load(SecurityContextDummy.new(old_current.credential)) return_value = yield load old_current return_value end |
Instance Method Details
#allow_action?(*args) ⇒ Boolean
Checks the rules of an other action. Note that rules that are bound to a variable can not be checked.
Parameters
-
controller
Symbol representing the controller, like :resource -
action
The called action, like :update -
objects
(optional) List of objects that will be relevant for that action. -
params
(optional) Hash of the passed parameters, like :id => 1.
Examples
Checks static and pretest rules.
allow_action? :resource, :create
# => true if the current user may execute ResourcesController#create
Checks static, pretest and context rules
allow_action? :resource, :edit, [@resource]
# => true if the current user may execute ResourcesController#edit,
# assuming that @resource will be used in that action
Checks static, pretest and context rules and all rules that are bound to :id.
allow_action? :resource, :edit, [@resource], {:id => 4}
# => true if the current user may execute ResourcesController#edit,
# assuming that @resource will be used in that action
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
# File 'lib/security_context.rb', line 252 def allow_action?(*args) # :nodoc: controller, action, objects, params = AnnotationSecurity::Utils.parse_action_args(args) # var rules are ignored here context_rules, param_rules, _ = get_rule_set(controller, action) # check static rules evaluate_statically(context_rules) # check context rules for all objects objects.each do |o| res_type = o.resource_type evaluate_context_rules(context_rules, res_type, o) end evaluate_bound_rules_for_params(param_rules, params) true rescue SecurityViolationError return false end |
#allowed?(*policy_args) ⇒ Boolean Also known as: is?
Returns true iif the operation defined by policy_args
is allowed.
The following calls to #allowed? are allowed:
allowed? :show, :resource, @resource
# => true if the current user has the right to show @resource,
# which belongs to the :resource resource-class
In case of model objects or other classes which implement a #resource_type method the the second argument may be ommited
allowed? :show, @resource
# equivalent to the above call if @resource.resource_type == :resource
A policy description used as a controller annotation may also be to check a right
allowed? "show resource", @resource
# => true if the current user has the right "show resource" for @resource
A policy may also be applied without an object representing the context:
allowed? :show, :resource
# => true if the current may show resources.
This will only check system and pretest rules. The result true
does not mean that the user may show all resources. However, a false
indicates that the user is not allowed to show any resources.
If the resource type is omitted as well, only rules defined for all resources can be tested. See RelationLoader#all_resources for details.
allowed? :administrate
# => true if the user is allowed to administrate all resources.
206 207 208 209 |
# File 'lib/security_context.rb', line 206 def allowed?(*policy_args) policy_args = AnnotationSecurity::Utils.parse_policy_arguments(policy_args) __allowed?(*policy_args) end |
#apply_context_rules(*res_args) ⇒ Object Also known as: apply_rules
Applies all rules of the current action to the resource defined by resource_args
. Raises a SecurityViolationError if a rule is violated.
295 296 297 298 |
# File 'lib/security_context.rb', line 295 def apply_context_rules(*res_args) # :nodoc: restype, res = AnnotationSecurity::Utils.parse_resource_arguments(res_args) evaluate_context_rules(@context_rules, restype, res) end |
#apply_param_rules ⇒ Object
:nodoc:
283 284 285 |
# File 'lib/security_context.rb', line 283 def apply_param_rules # :nodoc: evaluate_bound_rules(@param_rules, @param_valid_objects) end |
#apply_rule(*args) ⇒ Object
Raises a SecurityViolationError if the rule defined by policy_args
is not allowed. See allowed? for details.
222 223 224 |
# File 'lib/security_context.rb', line 222 def apply_rule(*args) self.class.raise_access_denied(*args) unless allowed?(*args) end |
#apply_rules_after_action ⇒ Object
:nodoc:
166 167 168 169 |
# File 'lib/security_context.rb', line 166 def apply_rules_after_action # :nodoc: # check again, bindings may have been changed apply_var_rules end |
#apply_rules_before_action ⇒ Object
:nodoc:
158 159 160 161 162 163 164 |
# File 'lib/security_context.rb', line 158 def apply_rules_before_action # :nodoc: # apply static rules before entering the action apply_static_rules # bindings may apply to parameters, try to check them too apply_param_rules apply_var_rules end |
#apply_static_rules ⇒ Object
Applies all system and pretest rules of the current action. Raises a SecurityViolationError if a rule is violated.
279 280 281 |
# File 'lib/security_context.rb', line 279 def apply_static_rules # :nodoc: evaluate_statically(@context_rules) end |
#apply_var_rules ⇒ Object
:nodoc:
287 288 289 |
# File 'lib/security_context.rb', line 287 def apply_var_rules # :nodoc: evaluate_bound_rules(@var_rules, @var_valid_objects) end |
#copy ⇒ Object
Creates a copy of the current security context. See #load for more information.
114 115 116 |
# File 'lib/security_context.rb', line 114 def copy returning self.class.new(@controller) { |sc| sc.credential = credential } end |
#credential ⇒ Object Also known as: current_credential
Get the current credential
105 106 107 |
# File 'lib/security_context.rb', line 105 def credential @credential end |
#credential=(user) ⇒ Object Also known as: current_credential=
Sets the current user. This has to be done in a before or around filter, before entering the action. Elsewise, the user will be interpreted as not being logged in. Once set, the current user cannot be changed.
95 96 97 98 99 100 101 102 |
# File 'lib/security_context.rb', line 95 def credential=(user) if @cred_set raise AnnotationSecurity::AnnotationSecurityError, "Credential already set for this request" end @cred_set = true @credential = user end |
#enabled? ⇒ Boolean
557 558 559 |
# File 'lib/security_context.rb', line 557 def enabled? true end |
#eval_with_security(rules) ⇒ Object
Evaluates the given block, additionally using the given rules.
rules == [ { :action => action, :resource => res_type, :source => binding }, ...]
action and res_type should be symbols, binding is optional
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/security_context.rb', line 140 def eval_with_security(rules) install_rules(rules) apply_rules_before_action result = yield apply_rules_after_action result rescue AnnotationSecurity::SecurityError SecurityContext.security_exception = $! raise $! ensure uninstall_rules(rules) result end |
#log!(&proc) ⇒ Object
Activates access logging for the current request.
329 330 331 332 333 334 335 336 |
# File 'lib/security_context.rb', line 329 def log!(&proc) @enable_logging = true @log = proc || Proc.new do |result, action, res_type, resource| result = result ? 'ALLOWED' : 'REFUSED' unless result.is_a? String msg = "%-8s %-10s %-16s %s" % [result, action, res_type, resource] puts msg end end |
#log_access_denied(policy_args) ⇒ Object
:nodoc:
338 339 340 |
# File 'lib/security_context.rb', line 338 def log_access_denied(policy_args) # :nodoc: @log.call('DENIED!', *policy_args) if @enable_logging end |
#observe(*resource_args) ⇒ Object
Call if a resource object was touched during an action. Will be called automatically for model objects.
Applies all rules that are currently active to the resource defined by resource_args
. Raises a SecurityViolationError if a rule is violated.
Usage
observe :resource, @resource
where :resource
is the resource type @resource belongs to, or
observe @resource
which is equivalent if @resource.resource_name == :resource
315 316 317 |
# File 'lib/security_context.rb', line 315 def observe(*resource_args) apply_context_rules(*resource_args) end |
#security_exception ⇒ Object
If the action was aborted due to a security exception, this returns the exception that was raised. Returns nil if no exception occurred.
127 128 129 |
# File 'lib/security_context.rb', line 127 def security_exception @security_exception end |
#security_exception=(ex) ⇒ Object
Will be set if an security exception was catched by the security filter
119 120 121 122 |
# File 'lib/security_context.rb', line 119 def security_exception=(ex) # :nodoc: @security_exception = ex @controller.security_exception = ex end |
#send_with_security(rules, obj, msg, *args, &proc) ⇒ Object
See eval_with_security.
132 133 134 |
# File 'lib/security_context.rb', line 132 def send_with_security(rules, obj, msg, *args, &proc) eval_with_security(rules) { obj.send(msg, *args, &proc) } end |