Class: Rend::Acl

Inherits:
Object
  • Object
show all
Includes:
Core::Helpers::Php
Defined in:
lib/rend/acl.rb,
lib/rend/acl/role.rb,
lib/rend/acl/version.rb,
lib/rend/acl/resource.rb,
lib/rend/acl/exception.rb,
lib/rend/acl/role/registry.rb,
lib/rend/acl/role/registry/exception.rb

Defined Under Namespace

Modules: Version Classes: Exception, Resource, Role

Constant Summary collapse

TYPE_ALLOW =
:TYPE_ALLOW
TYPE_DENY =
:TYPE_DENY
OP_ADD =
:OP_ADD
OP_REMOVE =
:OP_REMOVE

Instance Method Summary collapse

Constructor Details

#initializeAcl

Returns a new instance of Acl.



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/rend/acl.rb', line 16

def initialize
  # @var Rend::Acl::Role::Registry
  @_role_registry = nil

  # @var Hash
  @_resources = {}

  # @var Rend::Acl::Role
  @_is_allowed_role     = nil

  # @var Rend::Acl::Resource
  @_is_allowed_resource = nil

  # @var String
  @_is_allowed_privilege = nil

  # ACL rules whitelist (deny everything to all) by default
  # @var Hash
  @_rules = {
    :all_resources => {
      :all_roles => {
        :all_privileges => {
          :type => TYPE_DENY
        },
        :by_privilege_id => {}
      },
      :by_role_id => {}
    },
    :by_resource_id => {}
  }
end

Instance Method Details

#_role_dfs_all_privileges(role, resource = nil) ⇒ Object

Performs a depth-first search of the Role DAG, starting at role, in order to find a rule allowing/denying role access to all privileges upon resource

This method returns true if a rule is found and allows access. If a rule exists and denies access, then this method returns false. If no applicable rule is found, then this method returns nil.

Parameters:

  • Rend::Acl::Role

    role

  • Rend::Acl::Resource

    resource

Returns:

  • boolean|nil



637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
# File 'lib/rend/acl.rb', line 637

def _role_dfs_all_privileges(role, resource = nil)
  type_hint! Rend::Acl::Role, role, :is_required => true
  type_hint! Rend::Acl::Resource, resource

  dfs = {:visited => {}, :stack => []}

  result = _role_dfs_visit_all_privileges(role, resource, dfs)
  return result unless result.nil?

  while role = dfs[:stack].pop
    unless dfs[:visited].has_key?(role.id)
      result = _role_dfs_visit_all_privileges(role, resource, dfs)
      return result unless result.nil?
    end
  end
  nil
end

#_role_dfs_one_privilege(role, resource = nil, privilege = nil) ⇒ Object

Performs a depth-first search of the Role DAG, starting at role, in order to find a rule allowing/denying role access to a privilege upon resource

This method returns true if a rule is found and allows access. If a rule exists and denies access, then this method returns false. If no applicable rule is found, then this method returns nil.

Parameters:

  • Rend::Acl::Role

    role

  • Rend::Acl::Resource

    resource

  • string

    privilege

Returns:

  • boolean|nil

Raises:



699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
# File 'lib/rend/acl.rb', line 699

def _role_dfs_one_privilege(role, resource = nil, privilege = nil)
  type_hint! Rend::Acl::Role,      role, :is_required => true
  type_hint! Rend::Acl::Resource,  resource
  raise Rend::Acl::Exception, 'privilege parameter may not be nil' if privilege.nil?

  dfs = {:visited => {}, :stack => []}

  result = _role_dfs_visit_one_privilege(role, resource, privilege, dfs)
  return result unless result.nil?

  while role = dfs[:stack].pop
    unless dfs[:visited].has_key?(role.id)
      result = _role_dfs_visit_one_privilege(role, resource, privilege, dfs)
      return result unless result.nil?
    end
  end
  nil
end

#_role_dfs_visit_all_privileges(role, resource = nil, dfs = nil) ⇒ Object

Visits an role in order to look for a rule allowing/denying role access to all privileges upon resource

This method returns true if a rule is found and allows access. If a rule exists and denies access, then this method returns false. If no applicable rule is found, then this method returns nil.

This method is used by the internal depth-first search algorithm and may modify the DFS data structure.

Parameters:

  • Rend::Acl::Role

    role

  • Rend::Acl::Resource

    resource

  • array

    dfs

Returns:

  • boolean|nil

Raises:



667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
# File 'lib/rend/acl.rb', line 667

def _role_dfs_visit_all_privileges(role, resource = nil, dfs = nil)
  type_hint! Rend::Acl::Role,      role, :is_required => true
  type_hint! Rend::Acl::Resource,  resource
  raise Rend::Acl::Exception, 'dfs parameter may not be nil' if dfs.nil?

  if rules = _rules(resource, role)
    rules[:by_privilege_id].each do |privilege, rule|
      rule_type_one_privilege = _rule_type(resource, role, privilege)
      return false if rule_type_one_privilege == TYPE_DENY
    end
    rule_type_all_privileges = _rule_type(resource, role, nil)
    return rule_type_all_privileges == TYPE_ALLOW unless rule_type_all_privileges.nil?
  end

  dfs[:visited][role.id] = true
  role_registry.parents(role).each do |role_parent_id, role_parent|
    dfs[:stack].push(role_parent)
  end
  nil
end

#_role_dfs_visit_one_privilege(role, resource = nil, privilege = nil, dfs = nil) ⇒ Object

Visits an role in order to look for a rule allowing/denying role access to a privilege upon resource

This method returns true if a rule is found and allows access. If a rule exists and denies access, then this method returns false. If no applicable rule is found, then this method returns nil.

This method is used by the internal depth-first search algorithm and may modify the DFS data structure.

Parameters:

  • Rend::Acl::Role

    role

  • Rend::Acl::Resource

    resource

  • string

    privilege

  • array

    dfs

Returns:

  • boolean|nil

Raises:



731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
# File 'lib/rend/acl.rb', line 731

def _role_dfs_visit_one_privilege(role, resource = nil, privilege = nil, dfs = nil)
  type_hint! Rend::Acl::Role,      role, :is_required => true
  type_hint! Rend::Acl::Resource,  resource
  raise Rend::Acl::Exception, 'privilege parameter may not be nil'  if privilege.nil?
  raise Rend::Acl::Exception, 'dfs parameter may not be nil'        if dfs.nil?


  if rule_type_one_privilege = _rule_type(resource, role, privilege)
    return rule_type_one_privilege == TYPE_ALLOW
  end

  if rule_type_all_privileges = _rule_type(resource, role, nil)
    return rule_type_all_privileges == TYPE_ALLOW
  end

  dfs[:visited][role.id] = true
  role_registry.parents(role).each do |role_parent_id, role_parent|
    dfs[:stack].push(role_parent)
  end
  nil
end

#_rule_type(resource = nil, role = nil, privilege = nil) ⇒ Object

Returns the rule type associated with the specified Resource, Role, and privilege combination.

If a rule does not exist then this method returns nil. Otherwise, the rule type applies and is returned as either TYPE_ALLOW or TYPE_DENY.

If resource or role is nil, then this means that the rule must apply to all Resources or Roles, respectively.

If privilege is nil, then the rule must apply to all privileges.

If all three parameters are nil, then the default ACL rule type is returned, based on whether its assertion method passes.

Parameters:

  • Rend::Acl::Resource

    resource

  • Rend::Acl::Role

    role

  • string

    privilege

Returns:

  • string|nil



771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
# File 'lib/rend/acl.rb', line 771

def _rule_type(resource = nil, role = nil, privilege = nil)
  type_hint! Rend::Acl::Resource,  resource
  type_hint! Rend::Acl::Role,      role

  # get the rules for the resource and role
  return nil unless rules = _rules(resource, role)

  # follow privilege
  if privilege.nil?
    if rules.has_key?(:all_privileges)
      rule = rules[:all_privileges]
    else
      return nil
    end
  elsif !rules || !rules[:by_privilege_id].has_key?(privilege)
    return nil
  else
    rule = rules[:by_privilege_id][privilege]
  end

  # check assertion first
  assertion_value = nil
  if rule[:assert]
      # assertion = rule[:assert]
      # assertion_value = assertion.assert(
      #   self,
      #   (@_isAllowedRole instanceof Zend_Acl_Role_Interface) ? @_isAllowedRole : role,
      #   (@_isAllowedResource instanceof Zend_Acl_Resource_Interface) ? @_isAllowedResource : resource,
      #   @_isAllowedPrivilege
      # )
  end

  if rule[:assert].nil? || assertion_value
    rule[:type]
  elsif resource != nil || role != nil || privilege != nil
    nil
  elsif rule[:type] == TYPE_ALLOW
    TYPE_DENY
  else
    TYPE_ALLOW
  end
end

#_rules(resource = nil, role = nil, create = false) ⇒ Object

Returns the rules associated with a Resource and a Role, or nil if no such rules exist

If either resource or role is nil, this means that the rules returned are for all Resources or all Roles, respectively. Both can be nil to return the default rule set for all Resources and all Roles.

If the create parameter is true, then a rule set is first created and then returned to the caller.

Parameters:

  • Rend::Acl::Resource

    resource

  • Rend::Acl::Role

    role

  • boolean

    create

Returns:

  • array|nil



826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
# File 'lib/rend/acl.rb', line 826

def _rules(resource = nil, role = nil, create = false)
  type_hint! Rend::Acl::Resource, resource
  type_hint! Rend::Acl::Role,     role

  if resource.nil?
    visitor = @_rules[:all_resources]
  else
    if !@_rules[:by_resource_id].has_key?(resource.id)
      return nil unless create
      @_rules[:by_resource_id][resource.id] = {}
    end
    visitor = @_rules[:by_resource_id][resource.id]
  end

  if role.nil?
    if !visitor.has_key?(:all_roles)
      return nil unless create
      visitor[:all_roles] = { :by_privilege_id => {} }
    end
    return visitor[:all_roles]
  end

  visitor[:by_role_id] = {} unless visitor.has_key?(:by_role_id)

  unless visitor[:by_role_id].has_key?(role.id)
    return nil unless create
    visitor[:by_role_id][role.id] = {
      :by_privilege_id => {},
      :all_privileges => {:type => nil}
    }
  end
  visitor[:by_role_id][role.id]
end

#add_resource!(resource, parent = nil) ⇒ Object

Adds a Resource having an identifier unique to the ACL

The parent parameter may be a reference to, or the string identifier for, the existing Resource from which the newly added Resource will inherit.

Parameters:

  • Rend::Acl::Resource|string

    resource

  • Rend::Acl::Resource|string

    parent

Returns:

  • Rend::Acl Provides a fluent interface

Raises:



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/rend/acl.rb', line 171

def add_resource!(resource, parent = nil)
  resource = Rend::Acl::Resource.new(resource) if resource.is_a?(String)
  type_hint! Rend::Acl::Resource, resource, :is_required => true

  resource_id = resource.id

  raise Rend::Acl::Exception, "Resource id 'resource_id' already exists in the ACL" if has?(resource_id)

  resource_parent = nil

  if parent
    begin
      resource_parent_id  = (parent.class <= Rend::Acl::Resource) ? parent.id : parent
      resource_parent     = get!(resource_parent_id)
    rescue Rend::Acl::Exception
      raise Rend::Acl::Exception, "Parent Resource id 'resource_parent_id' does not exist"
    end
    @_resources[resource_parent_id][:children][resource_id] = resource
  end

  @_resources[resource_id] = { :instance => resource, :parent => resource_parent, :children => {} }
  self
end

#add_role!(role, parents = nil) ⇒ Object

Adds a Role having an identifier unique to the registry

The parents parameter may be a reference to, or the string identifier for, a Role existing in the registry, or parents may be passed as an array of these - mixing string identifiers and objects is ok - to indicate the Roles from which the newly added Role will directly inherit.

In order to resolve potential ambiguities with conflicting rules inherited from different parents, the most recently added parent takes precedence over parents that were previously added. In other words, the first parent added will have the least priority, and the last parent added will have the highest priority.

Parameters:

  • Rend::Acl::Role|string

    role

  • Rend::Acl::Role|string|array

    parents

Returns:

  • Rend::Acl Provides a fluent interface



65
66
67
68
69
70
# File 'lib/rend/acl.rb', line 65

def add_role!(role, parents = nil)
  role = Rend::Acl::Role.new(role) if role.is_a?(String)
  type_hint! Rend::Acl::Role, role, :is_required => true
  role_registry.add!(role, parents)
  self
end

#allow!(roles = nil, resources = nil, privileges = nil) ⇒ Object

Adds an “allow” rule to the ACL

Parameters:

  • Rend::Acl::Role|string|array

    roles

  • Rend::Acl::Resource|string|array

    resources

  • string|array

    privileges

Returns:

  • Rend::Acl Provides a fluent interface



307
308
309
# File 'lib/rend/acl.rb', line 307

def allow!(roles = nil, resources = nil, privileges = nil)
  set_rule!(OP_ADD, TYPE_ALLOW, roles, resources, privileges)
end

#allowed?(role = nil, resource = nil, privilege = nil) ⇒ Boolean

Returns true if and only if the Role has access to the Resource

The role and resource parameters may be references to, or the string identifiers for, an existing Resource and Role combination.

If either role or resource is nil, then the query applies to all Roles or all Resources, respectively. Both may be nil to query whether the ACL has a “blacklist” rule (allow everything to all). By default, Rend::Acl creates a “whitelist” rule (deny everything to all), and this method would return false unless this default has been overridden (i.e., by executing acl->allow()).

If a privilege is not provided, then this method returns false if and only if the Role is denied access to at least one privilege upon the Resource. In other words, this method returns true if and only if the Role is allowed all privileges on the Resource.

This method checks Role inheritance using a depth-first traversal of the Role registry. The highest priority parent (i.e., the parent most recently added) is checked first, and its respective parents are checked similarly before the lower-priority parents of the Role are checked.

Parameters:

  • Rend::Acl::Role|string

    role

  • Rend::Acl::Resource|string

    resource

  • string

    privilege

Returns:

  • (Boolean)

    boolean



551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
# File 'lib/rend/acl.rb', line 551

def allowed?(role = nil, resource = nil, privilege = nil)
  # reset role & resource to nil
  @_is_allowed_role       = nil
  @_is_allowed_resource   = nil
  @_is_allowed_privilege  = nil

  if role
    # keep track of originally called role
    @_is_allowed_role = role
    role = role_registry.get!(role)
    @_is_allowed_role = role unless @_is_allowed_role.class <= Rend::Acl::Role
  end

  if resource
    # keep track of originally called resource
    @_is_allowed_resource = resource
    resource = get!(resource)
    unless @_is_allowed_resource.class <= Rend::Acl::Resource
      @_is_allowed_resource = resource
    end
  end

  if privilege.nil?
    # query on all privileges
    loop do # loop terminates at :all_resources pseudo-parent
      # depth-first search on role if it is not :all_roles pseudo-parent
      result = _role_dfs_all_privileges(role, resource)
      return result if role && result

      # look for rule on :all_roles psuedo-parent
      rules = _rules(resource, nil)
      if rules
        rules[:by_privilege_id].each do |priv, rule|
          rule_type_one_privilege = _rule_type(resource, nil, priv)
          return false if rule_type_one_privilege == TYPE_DENY
        end
        rule_type_one_privilege = _rule_type(resource, nil, nil)
        return rule_type_one_privilege == TYPE_ALLOW if rule_type_one_privilege
      end

      # try next Resource
      resource = @_resources[resource.id][:parent]
    end
  else
    # IN HERE
    @_is_allowed_privilege = privilege
    # query on one privilege
    loop do # loop terminates at :all_resources pseudo-parent
      # depth-first search on role if it is not :all_roles pseudo-parent
      if nil != role && nil != (result = _role_dfs_one_privilege(role, resource, privilege))
        return result
      end


      # look for rule on 'allRoles' pseudo-parent
      if nil != (rule_type = _rule_type(resource, nil, privilege))
        return TYPE_ALLOW == rule_type
      elsif nil != (rule_type_all_privileges = _rule_type(resource, nil, nil))
        return TYPE_ALLOW == rule_type_all_privileges
      end

      # try next Resource
      resource = @_resources[resource.id][:parent]
    end
  end
end

#deny!(roles = nil, resources = nil, privileges = nil) ⇒ Object

Adds a “deny” rule to the ACL

Parameters:

  • Rend::Acl::Role|string|array

    roles

  • Rend::Acl::Resource|string|array

    resources

  • string|array

    privileges

Returns:

  • Rend::Acl Provides a fluent interface



318
319
320
# File 'lib/rend/acl.rb', line 318

def deny!(roles = nil, resources = nil, privileges = nil)
  set_rule!(OP_ADD, TYPE_DENY, roles, resources, privileges)
end

#get!(resource) ⇒ Object

Returns the identified Resource

The resource parameter can either be a Resource or a Resource identifier.

Parameters:

  • Rend::Acl::Resource|string

    resource

Returns:

  • Rend::Acl::Resource

Raises:



203
204
205
206
207
# File 'lib/rend/acl.rb', line 203

def get!(resource)
  resource_id = (resource.class <= Rend::Acl::Resource) ? resource.id : resource.to_s
  raise Rend::Acl::Exception, "Resource 'resource_id' not found" unless has?(resource)
  @_resources[resource_id][:instance]
end

#has?(resource) ⇒ Boolean

Returns true if and only if the Resource exists in the ACL

The resource parameter can either be a Resource or a Resource identifier.

Parameters:

  • Rend::Acl::Resource|string

    resource

Returns:

  • (Boolean)

    boolean



215
216
217
218
# File 'lib/rend/acl.rb', line 215

def has?(resource)
  resource_id = (resource.class <= Rend::Acl::Resource) ? resource.id : resource.to_s
  @_resources.keys.include?(resource_id)
end

#has_role?(role) ⇒ Boolean

Returns true if and only if the Role exists in the registry

The role parameter can either be a Role or a Role identifier.

Parameters:

  • Rend::Acl::Role|string

    role

Returns:

  • (Boolean)

    boolean



90
91
92
# File 'lib/rend/acl.rb', line 90

def has_role?(role)
  role_registry.has?(role)
end

#inherits?(resource, inherit, only_parent = false) ⇒ Boolean

Returns true if and only if resource inherits from inherit

Both parameters may be either a Resource or a Resource identifier. If only_parent is true, then resource must inherit directly from inherit in order to return true. By default, this method looks through the entire inheritance tree to determine whether resource inherits from inherit through its ancestor Resources.

Parameters:

  • Rend::Acl::Resource|string

    resource

  • Rend::Acl::Resource|string

    inherit

  • boolean

    onlyParent

Returns:

  • (Boolean)

    boolean



233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/rend/acl.rb', line 233

def inherits?(resource, inherit, only_parent = false)
  resource_id = get!(resource).id
  inherit_id  = get!(inherit).id

  if @_resources[resource_id][:parent]
    parent_id = @_resources[resource_id][:parent].id
    return true   if inherit_id == parent_id
    return false  if only_parent
  else
    return false
  end

  while @_resources[parent_id][:parent]
    parent_id = @_resources[parent_id][:parent].id
    return true if inherit_id == parent_id
  end
  false
end

#inherits_role?(role, inherit, only_parents = false) ⇒ Boolean

Returns true if and only if role inherits from inherit

Both parameters may be either a Role or a Role identifier. If only_parents is true, then role must inherit directly from inherit in order to return true. By default, this method looks through the entire inheritance DAG to determine whether role inherits from inherit through its ancestor Roles.

Parameters:

  • Rend::Acl::Role|string

    role

  • Rend::Acl::Role|string

    inherit

  • boolean

    only_parents

Returns:

  • (Boolean)

    boolean



107
108
109
# File 'lib/rend/acl.rb', line 107

def inherits_role?(role, inherit, only_parents = false)
  role_registry.inherits?(role, inherit, only_parents)
end

#remove!(resource) ⇒ Object

Removes a Resource and all of its children

The resource parameter can either be a Resource or a Resource identifier.

Parameters:

  • Rend::Acl::Resource|string

    resource

Returns:

  • Rend::Acl Provides a fluent interface



259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
# File 'lib/rend/acl.rb', line 259

def remove!(resource)
  resource_id       = get!(resource).id
  resources_removed = [resource_id]

  if resource_parent = @_resources[resource_id][:parent]
    @_resources[resource_parent.id][:children].delete(resource_id)
  end

  @_resources[resource_id][:children].each do |child_id, child|
    remove!(child_id)
    resources_removed.push(child_id)
  end

  resources_removed.each do |resource_id_removed|
    @_rules[:by_resource_id].each do |resource_id_current, rules|
      if resource_id_removed == resource_id_current
        @_rules[:by_resource_id].delete(resource_id_current)
      end
    end
  end

  @_resources.delete(resource_id)

  self
end

#remove_all!Object

Removes all Resources

Returns:

  • Rend::Acl Provides a fluent interface



288
289
290
291
292
293
294
295
296
297
298
# File 'lib/rend/acl.rb', line 288

def remove_all!
  @_resources.each do |resource_id, resource|
    @_rules[:by_resource_id].each do |resource_id_current, rules|
      @_rules[:by_resource_id].delete(resource_id_current) if resource_id == resource_id_current
    end
  end

  @_resources = {}

  self
end

#remove_allow!(roles = nil, resources = nil, privileges = nil) ⇒ Object

Removes “allow” permissions from the ACL

Parameters:

  • Rend::Acl::Role|string|array

    roles

  • Rend::Acl::Resource|string|array

    resources

  • string|array

    privileges

Returns:

  • Rend::Acl Provides a fluent interface



329
330
331
# File 'lib/rend/acl.rb', line 329

def remove_allow!(roles = nil, resources = nil, privileges = nil)
  set_rule!(OP_REMOVE, TYPE_ALLOW, roles, resources, privileges)
end

#remove_deny!(roles = nil, resources = nil, privileges = nil) ⇒ Object

Removes “deny” restrictions from the ACL

Parameters:

  • Rend::Acl::Role|string|array

    roles

  • Rend::Acl::Resource|string|array

    resources

  • string|array

    privileges

Returns:

  • Rend::Acl Provides a fluent interface



340
341
342
# File 'lib/rend/acl.rb', line 340

def remove_deny!(roles = nil, resources = nil, privileges = nil)
  set_rule!(OP_REMOVE, TYPE_DENY, roles, resources, privileges)
end

#remove_role!(role) ⇒ Object

Removes the Role from the registry

The role parameter can either be a Role or a Role identifier.

Parameters:

  • Rend::Acl::Role|string

    role

Returns:

  • Rend::Acl Provides a fluent interface



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/rend/acl.rb', line 118

def remove_role!(role)
  role_registry.remove!(role)

  role_id = (role.class <= Rend::Acl::Role) ? role.id : role

  @_rules[:all_resources][:by_role_id].each do |role_id_current, rules|
    if role_id == role_id_current
      @_rules[:all_resources][:by_role_id].delete(role_id_current)
    end
  end

  @_rules[:by_resource_id].each do |resource_id_current, visitor|
    if visitor.has_key?(:by_role_id)
      visitor[:by_role_id].each do |role_id_current, rules|
        if role_id == role_id_current
          @_rules[:by_resource_id][resource_id_current][:by_role_id].delete(role_id_current)
        end
      end
    end
  end

  self
end

#remove_role_all!Object

Removes all Roles from the registry

Returns:

  • Rend::Acl Provides a fluent interface



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/rend/acl.rb', line 146

def remove_role_all!
  role_registry.remove_all!

  @_rules[:all_resources][:by_role_id].each do |role_id_current, rules|
    @_rules[:all_resources][:by_role_id].delete(role_id_current)
  end

  @_rules[:by_resource_id].each do |resource_id_current, visitor|
    visitor[:by_role_id].each do |role_id_current, rules|
      @_rules[:by_resource_id][resource_id_current][:by_role_id].delete(role_id_current)
    end
  end

  self
end

#resourcesObject

Returns array of registered resources.

Returns:

  • array of registered resources



871
872
873
# File 'lib/rend/acl.rb', line 871

def resources
  @_resources.keys
end

#role(role) ⇒ Object

Returns the identified Role

The role parameter can either be a Role or Role identifier.

Parameters:

  • Rend::Acl::Role|string

    role

Returns:

  • Rend::Acl::Role



79
80
81
# File 'lib/rend/acl.rb', line 79

def role(role)
  role_registry.get!(role)
end

#role_registryObject

Returns the Role registry for this ACL

If no Role registry has been created yet, a new default Role registry is created and returned.

Returns:

  • Rend::Acl::Role::Registry



624
625
626
# File 'lib/rend/acl.rb', line 624

def role_registry
  @_role_registry ||= Rend::Acl::Role::Registry.new
end

#rolesObject

Returns an array of registered roles.

Note that this method does not return instances of registered roles, but only the role identifiers.

Returns:

  • array of registered roles



866
867
868
# File 'lib/rend/acl.rb', line 866

def roles
  role_registry.roles.keys
end

#set_rule!(operation, type, roles = nil, resources = nil, privileges = nil) ⇒ Object

Performs operations on ACL rules

The operation parameter may be either OP_ADD or OP_REMOVE, depending on whether the user wants to add or remove a rule, respectively:

OP_ADD specifics:

A rule is added that would allow one or more Roles access to [certain privileges
upon] the specified Resource(s).

OP_REMOVE specifics:

The rule is removed only in the context of the given Roles, Resources, and privileges.
Existing rules to which the remove operation does not apply would remain in the
ACL.

The type parameter may be either TYPE_ALLOW or TYPE_DENY, depending on whether the rule is intended to allow or deny permission, respectively.

The roles and resources parameters may be references to, or the string identifiers for, existing Resources/Roles, or they may be passed as arrays of these - mixing string identifiers and objects is ok - to indicate the Resources and Roles to which the rule applies. If either roles or resources is nil, then the rule applies to all Roles or all Resources, respectively. Both may be nil in order to work with the default rule of the ACL.

The privileges parameter may be used to further specify that the rule applies only to certain privileges upon the Resource(s) in question. This may be specified to be a single privilege with a string, and multiple privileges may be specified as an array of strings.

Parameters:

  • string

    operation

  • string

    type

  • Rend::Acl::Role|string|array

    roles

  • Rend::Acl::Resource|string|array

    resources

  • string|array

    privileges

Returns:

  • Rend::Acl Provides a fluent interface



383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
# File 'lib/rend/acl.rb', line 383

def set_rule!(operation, type, roles = nil, resources = nil, privileges = nil)
  # ensure that the rule type is valid normalize input to uppercase
  type = type.upcase
  if type != TYPE_ALLOW && type != TYPE_DENY
    raise Zend::Acl::Exception, "Unsupported rule type must be either '#{TYPE_ALLOW}' or '#{TYPE_DENY}'"
  end

  # ensure that all specified Roles exist normalize input to array of Role objects or nil
  if !roles.is_a?(Array)
    roles = [roles]
  elsif roles.empty?
    roles = [nil]
  end
  roles = roles.reduce([]) do |seed, role|
    seed << (role ? role_registry.get!(role) : nil)
  end

  # ensure that all specified Resources exist normalize input to array of Resource objects or nil
  if resources
    resources = Array(resources)
    resources << nil if resources.empty?
    resources = resources.reduce([]) do |seed, resource|
      seed << (resource ? get!(resource) : nil)
    end
  else
    # this might be used later if resource iteration is required
    all_resources = @_resources.reduce([]) do |seed, resource|
      seed << resource[:instance]
    end
  end

  # normalize privileges to array
  if privileges.nil?
    privileges = []
  elsif !privileges.is_a?(Array)
    privileges = [privileges]
  end

  case operation

  # add to the rules
  when OP_ADD
    if resources
      # this block will iterate the provided resources
      resources.each do |resource|
        roles.each do |role|
          rules = _rules(resource, role, true)
          if privileges.empty?
            rules[:all_privileges][:type] = type
            rules[:by_privilege_id]       = {} unless rules.has_key?(:by_privilege_id)
          else
            privileges.each do |privilege|
              rules[:by_privilege_id][privilege] = {:type => type}
            end
          end
        end
      end
    else
      # this block will apply to all resources in a global rule
      roles.each do |role|
        rules = _rules(nil, role, true)
        if privileges.empty?
          rules[:all_privileges] = {:type => type}
        else
          privileges.each do |privilege|
            rules[:by_privilege_id][privilege] = {:type => type}
          end
        end
      end
    end
  # remove from the rules
  when OP_REMOVE
    if resources
      # this block will iterate the provided resources
      resources.each do |resource|
        roles.each do |role|
          rules = _rules(resource, role)
          next if rules.nil?
          if privileges.empty?
            if resource.nil? && role.nil?
              if rules[:all_privileges][:type] == type
                rules.replace({
                  :all_privileges   => { :type => TYPE_DENY },
                  :by_privilege_id  => {}
                })
              end
              next
            end

            if rules[:all_privileges].has_key?(:type) && rules[:all_privileges][:type] == type
              rules.delete(:all_privileges)
            end
          else
            privileges.each do |privilege|
              if rules[:by_privilege_id].has_key?(privilege) && rules[:by_privilege_id][privilege][:type] == type
                rules[:by_privilege_id].delete(privilege)
              end
            end
          end
        end
      end
    else
      # this block will apply to all resources in a global rule
      roles.each do |role|

        # since nil (all resources) was passed to this set_role!() call, we need
        # clean up all the rules for the global allResources, as well as the indivually
        # set resources (per privilege as well)
        [nil].concat(all_resources).each do |resource|
          rules = _rules(resource, role, true)
          next if rules.nil?
          if privileges.empty?
            if role.nil?
              if rules[:all_privileges][:type] == type
                rules.replace({
                  :all_privileges   => { :type => TYPE_DENY },
                  :by_privilege_id  => {}
                })
              end
              next
            end

            if rules[:all_privileges].has_key?(:type) && rules[:all_privileges][:type] == type
              rules.delete(:all_privileges)
            end
          else
            privileges.each do |privilege|
              if rules[:by_privilege_id].has_key?(privilege) && rules[:by_privilege_id][privilege][:type] == type
                rules[:by_privilege_id].delete(privilege)
              end
            end
          end
        end
      end
    end
  else
    raise Rend::Acl::Exception, "Unsupported operation must be either '#{OP_ADD}' or '#{OP_REMOVE}'"
  end

  self
end