Module: Authz::Controllers::AuthorizationManager

Extended by:
ActiveSupport::Concern
Included in:
ApplicationController
Defined in:
lib/authz/controllers/authorization_manager.rb

Overview

Include this module in any controller that should be capable of performing authorization or in the ApplicationController to make the whole app capable.

API:

  • public

Defined Under Namespace

Classes: AuthorizationNotPerformedError, MissingScopingInstance, NotAuthorized

Instance Method Summary collapse

Instance Method Details

#apply_authz_scopes(on:) ⇒ ActiveRecord_Relation

Applies the current user’s scoping rules on the given relation or class

Parameters:

  • on top of which the user’s scoping rules will be applied

Returns:

  • resulting collection from applying all user’s roles scoping rules

API:

  • public



161
162
163
# File 'lib/authz/controllers/authorization_manager.rb', line 161

def apply_authz_scopes(on:)
  ScopingManager.apply_scopes_for_user(on, authz_user)
end

#authorize(using: nil, skip_scoping: false) ⇒ Object

Enforces authorization when called. Raises exception when unauthorized.

Parameters:

  • (defaults to: nil)

    the instance that will determine access

  • (defaults to: false)

    use true to explicitly skip scoping

Returns:

  • the instance that was given as param

Raises:

  • when unauthorized. May be rescued to provide custom behaviour.

See Also:

API:

  • public



76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/authz/controllers/authorization_manager.rb', line 76

def authorize(using: nil, skip_scoping: false)
  @_authorization_performed = true

  authorized = authorized?(controller: params[:controller],
                           action: params[:action],
                           using: using,
                           skip_scoping: skip_scoping)
  return using if authorized

  raise NotAuthorized, rolable: authz_user,
                       controller: params[:controller],
                       action: params[:action],
                       instance: using
end

#authorized?(controller:, action:, using: nil, skip_scoping: false) ⇒ Boolean

Determines if a user is authorized to perform a certain controller action on a given instance

Parameters:

  • name of the controller

  • name of the controller action

  • (defaults to: nil)

    the instance used to determine scope access

  • (defaults to: false)

    option for ignoring scoping during verification

Returns:

  • true if authorized, false otherwise

API:

  • public



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/authz/controllers/authorization_manager.rb', line 100

def authorized?(controller:, action:, using: nil, skip_scoping: false)
  # 1. Check if the user is correctly skipping scoping
  skip_scoping = skip_scoping == true
  if using.blank? && !skip_scoping
    raise MissingScopingInstance, controller: controller, action: action
  end

  # 2. At least one of the user's roles have both Permission and Scope
  usr = authz_user
  usr.roles.each do |role|
    # a. Check authorization on controller action
    auth_on_action = role.cached_has_permission?(controller, action)
    next unless auth_on_action

    # b. Check authorization on scoping privileges
    auth_on_scope = skip_scoping || ScopingManager.has_access_to_instance?(role, using, usr)

    # c. If a rule is fully authorized, return
    return true if auth_on_action && auth_on_scope
  end

  # 3. After searching all roles, no authorization found
  return false
end

#authorized_path?(path, method: :get, using: nil, skip_scoping: false) ⇒ Boolean

Returns true if the user has permission for the path and :using instance given as arguments

Parameters:

  • path or url that will be checked

  • (defaults to: :get)

    of the path or url

  • (defaults to: nil)

    instance that will be used to determine authorization

  • (defaults to: false)

    option to skip scoping validation

Returns:

API:

  • public



189
190
191
192
193
194
195
196
197
198
# File 'lib/authz/controllers/authorization_manager.rb', line 189

def authorized_path?(path, method: :get, using: nil, skip_scoping: false)
  recognized_ca = Rails.application.routes.recognize_path path,
                                                          method: method
  controller_name = recognized_ca[:controller]
  action_name = recognized_ca[:action]
  authorized?(controller: controller_name,
              action: action_name,
              using: using,
              skip_scoping: skip_scoping)
end

#skip_authorizationvoid

This method returns an undefined value.

Use within a controller action to explicitly skip authorization.

See Also:

API:

  • public



130
131
132
# File 'lib/authz/controllers/authorization_manager.rb', line 130

def skip_authorization
  @_authorization_performed = true
end

#verify_authorizedvoid

This method returns an undefined value.

Use as around_action filter to ensure all controller actions either perform authorization or explicitly skip it. Rollbacks changes in db if authorization was not performed.

Raises:

  • if authorization has not been performed or skipped

See Also:

API:

  • public



144
145
146
147
148
149
150
151
152
153
154
# File 'lib/authz/controllers/authorization_manager.rb', line 144

def verify_authorized
  # Yield gets replaced by the controller action performed: E.g. #show
  # http://stackoverflow.com/questions/27932270/how-does-an-around-action-callback-work-an-explanation-is-needed
  ActiveRecord::Base.transaction do
    yield
    unless authorization_performed?
      raise AuthorizationNotPerformedError, controller: self.class,
                                            action: self.action_name
    end
  end
end