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.
112 lines
2.8 KiB
112 lines
2.8 KiB
#!/usr/local/bin/ruby -w
|
|
|
|
# This is a trivial LDAP server which just stores directory entries in RAM.
|
|
# It does no validation or authentication. This is intended just to
|
|
# demonstrate the API, it's not for real-world use!!
|
|
|
|
$:.unshift('../lib')
|
|
$debug = true
|
|
|
|
require 'ldap/server'
|
|
|
|
# We subclass the Operation class, overriding the methods to do what we need
|
|
|
|
class HashOperation < LDAP::Server::Operation
|
|
def initialize(connection, messageID, hash)
|
|
super(connection, messageID)
|
|
@hash = hash # an object reference to our directory data
|
|
end
|
|
|
|
def search(basedn, scope, deref, filter)
|
|
basedn = basedn.downcase
|
|
|
|
case scope
|
|
when LDAP::Server::BaseObject
|
|
# client asked for single object by DN
|
|
obj = @hash[basedn]
|
|
raise LDAP::ResultError::NoSuchObject unless obj
|
|
send_SearchResultEntry(basedn, obj) if LDAP::Server::Filter.run(filter, obj)
|
|
|
|
when LDAP::Server::WholeSubtree
|
|
@hash.each do |dn, av|
|
|
next unless dn.index(basedn, -basedn.length) # under basedn?
|
|
next unless LDAP::Server::Filter.run(filter, av) # attribute filter?
|
|
send_SearchResultEntry(dn, av)
|
|
end
|
|
|
|
else
|
|
raise LDAP::ResultError::UnwillingToPerform, "OneLevel not implemented"
|
|
|
|
end
|
|
end
|
|
|
|
def add(dn, av)
|
|
dn = dn.downcase
|
|
raise LDAP::ResultError::EntryAlreadyExists if @hash[dn]
|
|
@hash[dn] = av
|
|
end
|
|
|
|
def del(dn)
|
|
dn = dn.downcase
|
|
raise LDAP::ResultError::NoSuchObject unless @hash.has_key?(dn)
|
|
@hash.delete(dn)
|
|
end
|
|
|
|
def modify(dn, ops)
|
|
dn = dn.downcase
|
|
entry = @hash[dn]
|
|
raise LDAP::ResultError::NoSuchObject unless entry
|
|
ops.each do |attr, vals|
|
|
op = vals.shift
|
|
case op
|
|
when :add
|
|
entry[attr] ||= []
|
|
entry[attr] += vals
|
|
entry[attr].uniq!
|
|
when :delete
|
|
if vals == []
|
|
entry.delete(attr)
|
|
else
|
|
vals.each { |v| entry[attr].delete(v) }
|
|
end
|
|
when :replace
|
|
entry[attr] = vals
|
|
end
|
|
entry.delete(attr) if entry[attr] == []
|
|
end
|
|
end
|
|
end
|
|
|
|
# This is the shared object which carries our actual directory entries.
|
|
# It's just a hash of {dn=>entry}, where each entry is {attr=>[val,val,...]}
|
|
|
|
directory = {}
|
|
|
|
# Let's put some backing store on it
|
|
|
|
require 'yaml'
|
|
begin
|
|
File.open("ldapdb.yaml") { |f| directory = YAML::load(f.read) }
|
|
rescue Errno::ENOENT
|
|
end
|
|
|
|
at_exit do
|
|
File.open("ldapdb.new","w") { |f| f.write(YAML::dump(directory)) }
|
|
File.rename("ldapdb.new","ldapdb.yaml")
|
|
end
|
|
|
|
# Listen for incoming LDAP connections. For each one, create a Connection
|
|
# object, which will invoke a HashOperation object for each request.
|
|
|
|
s = LDAP::Server.new(
|
|
:port => 1389,
|
|
:nodelay => true,
|
|
:listen => 10,
|
|
# :ssl_key_file => "key.pem",
|
|
# :ssl_cert_file => "cert.pem",
|
|
# :ssl_on_connect => true,
|
|
:operation_class => HashOperation,
|
|
:operation_args => [directory]
|
|
)
|
|
s.run_tcpserver
|
|
s.join
|