Class: Authorization::Reader::AuthorizationRulesReader

Inherits:
Object
  • Object
show all
Defined in:
lib/reader.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeAuthorizationRulesReader

:nodoc:



149
150
151
152
153
154
155
156
157
158
# File 'lib/reader.rb', line 149

def initialize # :nodoc:
  @current_role = nil
  @current_rule = nil
  @roles = []
  # higher_role => [lower_roles]
  @role_hierarchy = {}
  @role_titles = {}
  @role_descriptions = {}
  @auth_rules = []
end

Instance Attribute Details

#auth_rulesObject (readonly)

Returns the value of attribute auth_rules.



146
147
148
# File 'lib/reader.rb', line 146

def auth_rules
  @auth_rules
end

#role_descriptionsObject (readonly)

Returns the value of attribute role_descriptions.



146
147
148
# File 'lib/reader.rb', line 146

def role_descriptions
  @role_descriptions
end

#role_hierarchyObject (readonly)

Returns the value of attribute role_hierarchy.



146
147
148
# File 'lib/reader.rb', line 146

def role_hierarchy
  @role_hierarchy
end

#role_titlesObject (readonly)

Returns the value of attribute role_titles.



146
147
148
# File 'lib/reader.rb', line 146

def role_titles
  @role_titles
end

#rolesObject (readonly)

Returns the value of attribute roles.



146
147
148
# File 'lib/reader.rb', line 146

def roles
  @roles
end

Instance Method Details

#append_role(role, options = {}) ⇒ Object

:nodoc:



160
161
162
163
164
# File 'lib/reader.rb', line 160

def append_role (role, options = {}) # :nodoc:
  @roles << role unless @roles.include? role
  @role_titles[role] = options[:title] if options[:title]
  @role_descriptions[role] = options[:description] if options[:description]
end

#contains(&block) ⇒ Object

In an if_attribute statement, contains says that the value has to be part of the collection specified by the if_attribute attribute. For information on the block argument, see if_attribute.



354
355
356
# File 'lib/reader.rb', line 354

def contains (&block)
  [:contains, block]
end

#description(text) ⇒ Object

Sets a description for the current role. E.g.

role :admin
  description "To be assigned to administrative personnel"
  has_permission_on ...
end

Raises:



243
244
245
246
# File 'lib/reader.rb', line 243

def description (text)
  raise DSLError, "description only allowed in role blocks" if @current_role.nil?
  role_descriptions[@current_role] = text
end

#does_not_contain(&block) ⇒ Object

The negation of contains.



359
360
361
# File 'lib/reader.rb', line 359

def does_not_contain (&block)
  [:does_not_contain, block]
end

#has_permission_on(context, options = {}, &block) ⇒ Object

Allows the definition of privileges to be allowed for the current role, either in a has_permission_on block or directly in one call.

role :admin
  has_permission_on :employees, :to => :read
  has_permission_on [:employees, :orders], :to => :read
  has_permission_on :employees do
    to :create
    if_attribute ...
  end
  has_permission_on :employees, :to => :delete do
    if_attribute ...
  end
end

The block form allows to describe restrictions on the permissions using if_attribute. Multiple has_permission_on statements are OR’ed when evaluating the permissions. Also, multiple if_attribute statements in one block are OR’ed.

Available options

:to

A symbol or an array of symbols representing the privileges that should be granted in this statement.

Raises:



219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/reader.rb', line 219

def has_permission_on (context, options = {}, &block)
  raise DSLError, "has_permission_on only allowed in role blocks" if @current_role.nil?
  options = {:to => []}.merge(options)
  
  privs = options[:to] 
  privs = [privs] unless privs.is_a?(Array)
  raise DSLError, "has_permission_on either needs a block or :to option" if !block_given? and privs.empty?
  
  rule = AuthorizationRule.new(@current_role, privs, context)
  @auth_rules << rule
  if block_given?
    @current_rule = rule
    yield
    raise DSLError, "has_permission_on block content specifies no privileges" if rule.privileges.empty?
    # TODO ensure?
    @current_rule = nil
  end
end

#if_attribute(attr_conditions_hash) ⇒ Object

In a has_permission_on block, if_attribute specifies conditions of dynamic parameters that have to be met for the user to meet the privileges in this block. Conditions are evaluated on the context object. Thus, the following allows CRUD for branch admins only on employees that belong to the same branch as the current user.

role :branch_admin
  has_permission_on :employees do
    to :create, :read, :update, :delete
    if_attribute :branch => is { user.branch }
  end
end

In this case, is is the operator for evaluating the condition. Another operator is contains for collections. In the block supplied to the operator, user specifies the current user for whom the condition is evaluated.

Conditions may be nested:

role :company_admin
  has_permission_on :employees do
    to :create, :read, :update, :delete
    if_attribute :branch => { :company => is {user.branch.company} }
  end
end

Multiple if_attribute statements are OR’ed.

Arrays and fixed values may be used directly as hash values:

if_attribute :id => 1
if_attribute :id => [1,2]

Raises:



301
302
303
304
305
# File 'lib/reader.rb', line 301

def if_attribute (attr_conditions_hash)
  raise DSLError, "if_attribute only in has_permission blocks" if @current_rule.nil?
  parse_attribute_conditions_hash!(attr_conditions_hash)
  @current_rule.append_attribute Attribute.new(attr_conditions_hash)
end

#if_permitted_to(privilege, attr_or_hash, options = {}) ⇒ Object

if_permitted_to allows the has_permission_on block to depend on permissions on associated objects. By using it, the authorization rules may be a lot DRYer. E.g.:

role :branch_manager
  has_permission_on :branches, :to => :manage do
    if_attribute :employees => includes { user }
  end
  has_permission_on :employees, :to => :read do
    if_permitted_to :read, :branch
    # instead of
    # if_attribute :branch => { :employees => includes { user } }
  end
end

if_permitted_to associations may be nested as well:

if_permitted_to :read, :branch => :company

Options:

:context

If the context of the refered object may not be infered from the associations name, the context may be given explicitly:

if_permitted_to :read, :home_branch, :context => :branches
if_permitted_to :read, :branch => :main_company, :context => :companies

Raises:



332
333
334
335
336
337
# File 'lib/reader.rb', line 332

def if_permitted_to (privilege, attr_or_hash, options = {})
  raise DSLError, "if_permitted_to only in has_permission blocks" if @current_rule.nil?
  options[:context] ||= attr_or_hash.delete(:context) if attr_or_hash.is_a?(Hash)
  @current_rule.append_attribute AttributeWithPermission.new(privilege,
      attr_or_hash, options[:context])
end

#includes(*roles) ⇒ Object

Roles may inherit all the rights from subroles. The given roles become subroles of the current block’s role.

role :admin do
  includes :user
  has_permission_on :employees, :to => [:update, :create]
end
role :user do
  has_permission_on :employees, :to => :read
end

Raises:



190
191
192
193
194
# File 'lib/reader.rb', line 190

def includes (*roles)
  raise DSLError, "includes only in role blocks" if @current_role.nil?
  @role_hierarchy[@current_role] ||= []
  @role_hierarchy[@current_role] += roles.flatten
end

#is(&block) ⇒ Object

In an if_attribute statement, is says that the value has to be met exactly by the if_attribute attribute. For information on the block argument, see if_attribute.



342
343
344
# File 'lib/reader.rb', line 342

def is (&block)
  [:is, block]
end

#is_in(&block) ⇒ Object

In an if_attribute statement, is_in says that the value has to contain the attribute value. For information on the block argument, see if_attribute.



366
367
368
# File 'lib/reader.rb', line 366

def is_in (&block)
  [:is_in, block]
end

#is_not(&block) ⇒ Object

The negation of is.



347
348
349
# File 'lib/reader.rb', line 347

def is_not (&block)
  [:is_not, block]
end

#is_not_in(&block) ⇒ Object

The negation of is_in.



371
372
373
# File 'lib/reader.rb', line 371

def is_not_in (&block)
  [:is_not_in, block]
end

#role(role, options = {}, &block) ⇒ Object

Defines the authorization rules for the given role in the following block.

role :admin do
  has_permissions_on ...
end


172
173
174
175
176
177
178
# File 'lib/reader.rb', line 172

def role (role, options = {}, &block)
  append_role role, options
  @current_role = role
  yield
ensure
  @current_role = nil
end

#title(text) ⇒ Object

Sets a human-readable title for the current role. E.g.

role :admin
  title "Administrator"
  has_permission_on ...
end

Raises:



253
254
255
256
# File 'lib/reader.rb', line 253

def title (text)
  raise DSLError, "title only allowed in role blocks" if @current_role.nil?
  role_titles[@current_role] = text
end

#to(*privs) ⇒ Object

Used in a has_permission_on block, to may be used to specify privileges to be assigned to the current role under the conditions specified in the current block.

role :admin
  has_permission_on :employees do
    to :create, :read, :update, :delete
  end
end

Raises:



266
267
268
269
# File 'lib/reader.rb', line 266

def to (*privs)
  raise DSLError, "to only allowed in has_permission_on blocks" if @current_rule.nil?
  @current_rule.append_privileges(privs)
end