|
|
|
@ -1,100 +1,108 @@ |
|
|
|
require 'active_support/secure_random' |
|
|
|
require 'net/ldap' |
|
|
|
|
|
|
|
class SystemDataBackendLdap |
|
|
|
|
|
|
|
LDAP_USER_MAP = { |
|
|
|
:uid => :name, |
|
|
|
:userpassword => :pass, |
|
|
|
:uidnumber => :uid, |
|
|
|
:gidnumber => :gid, |
|
|
|
:loginshell => :shell, |
|
|
|
:homedirectory => :home |
|
|
|
} |
|
|
|
|
|
|
|
LDAP_GROUP_MAP = { |
|
|
|
:cn => :name, |
|
|
|
:gidnumber => :gid, |
|
|
|
:memberuid => :members |
|
|
|
} |
|
|
|
|
|
|
|
LDAP_SITE_MAP = {:o => :name} |
|
|
|
|
|
|
|
LDAP_MAP = { |
|
|
|
:User => LDAP_USER_MAP, |
|
|
|
:Group => LDAP_GROUP_MAP, |
|
|
|
:Site => LDAP_SITE_MAP |
|
|
|
} |
|
|
|
|
|
|
|
LDAP_FILTER = { |
|
|
|
:User => Net::LDAP::Filter::eq('objectClass', 'posixAccount'), |
|
|
|
:Group => Net::LDAP::Filter::eq('objectClass', 'posixGroup'), |
|
|
|
:Site => Net::LDAP::Filter::eq('objectClass', 'organization') & |
|
|
|
(~Net::LDAP::Filter::eq('o', 'hosting')), |
|
|
|
:MailAlias => Net::LDAP::Filter::eq('objectClass', 'mailAlias'), |
|
|
|
:MailAccount => Net::LDAP::Filter::eq('objectClass', 'mailAccount') |
|
|
|
} |
|
|
|
|
|
|
|
LDAP_OBJECTCLASS = { |
|
|
|
:User => [ 'account', 'posixAccount', 'shadowAccount' ], |
|
|
|
:Group => 'posixGroup' |
|
|
|
} |
|
|
|
|
|
|
|
LDAP_LAMBDA_USER = lambda do |entry| |
|
|
|
entry[:cn] = entry[:uid] |
|
|
|
entry[:shadowlastchange] = (Time::now.to_i/60/60/24).to_s |
|
|
|
entry[:replace] += ['shadowreplace'] if entry[:replace] |
|
|
|
end |
|
|
|
require 'active_support/secure_random' |
|
|
|
require 'net/ldap' |
|
|
|
|
|
|
|
class SystemDataBackendLdap |
|
|
|
|
|
|
|
LDAP_USER_MAP = { |
|
|
|
:uid => :name, |
|
|
|
:userpassword => :pass, |
|
|
|
:uidnumber => :uid, |
|
|
|
:gidnumber => :gid, |
|
|
|
:loginshell => :shell, |
|
|
|
:homedirectory => :home |
|
|
|
} |
|
|
|
|
|
|
|
LDAP_GROUP_MAP = { |
|
|
|
:cn => :name, |
|
|
|
:gidnumber => :gid, |
|
|
|
:memberuid => :members |
|
|
|
} |
|
|
|
|
|
|
|
LDAP_SITE_MAP = {:o => :name} |
|
|
|
|
|
|
|
LDAP_MAP = { |
|
|
|
:User => LDAP_USER_MAP, |
|
|
|
:Group => LDAP_GROUP_MAP, |
|
|
|
:Site => LDAP_SITE_MAP |
|
|
|
} |
|
|
|
|
|
|
|
LDAP_FILTER = { |
|
|
|
:User => Net::LDAP::Filter::eq('objectClass', 'posixAccount'), |
|
|
|
:Group => Net::LDAP::Filter::eq('objectClass', 'posixGroup'), |
|
|
|
:Site => Net::LDAP::Filter::eq('objectClass', 'organization') & |
|
|
|
(~Net::LDAP::Filter::eq('o', 'hosting')), |
|
|
|
:MailAlias => Net::LDAP::Filter::eq('objectClass', 'mailAlias'), |
|
|
|
:MailAccount => Net::LDAP::Filter::eq('objectClass', 'mailAccount') |
|
|
|
} |
|
|
|
|
|
|
|
LDAP_OBJECTCLASS = { |
|
|
|
:User => [ 'account', 'posixAccount', 'shadowAccount' ], |
|
|
|
:Group => 'posixGroup', |
|
|
|
:Site => 'organization' |
|
|
|
} |
|
|
|
|
|
|
|
LDAP_LAMBDA_USER = lambda do |entry| |
|
|
|
entry[:cn] = entry[:uid] |
|
|
|
entry[:shadowlastchange] = (Time::now.to_i/60/60/24).to_s |
|
|
|
entry[:replace] += ['shadowreplace'] if entry[:replace] |
|
|
|
end |
|
|
|
|
|
|
|
LDAP_LAMBDA = { |
|
|
|
:User => LDAP_LAMBDA_USER |
|
|
|
} |
|
|
|
LDAP_LAMBDA = { |
|
|
|
:User => LDAP_LAMBDA_USER |
|
|
|
} |
|
|
|
|
|
|
|
def initialize(host, port, baseDn, args={}) |
|
|
|
@baseDn = baseDn |
|
|
|
@systemDn = 'o=system,' + @baseDn |
|
|
|
@hostingDn = 'o=hosting,' + @baseDn |
|
|
|
def initialize(host, port, baseDn, args={}) |
|
|
|
@baseDn = baseDn |
|
|
|
@systemDn = 'o=system,' + @baseDn |
|
|
|
@hostingDn = 'o=hosting,' + @baseDn |
|
|
|
|
|
|
|
@systemDn = args[:systemDn] if args[:systemDn] |
|
|
|
@hostingDn = args[:hostingDn] if args[:hostingDn] |
|
|
|
@systemDn = args[:systemDn] if args[:systemDn] |
|
|
|
@hostingDn = args[:hostingDn] if args[:hostingDn] |
|
|
|
|
|
|
|
@ldap = Net::LDAP.new(:host => host, :port => port) |
|
|
|
@ldapData = Hash.new |
|
|
|
end |
|
|
|
@ldap = Net::LDAP.new(:host => host, :port => port) |
|
|
|
@ldapData = Hash.new |
|
|
|
end |
|
|
|
|
|
|
|
def load!(kind) |
|
|
|
@ldapData[kind] = Hash.new if ! @ldapData[kind] |
|
|
|
def load!(kind) |
|
|
|
@ldapData[kind] = Hash.new if ! @ldapData[kind] |
|
|
|
|
|
|
|
@ldapData[kind][:internal] = @ldap.search( |
|
|
|
:base => ldapBase(kind), |
|
|
|
:filter => LDAP_FILTER[kind] |
|
|
|
) |
|
|
|
end |
|
|
|
@ldapData[kind][:internal] = @ldap.search( |
|
|
|
:base => ldapBase(kind), |
|
|
|
:filter => LDAP_FILTER[kind] |
|
|
|
) |
|
|
|
end |
|
|
|
|
|
|
|
def load(kind) |
|
|
|
load!(kind) if ! @ldapData[kind] |
|
|
|
def load(kind) |
|
|
|
load!(kind) if ! @ldapData[kind] |
|
|
|
|
|
|
|
@ldapData[kind][:external] = @ldapData[kind][:internal].map do |data| |
|
|
|
map = { :dn => :id } |
|
|
|
map.merge!(LDAP_MAP[kind]) if LDAP_MAP[kind] |
|
|
|
@ldapData[kind][:external] = @ldapData[kind][:internal].map do |data| |
|
|
|
map = { :dn => :id } |
|
|
|
map.merge!(LDAP_MAP[kind]) if LDAP_MAP[kind] |
|
|
|
|
|
|
|
ydata = {} |
|
|
|
data.each do |key,value| |
|
|
|
ydata.merge!({ map[key] || key => value.size==1?value[0]:value.to_a }) |
|
|
|
end |
|
|
|
ydata |
|
|
|
end if ! @ldapData[kind][:external] |
|
|
|
ydata = {} |
|
|
|
data.each do |key,value| |
|
|
|
ydata.merge!({ map[key] || key => value.size==1?value[0]:value.to_a }) |
|
|
|
end |
|
|
|
ydata |
|
|
|
end if ! @ldapData[kind][:external] |
|
|
|
|
|
|
|
@ldapData[kind][:external].each{|ydata| yield ydata} |
|
|
|
@ldapData[kind][:external].each{|ydata| yield ydata} |
|
|
|
end |
|
|
|
|
|
|
|
def update(kind, data) |
|
|
|
map = {} |
|
|
|
map.merge!(LDAP_MAP[kind].invert) if LDAP_MAP[kind] |
|
|
|
|
|
|
|
entry = Net::LDAP::Entry.new(data[:id]) |
|
|
|
|
|
|
|
odata = @ldapData[kind][:external].find{|edata| edata[:id] == data[:id]} |
|
|
|
|
|
|
|
data.each do |key,value| |
|
|
|
pat_key = map[key] ? map[key] : key |
|
|
|
if odata[:id] =~ /(^|, *)#{pat_key.to_s}=([^, ]+)/ && $2 != value |
|
|
|
return replace(kind, data) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
entry = Net::LDAP::Entry.new(data[:id]) |
|
|
|
data = data.find_all{|key,value| value != odata[key]} |
|
|
|
data.delete(:id) |
|
|
|
|
|
|
|
@ -105,17 +113,52 @@ class SystemDataBackendLdap |
|
|
|
entry[key] = value |
|
|
|
end |
|
|
|
|
|
|
|
if not replace.empty? |
|
|
|
if replace.empty? |
|
|
|
puts 'INFO: no changes' |
|
|
|
else |
|
|
|
entry[:changetype] = 'modify' |
|
|
|
entry[:replace] = replace |
|
|
|
LDAP_LAMBDA[kind].call(entry) if LDAP_LAMBDA[kind] |
|
|
|
|
|
|
|
puts entry.to_ldif |
|
|
|
else |
|
|
|
puts 'INFO: no changes' |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
def replace(kind, data) |
|
|
|
puts 'INFO: do replace' |
|
|
|
puts '----------------' |
|
|
|
odata = @ldapData[kind][:external].find{|edata| edata[:id] == data[:id]} |
|
|
|
delete(odata) |
|
|
|
puts |
|
|
|
insert(kind, data) |
|
|
|
puts '----------------' |
|
|
|
end |
|
|
|
|
|
|
|
def delete(data) |
|
|
|
entry = Net::LDAP::Entry.new(data[:id]) |
|
|
|
entry[:changetype] = 'delete' |
|
|
|
|
|
|
|
puts entry.to_ldif |
|
|
|
end |
|
|
|
|
|
|
|
def insert(kind, data) |
|
|
|
map = {} |
|
|
|
map.merge!(LDAP_MAP[kind].invert) if LDAP_MAP[kind] |
|
|
|
|
|
|
|
data.delete(:id) |
|
|
|
entry = Net::LDAP::Entry.new(ldapDn(kind, data)) |
|
|
|
entry[:changetype] = 'add' |
|
|
|
entry[:objectclass] = LDAP_OBJECTCLASS[kind] |
|
|
|
|
|
|
|
data.each do |key,value| |
|
|
|
key = map[key] if map[key] |
|
|
|
entry[key] = value |
|
|
|
end |
|
|
|
LDAP_LAMBDA[kind].call(entry) if LDAP_LAMBDA[kind] |
|
|
|
|
|
|
|
puts entry.to_ldif |
|
|
|
end |
|
|
|
|
|
|
|
private |
|
|
|
|
|
|
|
def ldapBase(kind) |
|
|
|
@ -125,4 +168,17 @@ class SystemDataBackendLdap |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
def ldapDn(kind, data) |
|
|
|
case(kind) |
|
|
|
when :User |
|
|
|
"uid=#{data[:name]},ou=user,#{ldapBase(kind)}" |
|
|
|
when :Group |
|
|
|
"cn=#{data[:name]},ou=group,#{ldapBase(kind)}" |
|
|
|
when :Site |
|
|
|
"o=#{data[:name]},#{ldapBase(kind)}" |
|
|
|
else |
|
|
|
"not yet implemented" |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
end |