|
|
|
@ -1,62 +1,71 @@ |
|
|
|
#!/usr/bin/env ruby |
|
|
|
|
|
|
|
$:.unshift('lib') |
|
|
|
$debug = true |
|
|
|
|
|
|
|
$LOAD_PATH.unshift('lib') |
|
|
|
require 'ldap/server' |
|
|
|
|
|
|
|
$logger = Logger.new($stderr) |
|
|
|
# We subclass the Operation class, overriding the methods to do what we need |
|
|
|
LOGGER = Logger.new($stderr) |
|
|
|
|
|
|
|
# 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 |
|
|
|
def initialize(connection, message_id, hash) |
|
|
|
super(connection, message_id) |
|
|
|
@hash = hash |
|
|
|
end |
|
|
|
|
|
|
|
# ici, c'est bizarre |
|
|
|
# systèmatiquement appelé (SEARCH ou AUTH) |
|
|
|
# du coup, je retourne super si pas de dn => SEARCH normal sans authentication |
|
|
|
# sinon ça passe aussi !!! |
|
|
|
def do_bind(protocolOp, controls) # :nodoc: |
|
|
|
dn = protocolOp.value[1].value |
|
|
|
def do_bind(operation, _controls) |
|
|
|
dn = operation.value[1].value |
|
|
|
dn = nil if dn == '' |
|
|
|
return super if dn.nil? |
|
|
|
|
|
|
|
version = protocolOp.value[0].value |
|
|
|
authentication = protocolOp.value[2] |
|
|
|
password = authentication.value |
|
|
|
valid = password == 'toto' |
|
|
|
$logger.info("AUTHENTICATION ..version=#{version}, dn=#{dn}, valid=#{valid}") |
|
|
|
send_BindResponse(valid ? 0 : 1) |
|
|
|
password = operation.value[2].value |
|
|
|
email = extract_mail_from_dn(dn) |
|
|
|
authenticated = valid?(email, password) |
|
|
|
LOGGER.info("AUTHENTICATION email=#{email} => #{authenticated}") |
|
|
|
send_BindResponse(authenticated ? 0 : 1) |
|
|
|
end |
|
|
|
|
|
|
|
def search(basedn, scope, deref, filter) |
|
|
|
$logger.info("SEARCHING...basedn=#{basedn}, scope=#{scope}, deref=#{deref}, filter=#{filter}") |
|
|
|
def extract_mail_from_dn(entry) |
|
|
|
entry[/mail=(.*?),/, 1] # short for regex first capture |
|
|
|
end |
|
|
|
|
|
|
|
def valid?(_email, password) |
|
|
|
password == 'toto' |
|
|
|
end |
|
|
|
|
|
|
|
def search(basedn, scope, deref, filter) |
|
|
|
basedn = basedn.downcase |
|
|
|
nil |
|
|
|
LOGGER.info("SEARCHING...basedn=\"#{basedn}\", scope=#{scope}, deref=#{deref}, filter=#{filter}") |
|
|
|
case scope |
|
|
|
when LDAP::Server::BaseObject |
|
|
|
# client asked for single object by DN |
|
|
|
obj = @hash[basedn] |
|
|
|
raise LDAP::ResultError::NoSuchObject unless obj |
|
|
|
|
|
|
|
$logger.info('BaseObject') |
|
|
|
send_SearchResultEntry(basedn, obj) if LDAP::Server::Filter.run(filter, obj) |
|
|
|
if LDAP::Server::Filter.run(filter, obj) |
|
|
|
LOGGER.info("1 Base Found: #{obj}") |
|
|
|
send_SearchResultEntry(basedn, obj) |
|
|
|
end |
|
|
|
when LDAP::Server::WholeSubtree |
|
|
|
found = 0 |
|
|
|
@hash.each do |dn, av| |
|
|
|
next unless dn.index(basedn, -basedn.length) # under basedn? |
|
|
|
next unless LDAP::Server::Filter.run(filter, av) # attribute filter? |
|
|
|
|
|
|
|
$logger.info("WholeSubtree av=#{av}") |
|
|
|
found += 1 |
|
|
|
LOGGER.info("Found Filtered #{av}") |
|
|
|
send_SearchResultEntry(dn, av) |
|
|
|
end |
|
|
|
found = 'NO' if found == 0 |
|
|
|
LOGGER.info("#{found} items found") |
|
|
|
|
|
|
|
else |
|
|
|
raise LDAP::ResultError::UnwillingToPerform, 'OneLevel not implemented' |
|
|
|
|
|
|
|
end |
|
|
|
send_SearchResultDone(0) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
@ -66,11 +75,10 @@ end |
|
|
|
directory = {} |
|
|
|
require 'yaml' |
|
|
|
File.open('examples/ldapdb.yaml') { |f| directory = YAML.load(f.read) } |
|
|
|
$logger.info("DIRECTORY=#{directory}") |
|
|
|
LOGGER.info("DIRECTORY=#{directory}") |
|
|
|
|
|
|
|
# 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, |
|
|
|
@ -79,6 +87,6 @@ s = LDAP::Server.new( |
|
|
|
operation_args: [directory] |
|
|
|
) |
|
|
|
|
|
|
|
$logger.info('server2 RUNNING...') |
|
|
|
LOGGER.info('Ready to perform LDAP operations...') |
|
|
|
s.run_tcpserver |
|
|
|
s.join |