You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
92 lines
2.4 KiB
92 lines
2.4 KiB
require 'ldap/server/dn'
|
|
|
|
module LDAP
|
|
class Server
|
|
class Trie
|
|
|
|
# Trie or prefix tree suitable for storing LDAP paths
|
|
# Variables (wildcards) are supported
|
|
|
|
class NodeNotFoundError < Error; end
|
|
|
|
attr_accessor :parent, :value, :children
|
|
|
|
# Create a new Trie. Use with a block
|
|
def initialize(parent = nil, value = nil)
|
|
@parent = parent
|
|
@value = value
|
|
@children = Hash.new
|
|
|
|
yield self if block_given?
|
|
end
|
|
|
|
# Insert a path (empty node)
|
|
def <<(dn)
|
|
insert(dn)
|
|
end
|
|
|
|
# Insert a node with a value
|
|
def insert(dn, value = nil)
|
|
dn = LDAP::Server::DN.new(dn || '') if not dn.is_a? LDAP::Server::DN
|
|
dn.reverse_each do |component|
|
|
@children[component] = Trie.new(self) if @children[component].nil?
|
|
dn.dname.pop
|
|
if dn.any?
|
|
@children[component].insert dn, value
|
|
else
|
|
@children[component].value = value
|
|
end
|
|
end
|
|
end
|
|
|
|
# Looks up a node and returns its value or raises
|
|
# LDAP::Server::Trie::NodeNotFoundError if it's not in the tree
|
|
def lookup(dn)
|
|
dn = LDAP::Server::DN.new(dn || '') if not dn.is_a? LDAP::Server::DN
|
|
return @value if dn.dname.empty?
|
|
component = dn.dname.pop
|
|
@children.each do |key, value|
|
|
if key.keys.first == component.keys.first
|
|
if key.values.first.start_with?(':') or key.values.first == component.values.first
|
|
return value.lookup dn
|
|
end
|
|
end
|
|
end
|
|
raise NodeNotFoundError
|
|
end
|
|
|
|
# Looks up a node and returns its value or the (non-nil) value of
|
|
# the nearest ancestor.
|
|
def match(dn, path = '')
|
|
dn = LDAP::Server::DN.new(dn || '') if not dn.is_a? LDAP::Server::DN
|
|
return path, @value if dn.dname.empty?
|
|
component = dn.dname.pop
|
|
@children.each do |key, value|
|
|
if key.keys.first == component.keys.first
|
|
if key.values.first.start_with?(':') or key.values.first == component.values.first
|
|
path.prepend ',' unless path.empty?
|
|
path.prepend "#{LDAP::Server::DN.join key}"
|
|
new_path, new_value = value.match dn, path
|
|
if new_value
|
|
return new_path, new_value
|
|
else
|
|
return (@value ? path : nil), @value
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return path, @value
|
|
end
|
|
|
|
def print_tree(prefix = '')
|
|
if @value
|
|
p "#{prefix}{{#{@value}}}"
|
|
end
|
|
@children.each do |key, value|
|
|
p "#{prefix}#{key.keys.first} => #{key.values.first}"
|
|
@children[key].print_tree("#{prefix} ")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|