Class: Shamu::Security::Policy
- Inherits:
-
Object
- Object
- Shamu::Security::Policy
- Includes:
- Roles
- Defined in:
- lib/shamu/security/policy.rb
Overview
...
Direct Known Subclasses
Dependencies collapse
-
#principal ⇒ Principal
Principal holding user identity and access credentials.
-
#related_user_ids ⇒ Array<Integer>
may act on behalf of.
-
#roles ⇒ Array<Roles>
Roles that have been granted to the #principal.
DSL collapse
-
#alias_action(*actions, to: fail)
Add an action alias so that granting the alias will result in permits for any of the listed actions.
-
#deny(*actions) {|resource, additional_context| ... }
Explicitly deny an action previously granted with #permit.
-
#permissions
Hook to be overridden by a derived class to define the set of rules that #permit? should consider when evaluating the #principal's permissions on a resource.
-
#permit(*actions) {|resource, additional_context| ... }
permit :read, UserEntity permit :show, :dashboard permit :update, UserEntity do |user| user.id == principal.user_id end permit :destroy, UserEntity do |user, additional_context| in_role?( :admin ) && additional_context[:custom_data] == :safe end.
- #resource(resource) ⇒ Object
-
#when_elevated(&block)
Only #authorize! the permissions defined in the given block when the #principal has elevated this session by providing their credentials.
Instance Method Summary collapse
- #add_rule(actions, resource, result, &block) ⇒ Object
-
#authorize!(action, resource, additional_context = nil) ⇒ resource
Authorize the given
action
on the given resource. - #dsl_resource ⇒ Object
- #expand_alias_into(candidate, expanded) ⇒ Object
- #expand_aliases(actions) ⇒ Object
- #extract_resource(actions) ⇒ Object
- #fail_on_active_record_check(resource) ⇒ Object
-
#in_role?(*roles) ⇒ Boolean
True if the #principal has been granted one of the given roles.
-
#initialize(principal: nil, roles: nil, related_user_ids: nil) ⇒ Policy
constructor
A new instance of Policy.
-
#is_principal?(id) ⇒ Boolean
ids on the principal.
-
#permit?(action, resource, additional_context = nil) ⇒ :yes, ...
Determines if the given
action
may be performed on the givenresource
.
Methods included from Roles
expand_roles, role, role_defined?, roles
Constructor Details
#initialize(principal: nil, roles: nil, related_user_ids: nil) ⇒ Policy
Returns a new instance of Policy.
59 60 61 62 63 |
# File 'lib/shamu/security/policy.rb', line 59 def initialize( principal: nil, roles: nil, related_user_ids: nil ) @principal = principal || Principal.new @roles = roles || [] @related_user_ids = Array.wrap( ) end |
Instance Attribute Details
#principal ⇒ Principal
Returns principal holding user identity and access credentials.
45 46 47 |
# File 'lib/shamu/security/policy.rb', line 45 def principal @principal end |
#related_user_ids ⇒ Array<Integer>
may act on behalf of.
54 55 56 |
# File 'lib/shamu/security/policy.rb', line 54 def @related_user_ids end |
#roles ⇒ Array<Roles>
Returns roles that have been granted to the #principal.
49 50 51 |
# File 'lib/shamu/security/policy.rb', line 49 def roles @roles end |
Instance Method Details
#add_rule(actions, resource, result, &block) ⇒ Object
327 328 329 |
# File 'lib/shamu/security/policy.rb', line 327 def add_rule( actions, resource, result, &block ) rules.unshift PolicyRule.new( ( actions ), resource, result, block ) end |
#alias_action(*actions, to: fail)
This method returns an undefined value.
Add an action alias so that granting the alias will result in permits for any of the listed actions.
287 288 289 290 |
# File 'lib/shamu/security/policy.rb', line 287 def alias_action( *actions, to: fail ) # bug in rubocop chokes on trailing required keyword aliases[to] ||= [] aliases[to] |= actions end |
#authorize!(action, resource, additional_context = nil) ⇒ resource
Authorize the given action
on the given resource. If it is not
permitted then an exception is raised.
71 72 73 74 75 76 77 78 79 |
# File 'lib/shamu/security/policy.rb', line 71 def ( action, resource, additional_context = nil ) return resource if permit?( action, resource, additional_context ) == :yes fail Security::AccessDeniedError, action: action, resource: resource, additional_context: additional_context, principal: principal end |
#deny(*actions) {|resource, additional_context| ... }
This method returns an undefined value.
Explicitly deny an action previously granted with #permit.
244 245 246 247 |
# File 'lib/shamu/security/policy.rb', line 244 def deny( *actions, &block ) resource, actions = extract_resource( actions ) add_rule( actions, resource, false, &block ) end |
#dsl_resource ⇒ Object
318 319 320 |
# File 'lib/shamu/security/policy.rb', line 318 def dsl_resource @dsl_resource || fail( "Provide a `resource` argument or use a #resource block to declare the protected resource." ) # rubocop:disable Metrics/LineLength end |
#expand_alias_into(candidate, expanded) ⇒ Object
340 341 342 343 344 345 346 347 348 349 |
# File 'lib/shamu/security/policy.rb', line 340 def ( candidate, ) return unless mapped = aliases[candidate] mapped.each do |action| next if .include? action << action ( action, ) end end |
#expand_aliases(actions) ⇒ Object
331 332 333 334 335 336 337 338 |
# File 'lib/shamu/security/policy.rb', line 331 def ( actions ) = actions.dup actions.each do |action| ( action, ) end end |
#extract_resource(actions) ⇒ Object
322 323 324 325 |
# File 'lib/shamu/security/policy.rb', line 322 def extract_resource( actions ) resource = actions.last.is_a?( Symbol ) ? dsl_resource : actions.pop [ resource, actions ] end |
#fail_on_active_record_check(resource) ⇒ Object
351 352 353 354 355 356 357 358 |
# File 'lib/shamu/security/policy.rb', line 351 def fail_on_active_record_check( resource ) return unless resource return unless defined? ActiveRecord if resource.is_a?( ActiveRecord::Base ) || ( resource.is_a?( Class ) && resource < ActiveRecord::Base ) fail NoActiveRecordPolicyChecksError end end |
#in_role?(*roles) ⇒ Boolean
Returns true if the #principal has been granted one of the given roles.
133 134 135 |
# File 'lib/shamu/security/policy.rb', line 133 def in_role?( *roles ) ( principal_roles & roles ).any? end |
#is_principal?(id) ⇒ Boolean
ids on the principal.
150 151 152 |
# File 'lib/shamu/security/policy.rb', line 150 def is_principal?( id ) # rubocop:disable Style/PredicateName principal.try( :user_id ) == id || .include?( id ) end |
#permissions
This method returns an undefined value.
Hook to be overridden by a derived class to define the set of rules that #permit? should consider when evaluating the #principal's permissions on a resource.
Rules defined in the permissions block are evaluated in reverse order such that the last matching #permit or #deny will determine the permission.
If no rules match, the permission is denied.
180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/shamu/security/policy.rb', line 180 def if respond_to?( :anonymous_permissions, true ) && respond_to?( :authenticated_permissions, true ) if principal.user_id else end else fail IncompleteSetupError, "Permissions have not been defined. Add a private `permissions` method to #{ self.class.name }" # rubocop:disable Metrics/LineLength end end |
#permit(*actions) {|resource, additional_context| ... }
This method returns an undefined value.
permit :read, UserEntity permit :show, :dashboard permit :update, UserEntity do |user| user.id == principal.user_id end permit :destroy, UserEntity do |user, additional_context| in_role?( :admin ) && additional_context[:custom_data] == :safe end
228 229 230 231 232 233 |
# File 'lib/shamu/security/policy.rb', line 228 def permit( *actions, &block ) result = @when_elevated ? :maybe : :yes resource, actions = extract_resource( actions ) add_rule( actions, resource, result, &block ) end |
#permit?(action, resource, additional_context = nil) ⇒ :yes, ...
Determines if the given action
may be performed on the given
resource
.
93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/shamu/security/policy.rb', line 93 def permit?( action, resource, additional_context = nil ) fail_on_active_record_check( resource ) rules.each do |rule| next unless rule.match?( action, resource, additional_context ) return rule.result end false end |
#resource(resource) ⇒ Object
307 308 309 310 311 312 313 |
# File 'lib/shamu/security/policy.rb', line 307 def resource( resource ) last_resource = @dsl_resource @dsl_resource = resource yield ensure @dsl_resource = last_resource end |
#when_elevated(&block)
This method returns an undefined value.
Only #authorize! the permissions defined in the given block when the #principal has elevated this session by providing their credentials.
Permissions defined in the block will yield a :maybe
result when
queried via #permit? and will raise an AccessDeniedError when
an #authorize! check is enforced.
This allows you to enable/disable UX in response to what a user should be capable of doing but wait to actually allow it until they have offered their credentials.
263 264 265 266 267 268 |
# File 'lib/shamu/security/policy.rb', line 263 def when_elevated( &block ) current = @when_elevated @when_elevated = true yield @when_elevated = current end |