Class: Authorization::Engine
- Inherits:
-
Object
- Object
- Authorization::Engine
- Extended by:
- Forwardable
- Defined in:
- lib/declarative_authorization/authorization.rb
Overview
Authorization::Engine implements the reference monitor. It may be used for querying the permission and retrieving obligations under which a certain privilege is granted for the current user.
Defined Under Namespace
Classes: AttributeValidator
Instance Attribute Summary collapse
-
#reader ⇒ Object
readonly
Returns the value of attribute reader.
Class Method Summary collapse
- .development_reload? ⇒ Boolean
-
.instance(dsl_file = nil) ⇒ Object
Returns an instance of Engine, which is created if there isn’t one yet.
Instance Method Summary collapse
-
#description_for(role) ⇒ Object
Returns the description for the given role.
-
#initialize(reader = nil) ⇒ Engine
constructor
If
readeris not given, a new one is created with the default authorization configuration ofAUTH_DSL_FILES. -
#initialize_copy(from) ⇒ Object
:nodoc:.
-
#obligations(privilege, options = {}) ⇒ Object
Returns the obligations to be met by the current user for the given privilege as an array of obligation hashes in form of [=> obligation_value, …, …] where
obligation_valueis either (recursively) another obligation hash or a value spec, such as [operator, literal_value] The obligation hashes in the array should be OR’ed, conditions inside the hashes AND’ed. -
#permit!(privilege, options = {}) ⇒ Object
Returns true if privilege is met by the current user.
-
#permit?(privilege, options = {}) ⇒ Boolean
Calls permit! but doesn’t raise authorization errors.
-
#rev_priv_hierarchy ⇒ Object
ctx] => [priv, …].
-
#rev_role_hierarchy ⇒ Object
ctx] => [priv, …].
-
#roles_for(user) ⇒ Object
Returns the role symbols of the given user.
-
#roles_with_hierarchy_for(user) ⇒ Object
Returns the role symbols and inherritted role symbols for the given user.
-
#title_for(role) ⇒ Object
Returns the title for the given role.
Constructor Details
#initialize(reader = nil) ⇒ Engine
If reader is not given, a new one is created with the default authorization configuration of AUTH_DSL_FILES. If given, may be either a Reader object or a path to a configuration file.
107 108 109 110 |
# File 'lib/declarative_authorization/authorization.rb', line 107 def initialize(reader = nil) #@auth_rules = AuthorizationRuleSet.new reader.auth_rules_reader.auth_rules @reader = Reader::DSLReader.factory(reader || AUTH_DSL_FILES) end |
Instance Attribute Details
#reader ⇒ Object (readonly)
Returns the value of attribute reader.
98 99 100 |
# File 'lib/declarative_authorization/authorization.rb', line 98 def reader @reader end |
Class Method Details
.development_reload? ⇒ Boolean
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 |
# File 'lib/declarative_authorization/authorization.rb', line 326 def self.development_reload? if Rails.env.development? mod_time = AUTH_DSL_FILES.map do |m| begin File.mtime(m) rescue Time.at(0) end end.flatten.max @@auth_dsl_last_modified ||= mod_time if mod_time > @@auth_dsl_last_modified @@auth_dsl_last_modified = mod_time return true end end end |
.instance(dsl_file = nil) ⇒ Object
Returns an instance of Engine, which is created if there isn’t one yet. If dsl_file is given, it is passed on to Engine.new and a new instance is always created.
346 347 348 349 350 351 352 |
# File 'lib/declarative_authorization/authorization.rb', line 346 def self.instance(dsl_file = nil) if dsl_file or development_reload? @@instance = new(dsl_file) else @@instance ||= new end end |
Instance Method Details
#description_for(role) ⇒ Object
Returns the description for the given role. The description may be specified with the authorization rules. Returns nil if none was given.
292 293 294 |
# File 'lib/declarative_authorization/authorization.rb', line 292 def description_for(role) role_descriptions[role] end |
#initialize_copy(from) ⇒ Object
:nodoc:
112 113 114 |
# File 'lib/declarative_authorization/authorization.rb', line 112 def initialize_copy(from) # :nodoc: @reader = from.reader.clone end |
#obligations(privilege, options = {}) ⇒ Object
Returns the obligations to be met by the current user for the given privilege as an array of obligation hashes in form of
[{:object_attribute => obligation_value, ...}, ...]
where obligation_value is either (recursively) another obligation hash or a value spec, such as
[operator, literal_value]
The obligation hashes in the array should be OR’ed, conditions inside the hashes AND’ed.
Example
{:branch => {:company => [:is, 24]}, :active => [:is, true]}
Options
- :
context -
See permit!
- :
user -
See permit!
275 276 277 278 279 280 281 282 283 284 285 286 287 |
# File 'lib/declarative_authorization/authorization.rb', line 275 def obligations(privilege, = {}) = {:context => nil}.merge() user, roles, privileges = (privilege, ) permit!(privilege, :skip_attribute_test => true, :user => user, :context => [:context]) return [] if roles.is_a?(Hash) && !(roles.keys & omnipotent_roles).empty? attr_validator = AttributeValidator.new(self, user, nil, privilege, [:context]) matching_auth_rules(roles, privileges, [:context]).collect do |rule| rule.obligations(attr_validator) end.flatten end |
#permit!(privilege, options = {}) ⇒ Object
Returns true if privilege is met by the current user. Raises AuthorizationError otherwise. privilege may be given with or without context. In the latter case, the :context option is required.
Options:
- :
context -
The context part of the privilege. Defaults either to the tableized
class_nameof the given :object, if given. That is, :usersfor :objectof type User. Raises AuthorizationUsageError if context is missing and not to be inferred. - :
object -
An context object to test attribute checks against.
- :
skip_attribute_test -
Skips those attribute checks in the authorization rules. Defaults to false.
- :
user -
The user to check the authorization for. Defaults to Authorization#current_user.
- :
bang -
Should NotAuthorized exceptions be raised Defaults to true.
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
# File 'lib/declarative_authorization/authorization.rb', line 165 def permit!(privilege, = {}) return true if Authorization.ignore_access_control = { :object => nil, :skip_attribute_test => false, :context => nil, :bang => true }.merge() # Make sure we're handling all privileges as symbols. privilege = privilege.is_a?( Array ) ? privilege.flatten.collect { |priv| priv.to_sym } : privilege.to_sym # # If the object responds to :proxy_reflection, we're probably working with # an association proxy. Use 'new' to leverage ActiveRecord's builder # functionality to obtain an object against which we can check permissions. # # Example: permit!( :edit, :object => user.posts ) # if Authorization.is_a_association_proxy?([:object]) && [:object].respond_to?(:new) [:object] = [:object].where(nil).new end [:context] ||= [:object] && ( [:object].class.respond_to?(:decl_auth_context) ? [:object].class.decl_auth_context : [:object].class.name.tableize.to_sym ) rescue NoMethodError user, roles, privileges = (privilege, ) callback = Rails.application.config.try(:ae_declarative_authorization_permit_callback) callback.call(controller: [:controller], privilege: privilege) if callback && .include?(:controller) return true if roles.is_a?(Hash) && !(roles.keys & omnipotent_roles).empty? # find a authorization rule that matches for at least one of the roles and # at least one of the given privileges attr_validator = AttributeValidator.new(self, user, [:object], privilege, [:context]) rules = matching_auth_rules(roles, privileges, [:context]) # Test each rule in turn to see whether any one of them is satisfied. rules.each do |rule| return true if rule.validate?(attr_validator, [:skip_attribute_test]) end if [:bang] # Call authorization_denied_callback if configured if Authorization.config. action = if [:controller]&.respond_to?(:action_name) [:controller].action_name elsif [:controller]&.respond_to?(:route) # Grape API [:controller].route&.request_method end referer_url = [:controller]&.respond_to?(:request) ? [:controller].request&.referer : nil referer_path = referer_url ? (URI.parse(referer_url).path rescue nil) : nil Authorization.config..call( { action: action, path: [:controller]&.respond_to?(:request) ? [:controller].request&.path : nil, context: [:context].to_s, attribute_check_denial: !rules.empty?, referer: referer_path } ) end if rules.empty? raise NotAuthorized, "No matching rules found for #{privilege} for User with id #{user.try(:id)} " + "(roles #{roles.inspect}, privileges #{privileges.inspect}, " + "context #{options[:context].inspect})." else raise AttributeAuthorizationError, "#{privilege} not allowed for User with id #{user.try(:id)} on #{(options[:object] || options[:context]).inspect}." end else false end end |
#permit?(privilege, options = {}) ⇒ Boolean
Calls permit! but doesn’t raise authorization errors. If no exception is raised, permit? returns true and yields to the optional block.
250 251 252 253 254 255 256 257 |
# File 'lib/declarative_authorization/authorization.rb', line 250 def permit?(privilege, = {}) # :yields: if permit!(privilege, .merge(:bang=> false)) yield if block_given? true else false end end |
#rev_priv_hierarchy ⇒ Object
ctx] => [priv, …]
117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/declarative_authorization/authorization.rb', line 117 def rev_priv_hierarchy if @rev_priv_hierarchy.nil? @rev_priv_hierarchy = {} privilege_hierarchy.each do |key, value| value.each do |val| @rev_priv_hierarchy[val] ||= [] @rev_priv_hierarchy[val] << key end end end @rev_priv_hierarchy end |
#rev_role_hierarchy ⇒ Object
ctx] => [priv, …]
131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/declarative_authorization/authorization.rb', line 131 def rev_role_hierarchy if @rev_role_hierarchy.nil? @rev_role_hierarchy = {} role_hierarchy.each do |higher_role, lower_roles| lower_roles.each do |role| (@rev_role_hierarchy[role] ||= []) << higher_role end end end @rev_role_hierarchy end |
#roles_for(user) ⇒ Object
Returns the role symbols of the given user.
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 |
# File 'lib/declarative_authorization/authorization.rb', line 304 def roles_for(user) user ||= Authorization.current_user raise AuthorizationUsageError, "User object doesn't respond to roles (#{user.try(:id)})" \ if !user.respond_to?(:role_symbols) and !user.respond_to?(:roles) Rails.logger.info("The use of user.roles is deprecated. Please add a method " + "role_symbols to your User model.") if defined?(Rails) and Rails.respond_to?(:logger) and !user.respond_to?(:role_symbols) roles = user.respond_to?(:role_symbols) ? user.role_symbols : user.roles raise AuthorizationUsageError, "User.#{user.respond_to?(:role_symbols) ? 'role_symbols' : 'roles'} " + "doesn't return an Array of Symbols (#{roles.inspect})" \ if !roles.is_a?(Array) or (!roles.empty? and !roles[0].is_a?(Symbol)) (roles.empty? ? [Authorization.default_role] : roles) end |
#roles_with_hierarchy_for(user) ⇒ Object
Returns the role symbols and inherritted role symbols for the given user
322 323 324 |
# File 'lib/declarative_authorization/authorization.rb', line 322 def roles_with_hierarchy_for(user) flatten_roles(roles_for(user)) end |
#title_for(role) ⇒ Object
Returns the title for the given role. The title may be specified with the authorization rules. Returns nil if none was given.
299 300 301 |
# File 'lib/declarative_authorization/authorization.rb', line 299 def title_for(role) role_titles[role] end |