Skip to content

Instantly share code, notes, and snippets.

@andreasronge
Created February 25, 2010 17:53
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andreasronge/314816 to your computer and use it in GitHub Desktop.
Save andreasronge/314816 to your computer and use it in GitHub Desktop.
require 'rubygems'
require 'neo4j'
# include the Module so we can skip the Neo4j:: prefix
include Neo4j
# this node is accessible from Neo4j.ref_node
# add a relationship to the top principal = All principals
class Neo4j::ReferenceNode
has_one :top_principal
end
class Principal
include NodeMixin
has_n :members
has_one(:owner).from(Principal, :members)
property :name
def init_node(name, *members)
self.name = name
members.each {|m| self.members << m}
end
def distance_to_owner(principal)
dinstance = 0
curr_owner = owner
while (curr_owner && owner != principal) do
distance += 1
curr_owner = curr_owner.owner
end
curr_owner ? distance : -1
end
def to_s
"Principal #{name}"
end
def self.top
Neo4j.ref_node.top_principal ||= Principal.new('ALL_PRINCIPALS')
end
end
class Content
include NodeMixin
property :name
has_one(:parent)
has_n(:children).from(Content, :parent)
has_n(:accesses)
def init_node(name, parent=nil)
self.name = name
self.parent = parent if parent
end
def access_for(principal, *flags)
security = accesses.new(principal)
# flags is varargs param, we expect first parameter to be an hash or nil
flags[0].each_pair {|key, value| security[key] = value} if flags[0]
end
def show_access(principal, flag)
if access?(principal, flag)
puts "#{principal} HAS access to #{self} with flag #{flag}"
else
puts "#{principal} has NOT access to #{self} with flag #{flag}"
end
end
def access?(principal, flag)
# Move from the content node and upwards through the file system structure and investigate
# each level for permission information.
access_for_parent?(self, principal, flag)
end
def access_for_parent?(content, principal, flag)
# On each level, see if there are any principals related to or identical with the principal concerned.
# Find all relationship accesses with the given flags
# using Ruby Enumerable Mixins find_all
found = content.accesses_rels.find_all{|access| access[flag] }
# Make sure to use the permission information from the principal closest to the principal concerned.
# found.min - see Ruby Enumerable#min
rel = found.min do |rel1, rel2|
principal.distance_to_owner(rel1.start_node) <=> principal.distance_to_owner(rel2.start_node)
end
# If permission information was found, return it;
# otherwise, continue traversing to the next level in the file system.
if rel
rel[flag]
else
access_for_parent?(content.parent, principal, flag) # recursive
end
end
def to_s
"Content #{name}"
end
end
Neo4j.start
Transaction.run do
root = Principal.new('root', Principal.top)
reg_users = Principal.new('Regualar user', Principal.top)
user1 = Principal.new('user1', reg_users)
user2 = Principal.new('user2', reg_users)
root_folder = Content.new('Root folder')
# All principals (top) have read access
root_folder.access_for(Principal.top, :r => true)
# Root principals have write access
root_folder.access_for(root, :w => true)
temp_folder = Content.new('Temp', root_folder)
# All principals have read access
temp_folder.access_for(Principal.top, :r => true)
home_folder = Content.new('Home', root_folder)
user1_home_folder = Content.new('user1 home', home_folder)
# regular user has no read and write access to user1 home folder
user1_home_folder.access_for(reg_users, :r => false, :w => false)
user1_home_folder.access_for(user1, :r => true, :w => true)
# user1 has both read and write access to user1 home folder
user2_home_folder = Content.new('user2 home', home_folder)
a_file = Content.new("MyFile.pdf", user1_home_folder)
home_folder.show_access(root, :w)
home_folder.show_access(user1, :w)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment