Module: RoleBasedAuthorization

Defined in:
lib/role_based_authorization/rule.rb,
lib/role_based_authorization/class_additions.rb,
lib/role_based_authorization/role_based_authorization.rb

Defined Under Namespace

Modules: ClassAdditions Classes: Rule

Constant Summary collapse

AUTHORIZATION_LOGGER =

AuthorizationLogger instance that is used throughout the plugin for logging events.

AuthorizationLogger.new(File.join(Rails.root || '.','log','authorization.log'))

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.find_matching_rule(rules, options) ⇒ Object

Returns true if one of the given rules matches the given options. rules must be an hash with a list of rules for each action



21
22
23
24
25
26
27
28
29
30
# File 'lib/role_based_authorization/role_based_authorization.rb', line 21

def RoleBasedAuthorization.find_matching_rule rules, options
  user,actions,ids = *options.values_at(:user, :actions, :ids)

  return actions.find do |action|
    AUTHORIZATION_LOGGER.debug('current action: %s' % [action])      
    action = action.to_sym
    rules_for_action = rules[action]
    rules_for_action && rules_for_action.find { |rule| rule.match(user, ids) }
  end
end

.included(klass) ⇒ Object

Fires when the module is included into the controllers. It adds all class methods defined in the ClassAdditions sub-module and the authorize_action? and if_authorized? instance methods.



9
10
11
12
13
14
15
16
# File 'lib/role_based_authorization/role_based_authorization.rb', line 9

def self.included(klass)
 klass.extend(ClassAdditions)
 
 klass.class_eval do
   helper_method :authorize_action?
   helper_method :if_authorized?
 end
end

.path_or_options_to_options(opts) ⇒ Object

Returns an hash options amenable to be passed to authorize_action?. It takes either an option hash, or a path string



35
36
37
38
39
40
41
42
# File 'lib/role_based_authorization/role_based_authorization.rb', line 35

def RoleBasedAuthorization.path_or_options_to_options(opts)
  path_cleanup_regexp = %r{(#{ENV['RAILS_RELATIVE_URL_ROOT']})?}
     
  url_options = (opts.class <= String) && Rails.application.routes.recognize_path(opts.gsub(path_cleanup_regexp,''))
  url_options ||= opts.dup
  
  url_options
end

Instance Method Details

#authorize_action?(opts = {}) ⇒ Boolean

wraps some logging around do_authorize_action?.

Returns:

  • (Boolean)


91
92
93
94
95
96
97
# File 'lib/role_based_authorization/role_based_authorization.rb', line 91

def authorize_action? opts = {}
  AUTHORIZATION_LOGGER.info("access request. options: %s" % [opts.inspect])
  result = do_authorize_action?(opts)
  AUTHORIZATION_LOGGER.info("returning #{result}")
  
  return result
end

#authorized?Boolean

Returns true if the current user is authorized to perform the current action on the current controller. It is mainly used in a before_filter (usually the method implementing the authentication logic calls this method immediately after checking the validity of the credentials.)

Returns:

  • (Boolean)


126
127
128
129
130
# File 'lib/role_based_authorization/role_based_authorization.rb', line 126

def authorized?
  authorize_action?     :controller => controller_name,  
                        :action => action_name, 
                        :ids => params.reject { |key,value| key.to_s !~ /(_id\Z)|(\Aid\Z)/ }
end

#cleanup_options(opts) ⇒ Object

cleans options so that they are good to be passed to exists_matching_rule



46
47
48
49
50
51
52
53
54
55
# File 'lib/role_based_authorization/role_based_authorization.rb', line 46

def cleanup_options(opts)
  opts.reverse_merge!( :user => current_user, :controller => controller_name, :ids => {} )
  user, controller, action, ids = opts.values_at( :user, :controller, :action, :ids )
  ids.reverse_merge!( opts.reject { |key,value| key.to_s !~ /(_id\Z)|(\Aid\Z)/ } )
  
  { :user         => user, 
    :controllers  => [controller,'application'], 
    :actions      => [:all,action], 
    :ids          => ids }    
end

#do_authorize_action?(opts) ⇒ Boolean

Main authorization logic. opts is an hash with the following keys

:user, :controller, :action

self explanatory

:ids

id to be used to retrieve relevant objects

Returns:

  • (Boolean)


83
84
85
86
87
88
# File 'lib/role_based_authorization/role_based_authorization.rb', line 83

def do_authorize_action? opts
  # exiting immediately if not logged in
  return false if respond_to?(:logged_in?) && !logged_in?
  
  exists_matching_rule?( cleanup_options(opts) )
end

#exists_matching_rule?(options) ⇒ Boolean

Returns true if one of the rules defined for this controller matches the given options

Returns:

  • (Boolean)


60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/role_based_authorization/role_based_authorization.rb', line 60

def exists_matching_rule? options
  rules = self.class.role_auth_rules
  
  # !! is an idiom for transforming any value in true/false (e.g., !!nil is exactly false)
  !!options[:controllers].find do |controller|
    AUTHORIZATION_LOGGER.debug("current controller: %s" % [controller])

    rules_for_controller = rules[controller]

    # tries to load the controller. Rails automagically loads classes if their name
    # is used anywhere. By trying to constantize the name of the controller, we
    # force rails to load it. Loading the controller class causes the insertion of the rules defined therein
    # into the object pointed by rules_for_controller.
    (controller.to_s+'_controller').camelize.constantize if( !controller.blank? && rules_for_controller.nil? )
  

    rules_for_controller && RoleBasedAuthorization.find_matching_rule(rules_for_controller, options)
  end
end

#if_authorized?(opts, &block) ⇒ Boolean

This is a helper method that provides a conditional execution syntax for a block of code. It is mainly useful because in most cases the same options that are needed for the authorization are also needed for url generation. Since this method forward those options to the block, it allows to write something like:

if_authorized? {:controller => xxx, :action => yyy} {|opts| link_to('yyy', opts) }

instead of:

if authorized_action? {:controller => xxx, :action => yyy}
  link_to 'yyy', {:controller => xxx, :action => yyy}
end

As an additional benefit, this method also accepts urls instead of parameter hashes. e.g.

if_authorized?( '/xxx/yyy' ) { |opts| link_to('yyy', opts) }

this comes particularly handy when you use resource based url generation as in the case:

if_authorized?( edit_item_path ) { |opts| link_to('yyy', opts) }

Returns:

  • (Boolean)


118
119
120
# File 'lib/role_based_authorization/role_based_authorization.rb', line 118

def if_authorized? opts, &block
  block.call(opts) if authorize_action?(RoleBasedAuthorization.path_or_options_to_options(opts))
end