class PolicyMachineStorageAdapter::ActiveRecord

Constants

POLICY_ELEMENT_TYPES

Public Instance Methods

add_association(user_attribute, operation_set, object_attribute, policy_machine_uuid) click to toggle source

Add the given association to the policy map. If an association between user_attribute and object_attribute already exists, then replace it with that given in the arguments. Returns true if the association was added and false otherwise.

# File lib/policy_machine_storage_adapters/active_record.rb, line 258
def add_association(user_attribute, operation_set, object_attribute, policy_machine_uuid)
  PolicyElementAssociation.where(
    user_attribute_id: user_attribute.id,
    object_attribute_id: object_attribute.id
  ).first_or_create.operations = operation_set.to_a
end
assign(src, dst) click to toggle source

Assign src to dst in policy machine. The two policy elements must be persisted policy elements Returns true if the assignment occurred, false otherwise.

# File lib/policy_machine_storage_adapters/active_record.rb, line 193
def assign(src, dst)
  assert_persisted_policy_element(src, dst)
  src.children << dst
end
associations_with(operation) click to toggle source

Return an array of all associations in which the given operation is included. Each element of the array should itself be an array in which the first element is the user_attribute member of the association, the second element is a Ruby Set, each element of which is an operation, the third element is the object_attribute member of the association. If no associations are found then the empty array should be returned.

# File lib/policy_machine_storage_adapters/active_record.rb, line 273
def associations_with(operation)
  assocs = operation.policy_element_associations.all(include: [:user_attribute, :operations, :object_attribute])
  assocs.map { |assoc| [assoc.user_attribute, Set.new(assoc.operations), assoc.object_attribute] }
end
class_for_type(pe_type) click to toggle source
# File lib/policy_machine_storage_adapters/active_record.rb, line 183
def class_for_type(pe_type)
  @pe_type_class_hash ||= Hash.new { |h,k| h[k] = "PolicyMachineStorageAdapter::ActiveRecord::#{k.camelize}".constantize }
  @pe_type_class_hash[pe_type]
end
connected?(src, dst) click to toggle source

Determine if there is a path from src to dst in the policy machine. The two policy elements must be persisted policy elements; otherwise the method should raise an ArgumentError. Returns true if there is a such a path and false otherwise. Should return true if src == dst

# File lib/policy_machine_storage_adapters/active_record.rb, line 205
def connected?(src, dst)
  assert_persisted_policy_element(src, dst)
  src == dst || Assignment.transitive_closure?(src, dst)
end
delete(element) click to toggle source

Remove a persisted policy element. This should remove its assignments and associations but must not cascade to any connected policy elements. Returns true if the delete succeeded.

# File lib/policy_machine_storage_adapters/active_record.rb, line 230
def delete(element)
  element.destroy
end
element_in_machine?(pe) click to toggle source

Determine if the given node is in the policy machine or not. Returns true or false accordingly. TODO: This seems wrong.

# File lib/policy_machine_storage_adapters/active_record.rb, line 249
def element_in_machine?(pe)
  pe.persisted?
end
policy_classes_for_object_attribute(object_attribute) click to toggle source

Return array of all policy classes which contain the given object_attribute (or object). Return empty array if no such policy classes found.

# File lib/policy_machine_storage_adapters/active_record.rb, line 281
def policy_classes_for_object_attribute(object_attribute)
  object_attribute.descendants.where(type: class_for_type('policy_class'))
end
scoped_privileges(user_or_attribute, object_or_attribute) click to toggle source
Optimized version of PolicyMachine#scoped_privileges

Returns all operations the user has on the object

# File lib/policy_machine_storage_adapters/active_record.rb, line 301
def scoped_privileges(user_or_attribute, object_or_attribute)
  policy_classes_containing_object = policy_classes_for_object_attribute(object_or_attribute)
  if policy_classes_containing_object.count < 2
    scoped_privileges_single_policy_class(user_or_attribute, object_or_attribute)
  else
    scoped_privileges_multiple_policy_classes(user_or_attribute, object_or_attribute, policy_classes_containing_object)
  end
end
transaction(&block) click to toggle source

Execute the passed-in block transactionally: any error raised out of the block causes all the block’s changes to be rolled back.

# File lib/policy_machine_storage_adapters/active_record.rb, line 295
def transaction(&block)
  PolicyElement.transaction(&block)
end
unassign(src, dst) click to toggle source

Disconnect two policy elements in the machine The two policy elements must be persisted policy elements; otherwise the method should raise an ArgumentError. Returns true if unassignment occurred and false otherwise. Generally, false will be returned if the assignment didn’t exist in the PM in the first place.

# File lib/policy_machine_storage_adapters/active_record.rb, line 218
def unassign(src, dst)
  assert_persisted_policy_element(src, dst)
  if assignment = src.assignments.where(child_id: dst.id).first
    assignment.destroy
  end
end
update(element, changes_hash) click to toggle source

Update the extra_attributes of a persisted policy element. This should only affect attributes corresponding to the keys passed in. Returns true if the update succeeded or was redundant.

# File lib/policy_machine_storage_adapters/active_record.rb, line 239
def update(element, changes_hash)
  changes_hash.each { |k,v| element.send("#{k}=",v) }
  element.save
end
user_attributes_for_user(user) click to toggle source

Return array of all user attributes which contain the given user. Return empty array if no such user attributes are found.

# File lib/policy_machine_storage_adapters/active_record.rb, line 288
def user_attributes_for_user(user)
  user.descendants.where(type: class_for_type('user_attribute'))
end

Private Instance Methods

assert_persisted_policy_element(*arguments) click to toggle source
# File lib/policy_machine_storage_adapters/active_record.rb, line 333
def assert_persisted_policy_element(*arguments)
  arguments.each do |argument|
    raise ArgumentError, "expected policy elements, got #{argument}" unless argument.is_a?(PolicyElement)
  end
end
scoped_privileges_multiple_policy_classes(user_or_attribute, object_or_attribute, policy_classes_containing_object) click to toggle source
# File lib/policy_machine_storage_adapters/active_record.rb, line 321
def scoped_privileges_multiple_policy_classes(user_or_attribute, object_or_attribute, policy_classes_containing_object)
  base_scope = class_for_type('policy_element_association').where(
    object_attribute_id: object_or_attribute.descendants | [object_or_attribute],
    user_attribute_id: user_or_attribute.descendants | [user_or_attribute]
    )
  operations_for_policy_classes = policy_classes_containing_object.map do |pc|
    associations = base_scope.where(object_attribute_id: pc.ancestors).includes(:operations)
    associations.flat_map(&:operations)
  end
  operations_for_policy_classes.inject(:&) || []
end
scoped_privileges_single_policy_class(user_or_attribute, object_or_attribute) click to toggle source
# File lib/policy_machine_storage_adapters/active_record.rb, line 312
def scoped_privileges_single_policy_class(user_or_attribute, object_or_attribute)
  associations = class_for_type('policy_element_association').where(
    object_attribute_id: object_or_attribute.descendants | [object_or_attribute],
    user_attribute_id: user_or_attribute.descendants | [user_or_attribute]
    ).includes(:operations)

  associations.flat_map(&:operations).uniq
end