Class: PolicyMachineStorageAdapter::Neography

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

Constant Summary collapse

POLICY_ELEMENT_TYPES =
%w(user user_attribute object object_attribute operation policy_class)

Instance Method Summary collapse

Instance Method Details

#add_association(user_attribute, operation_set, object_attribute, policy_machine_uuid) ⇒ Object

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.



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/policy_machine_storage_adapters/neography.rb', line 138

def add_association(user_attribute, operation_set, object_attribute, policy_machine_uuid)
  remove_association(user_attribute, object_attribute, policy_machine_uuid)
  
  # TODO:  scope by policy machine uuid
  unique_identifier = user_attribute.unique_identifier + object_attribute.unique_identifier
  node_attrs = {
    :unique_identifier => unique_identifier,
    :policy_machine_uuid => policy_machine_uuid,
    :user_attribute_unique_identifier => user_attribute.unique_identifier,
    :object_attribute_unique_identifier => object_attribute.unique_identifier,
    :operations => operation_set.map(&:unique_identifier).to_json,
  }
  persisted_assoc = ::Neography::Node.create(node_attrs)
  persisted_assoc.add_to_index('associations', 'unique_identifier', unique_identifier)
  
  [user_attribute, object_attribute, *operation_set].each do |element|
    ::Neography::Relationship.create(:in_association, element, persisted_assoc)
  end

  true
end

#assign(src, dst) ⇒ Object

Assign src to dst in policy machine



56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/policy_machine_storage_adapters/neography.rb', line 56

def assign(src, dst)
  assert_persisted_policy_element(src)
  assert_persisted_policy_element(dst)
  
  e = ::Neography::Relationship.create(:outgoing, src, dst)
  
  if e.nil?
    false
  else
    unique_identifier = src.unique_identifier + dst.unique_identifier
    e.add_to_index('edges', 'unique_identifier', unique_identifier)
    true
  end
end

#associations_with(operation) ⇒ Object

Return all associations in which the given operation is included Returns an array of arrays. Each sub-array is of the form

user_attribute, operation_set, object_attribute


165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/policy_machine_storage_adapters/neography.rb', line 165

def associations_with(operation)
  operation.outgoing(:in_association).map do |association|
    user_attribute = ::Neography::Node.find('nodes', 'unique_identifier', association.user_attribute_unique_identifier)
    object_attribute = ::Neography::Node.find('nodes', 'unique_identifier', association.object_attribute_unique_identifier)
    
    operation_set = Set.new
    JSON.parse(association.operations).each do |op_unique_id|
      op_node = ::Neography::Node.find('nodes', 'unique_identifier', op_unique_id)
      operation_set << op_node
    end
    
    [user_attribute, operation_set, object_attribute]
  end      
end

#connected?(src, dst) ⇒ Boolean

Determine if there is a path from src to dst in the policy machine

Returns:

  • (Boolean)


74
75
76
77
78
79
80
81
82
# File 'lib/policy_machine_storage_adapters/neography.rb', line 74

def connected?(src, dst)
  assert_persisted_policy_element(src)
  assert_persisted_policy_element(dst)
  
  return true if src == dst
  
  neo_connection.execute_query("start n=node({id1}),m=node({id2}) return (n)-[*]->(m)", 
    {:id1 => src.neo_id.to_i, :id2 => dst.neo_id.to_i})['data'] != [[[]]]
end

#delete(element) ⇒ Object

Remove a persisted policy element



111
112
113
114
115
116
117
118
# File 'lib/policy_machine_storage_adapters/neography.rb', line 111

def delete(element)
  if %w[user_attribute object_attribute].include?(element.pe_type)
    element.outgoing(:in_association).each do |assoc|
      assoc.del
    end
  end
  element.del
end

#element_in_machine?(pe) ⇒ Boolean

Determine if the given node is in the policy machine or not.

Returns:

  • (Boolean)


130
131
132
133
# File 'lib/policy_machine_storage_adapters/neography.rb', line 130

def element_in_machine?(pe)
  found_node = ::Neography::Node.find('nodes', 'unique_identifier', pe.unique_identifier)
  !found_node.nil?
end

#policy_classes_for_object_attribute(object_attribute) ⇒ Object

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



199
200
201
202
203
# File 'lib/policy_machine_storage_adapters/neography.rb', line 199

def policy_classes_for_object_attribute(object_attribute)
  find_all_of_type_policy_class.select do |pc|
    connected?(object_attribute, pc)
  end
end

#remove_association(user_attribute, object_attribute, policy_machine_uuid) ⇒ Object

Remove an existing association. Return true if the association was removed and false if it didn’t exist in the first place.



183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/policy_machine_storage_adapters/neography.rb', line 183

def remove_association(user_attribute, object_attribute, policy_machine_uuid)
  unique_identifier = user_attribute.unique_identifier + object_attribute.unique_identifier
  
  begin
    assoc_node = ::Neography::Node.find('associations', 'unique_identifier', unique_identifier)
    return false unless assoc_node
    assoc_node.del
    true
  rescue ::Neography::NotFoundException
    false
  end
end

#transactionObject

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

Raises:

  • (NotImplementedError)


218
219
220
# File 'lib/policy_machine_storage_adapters/neography.rb', line 218

def transaction
  raise NotImplementedError, "transactions are only available in neo4j 2.0 which #{self.class} is not compatible with"
end

#unassign(src, dst) ⇒ Object

Disconnect two policy elements in the machine



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/policy_machine_storage_adapters/neography.rb', line 87

def unassign(src, dst)
  assert_persisted_policy_element(src)
  assert_persisted_policy_element(dst)
  
  unique_identifier = src.unique_identifier + dst.unique_identifier
  found_edges = ::Neography::Relationship.find('edges', 'unique_identifier', unique_identifier)
  
  if found_edges
    # Neography::Relationship doesn't respond to .to_a
    found_edges = [found_edges] unless found_edges.is_a?(Array)
    found_edges.each do |found_edge|
      # Unfortunately, we have to reload the edge as find isn't deserializing it properly.
      e = ::Neography::Relationship.load(found_edge.neo_id.to_i)
      e.del unless e.nil?
    end
    true
  else
    false
  end
end

#update(element, changes_hash) ⇒ Object

Update a persisted policy element



123
124
125
# File 'lib/policy_machine_storage_adapters/neography.rb', line 123

def update(element, changes_hash)
  element.neo_server.set_node_properties(element.neo_id, changes_hash)
end

#user_attributes_for_user(user) ⇒ Object

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



208
209
210
211
212
213
# File 'lib/policy_machine_storage_adapters/neography.rb', line 208

def user_attributes_for_user(user)
  #Don't use this kind of query plan in a for-production adapter.
  find_all_of_type_user_attribute.select do |user_attribute|
    connected?(user, user_attribute)
  end
end