37 changed files with 296 additions and 993 deletions
-
14Group.rb
-
17MailAccount.rb
-
18MailAliasPerson.rb
-
17MailAliasRole.rb
-
11Site.rb
-
24SystemData.rb
-
91SystemDataBackend.rb
-
197SystemDataBackendLdap.rb
-
18User.rb
-
91controllers/system_data.rb
-
10database.rb
-
13database/base.rb
-
3database/factory.rb
-
53database/ldap.rb
-
BINdocs/development/mystuff.dia
-
66docs/development/was.txt
-
4ds_admin.rb
-
0loader/user.rb
-
197mappers/ldap.rb
-
72model.rb
-
9model/base.rb
-
12model/group.rb
-
7model/interface.rb
-
5model/mail_account.rb
-
5model/mail_alias_person.rb
-
5model/mail_alias_role.rb
-
5model/site.rb
-
24model/system_data.rb
-
30model/user.rb
-
10sd_admin.rb
-
37storage.rb
-
21storage/config.rb
-
34storage/ldap.rb
-
3storage/mysql.rb
-
123test_dummy.rb
-
5test_dummy2.rb
-
38tester.rb
@ -1,14 +0,0 @@ |
|||
require 'SystemData' |
|||
|
|||
class Group < SystemData |
|||
attr_accessor :name, :gid, :members |
|||
|
|||
def initialize(args = {}) |
|||
super(args) |
|||
|
|||
@name = args[:name] |
|||
@gid = args[:gid] |
|||
@members = args[:members] |
|||
@members = Array.new if @members.nil? |
|||
end |
|||
end |
|||
@ -1,17 +0,0 @@ |
|||
require 'SystemData' |
|||
|
|||
class MailAccount < SystemData |
|||
attr_accessor :mail, :mailbox |
|||
|
|||
def initialize(args = {}) |
|||
super(args) |
|||
|
|||
@mail = args[:mail] |
|||
@home = args[:home] |
|||
@mailbox = args[:mailbox] |
|||
end |
|||
|
|||
def site |
|||
@mail.sub(/.*@/, '') |
|||
end |
|||
end |
|||
@ -1,18 +0,0 @@ |
|||
require 'SystemData' |
|||
|
|||
class MailAliasPerson < SystemData |
|||
attr_accessor :mail, :maildrop, :surname, :name |
|||
|
|||
def initialize(args = {}) |
|||
super(args) |
|||
|
|||
@mail = args[:mail] |
|||
@maildrop = args[:maildrop] |
|||
@surname = args[:surname] |
|||
@name = args[:name] |
|||
end |
|||
|
|||
def site |
|||
@mail.sub(/.*@/, '') |
|||
end |
|||
end |
|||
@ -1,17 +0,0 @@ |
|||
require 'SystemData' |
|||
|
|||
class MailAliasRole < SystemData |
|||
attr_accessor :mail, :maildrop, :user |
|||
|
|||
def initialize(args = {}) |
|||
super(args) |
|||
|
|||
@mail = args[:mail] |
|||
@maildrop = args[:maildrop] |
|||
@user = args[:user] |
|||
end |
|||
|
|||
def site |
|||
@mail.sub(/.*@/, '') |
|||
end |
|||
end |
|||
@ -1,11 +0,0 @@ |
|||
require 'SystemData' |
|||
|
|||
class Site < SystemData |
|||
attr_accessor :name |
|||
|
|||
def initialize(args = {}) |
|||
super(args) |
|||
|
|||
@name = args[:name] |
|||
end |
|||
end |
|||
@ -1,24 +0,0 @@ |
|||
class SystemData |
|||
attr_reader :id |
|||
|
|||
def initialize(args = {}) |
|||
@backend = args[:backend] |
|||
@id = args[:id] |
|||
end |
|||
|
|||
def save |
|||
kind = self.class.to_s.to_sym |
|||
|
|||
if @id |
|||
@backend.update(kind, to_h) |
|||
else |
|||
@backend.insert(kind, to_h) |
|||
end |
|||
end |
|||
|
|||
def to_h |
|||
Hash[instance_variables.map do |var| |
|||
[var[1...var.size].to_sym, eval(var)] if var != '@backend' |
|||
end] |
|||
end |
|||
end |
|||
@ -1,91 +0,0 @@ |
|||
require 'User' |
|||
require 'Group' |
|||
require 'Site' |
|||
require 'MailAliasRole' |
|||
require 'MailAliasPerson' |
|||
require 'MailAccount' |
|||
|
|||
class SystemDataBackend |
|||
|
|||
def initialize(backend) |
|||
@backend = backend |
|||
@data = Hash.new |
|||
end |
|||
|
|||
def users |
|||
load(:User) |
|||
end |
|||
|
|||
def groups |
|||
load(:Group) |
|||
end |
|||
|
|||
def sites |
|||
load(:Site) |
|||
end |
|||
|
|||
def mailAliasRoles |
|||
load(:MailAliasRole) |
|||
end |
|||
|
|||
def mailAliasPeople |
|||
load(:MailAliasPerson) |
|||
end |
|||
|
|||
def mailAccounts |
|||
load(:MailAccount) |
|||
end |
|||
|
|||
def userByName(name) |
|||
users.find{|user| user.name == name} |
|||
end |
|||
|
|||
def groupByName(name) |
|||
groups.find{|group| group.name == name} |
|||
end |
|||
|
|||
def siteByName(name) |
|||
sites.find{|site| site.name == name} |
|||
end |
|||
|
|||
def usersInGroup(group) |
|||
case |
|||
when group.members.instance_of?(Array): |
|||
Hash[group.members.map{|uid| [uid, userByName(uid)] if userByName(uid)}] |
|||
when goup.members.nil?: |
|||
{} |
|||
else |
|||
{group.members => userByName(group.members)} if userByName(group.members) |
|||
end |
|||
end |
|||
|
|||
def mailAliasRolesBySite(site) |
|||
mailAliasRoles.find_all{|mail| mail.site == site.name} |
|||
end |
|||
|
|||
def mailAliasPeopleBySite(site) |
|||
mailAliasPeople.find_all{|mail| mail.site == site.name} |
|||
end |
|||
|
|||
def mailAccountsBySite(site) |
|||
mailAccounts.find_all{|mail| mail.site == site.name} |
|||
end |
|||
|
|||
private |
|||
|
|||
def load(kind) |
|||
load!(kind) if ! @data[kind] |
|||
@data[kind] |
|||
end |
|||
|
|||
def load!(kind) |
|||
@data[kind] = Array.new |
|||
@backend.load(kind) do |data| |
|||
data[:backend] = @backend |
|||
@data[kind].push( |
|||
eval(kind.to_s + '.new(data)') |
|||
) |
|||
end |
|||
end |
|||
|
|||
end |
|||
@ -1,197 +0,0 @@ |
|||
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_MAILALIASPERSON_MAP = { |
|||
:sn => :surname, |
|||
:cn => :name |
|||
} |
|||
|
|||
LDAP_MAP = { |
|||
:User => LDAP_USER_MAP, |
|||
:Group => LDAP_GROUP_MAP, |
|||
:Site => { :o => :name }, |
|||
:MailAliasRole => { :cn => :user }, |
|||
:MailAliasPerson => LDAP_MAILALIASPERSON_MAP, |
|||
:mailAccount => { :homedirectory => :home } |
|||
} |
|||
|
|||
LDAP_FILTER = { |
|||
:User => '(objectClass=posixAccount)', |
|||
:Group => '(objectClass=posixGroup)', |
|||
:Site => '(&(objectClass=organization)(!(o=hosting)))', |
|||
:MailAliasRole => '(&(objectClass=MailAlias)(objectClass=organizationalrole))', |
|||
:MailAliasPerson => '(&(objectClass=MailAlias)(objectClass=person))', |
|||
:MailAccount => '(objectClass=mailAccount)' |
|||
} |
|||
|
|||
LDAP_OBJECTCLASS = { |
|||
:User => [ 'account', 'posixAccount', 'shadowAccount' ], |
|||
:Group => 'posixGroup', |
|||
:Site => 'organization', |
|||
:MailAliasRole => [ 'organizationalRole', 'MailAlias' ], |
|||
:MailAliasPerson => [ 'person', 'MailAlias' ], |
|||
:MailAccount => [ 'person', 'MailAccount' ] |
|||
} |
|||
|
|||
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 |
|||
} |
|||
|
|||
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] |
|||
|
|||
@ldap = Net::LDAP.new(:host => host, :port => port) |
|||
@ldapData = Hash.new |
|||
end |
|||
|
|||
def load!(kind) |
|||
@ldapData[kind] = Hash.new if ! @ldapData[kind] |
|||
|
|||
@ldapData[kind][:int] = @ldap.search( |
|||
:base => ldapBase(kind), |
|||
:filter => Net::LDAP::Filter::construct(LDAP_FILTER[kind]) |
|||
) |
|||
end |
|||
|
|||
def load(kind) |
|||
load!(kind) if ! @ldapData[kind] |
|||
|
|||
@ldapData[kind][:ext] = @ldapData[kind][:int].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][:ext] && @ldapData[kind][:int] |
|||
|
|||
@ldapData[kind][:ext].each{|ydata| yield ydata} if @ldapData[kind][:ext] |
|||
end |
|||
|
|||
def update(kind, data) |
|||
map = {} |
|||
map.merge!(LDAP_MAP[kind].invert) if LDAP_MAP[kind] |
|||
|
|||
odata = @ldapData[kind][:ext].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) |
|||
|
|||
replace = Array.new |
|||
data.each do |key,value| |
|||
key = map[key] if map[key] |
|||
replace.push(key.to_s) |
|||
entry[key] = value |
|||
end |
|||
|
|||
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 |
|||
end |
|||
end |
|||
|
|||
def replace(kind, data) |
|||
puts 'INFO: do replace' |
|||
puts '----------------' |
|||
odata = @ldapData[kind][:ext].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) |
|||
case(kind) |
|||
when :User, :Group: @systemDn |
|||
when :Site, :MailAliasRole, :MailAliasPerson, :MailAccount: @hostingDn |
|||
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)}" |
|||
when :MailAliasRole |
|||
"cn=#{data[:user]},o=#{data[:mail].sub(/.*@/, '')},#{ldapBase(kind)}" |
|||
when :MailAliasPerson |
|||
"mail=#{data[:mail]},o=#{data[:mail].sub(/.*@/, '')},#{ldapBase(kind)}" |
|||
when :MailAccount |
|||
"mail=#{data[:mail]},o=#{data[:mail].sub(/.*@/, '')},#{ldapBase(kind)}" |
|||
end |
|||
end |
|||
|
|||
end |
|||
@ -1,18 +0,0 @@ |
|||
require 'SystemData' |
|||
|
|||
class User < SystemData |
|||
attr_accessor :name, :pass, :uid, :gid, :shell, :home |
|||
|
|||
def initialize(args = {}) |
|||
super(args) |
|||
|
|||
@name = args[:name] |
|||
@pass = args[:pass] |
|||
@uid = args[:uid] |
|||
@gid = args[:gid] |
|||
@shell = args[:shell] |
|||
@home = args[:home] |
|||
@shadowmax = args[:shadowmax] |
|||
@shadowwarning = args[:shadowwarning] |
|||
end |
|||
end |
|||
@ -1,91 +0,0 @@ |
|||
require 'User' |
|||
require 'Group' |
|||
require 'Site' |
|||
require 'MailAliasRole' |
|||
require 'MailAliasPerson' |
|||
require 'MailAccount' |
|||
|
|||
class SystemDataBackend |
|||
|
|||
def initialize(backend) |
|||
@backend = backend |
|||
@data = Hash.new |
|||
end |
|||
|
|||
def users |
|||
load(:User) |
|||
end |
|||
|
|||
def groups |
|||
load(:Group) |
|||
end |
|||
|
|||
def sites |
|||
load(:Site) |
|||
end |
|||
|
|||
def mailAliasRoles |
|||
load(:MailAliasRole) |
|||
end |
|||
|
|||
def mailAliasPeople |
|||
load(:MailAliasPerson) |
|||
end |
|||
|
|||
def mailAccounts |
|||
load(:MailAccount) |
|||
end |
|||
|
|||
def userByName(name) |
|||
users.find{|user| user.name == name} |
|||
end |
|||
|
|||
def groupByName(name) |
|||
groups.find{|group| group.name == name} |
|||
end |
|||
|
|||
def siteByName(name) |
|||
sites.find{|site| site.name == name} |
|||
end |
|||
|
|||
def usersInGroup(group) |
|||
case |
|||
when group.members.instance_of?(Array): |
|||
Hash[group.members.map{|uid| [uid, userByName(uid)] if userByName(uid)}] |
|||
when goup.members.nil?: |
|||
{} |
|||
else |
|||
{group.members => userByName(group.members)} if userByName(group.members) |
|||
end |
|||
end |
|||
|
|||
def mailAliasRolesBySite(site) |
|||
mailAliasRoles.find_all{|mail| mail.site == site.name} |
|||
end |
|||
|
|||
def mailAliasPeopleBySite(site) |
|||
mailAliasPeople.find_all{|mail| mail.site == site.name} |
|||
end |
|||
|
|||
def mailAccountsBySite(site) |
|||
mailAccounts.find_all{|mail| mail.site == site.name} |
|||
end |
|||
|
|||
private |
|||
|
|||
def load(kind) |
|||
load!(kind) if ! @data[kind] |
|||
@data[kind] |
|||
end |
|||
|
|||
def load!(kind) |
|||
@data[kind] = Array.new |
|||
@backend.load(kind) do |data| |
|||
data[:backend] = @backend |
|||
@data[kind].push( |
|||
eval(kind.to_s + '.new(data)') |
|||
) |
|||
end |
|||
end |
|||
|
|||
end |
|||
@ -1,10 +0,0 @@ |
|||
module SdAdmin::Database |
|||
class Ldap |
|||
require 'database/base.rb' |
|||
require 'net/ldap' |
|||
|
|||
include Enumerable |
|||
end |
|||
|
|||
require 'database/ldap' |
|||
end |
|||
@ -1,13 +0,0 @@ |
|||
class SdAdmin::Database::Base |
|||
|
|||
def initialize |
|||
@data = Hash.new |
|||
end |
|||
|
|||
def _create(data) |
|||
end |
|||
|
|||
def _read(id) |
|||
end |
|||
|
|||
end |
|||
@ -1,3 +0,0 @@ |
|||
class SdAdmin::Database::Factory |
|||
|
|||
end |
|||
@ -1,53 +0,0 @@ |
|||
class SdAdmin::Database::Ldap |
|||
attr_writer :base_dn, :mapper |
|||
|
|||
def initialize(args = {}) |
|||
@con = {:host => 'host.one.virtual', :port => 389} |
|||
|
|||
@con[:host] = args[:host] if args[:host] |
|||
@con[:port] = args[:port] if args[:port] |
|||
|
|||
@base_dn = args[:base_dn] if args[:base_dn] |
|||
|
|||
@ldap = Net::LDAP.new(@con) |
|||
filter = args[:filter] if args[:filter] |
|||
end |
|||
|
|||
def filter=(filter) |
|||
@filter = Net::LDAP::Filter::construct(filter) |
|||
end |
|||
|
|||
def each |
|||
_load.each{|key,entry| puts "DEBUG: #{key}"; yield key,entry} |
|||
end |
|||
|
|||
def [](id) |
|||
_load[id] |
|||
end |
|||
|
|||
def []=(id, data) |
|||
end |
|||
|
|||
def insert(data) |
|||
end |
|||
|
|||
def delete(id) |
|||
end |
|||
|
|||
private |
|||
|
|||
def _load! |
|||
@data = Hash.new |
|||
@ldap.search(:base => @base_dn, :filter => @filter) do |entry| |
|||
attributes = Hash.new |
|||
entry.each{|attr,value| attributes.merge!({attr => value})} |
|||
@data.merge!({attributes[:dn][0] => attributes}) |
|||
end |
|||
end |
|||
|
|||
def _load |
|||
_load! if ! @data |
|||
@data |
|||
end |
|||
|
|||
end |
|||
@ -0,0 +1,66 @@ |
|||
was wir haben. |
|||
|
|||
- verschiedene Model (user, group, mailAccount, mailALias, etc.) |
|||
- diese koennen in verschiedenen Datenquellen liegen |
|||
- die Datenquellen werden mit verschiedenen Abfragesprachen abgefragt. |
|||
- das entsprechende Model bestimmt welche Daten abgefragt werden. |
|||
- die Datenquelle bestimmt wie diese Daten abgefragt werden. |
|||
|
|||
Konflikt: bei ldap laesst sich das wie nur schwer von dem was abgefragt |
|||
werden soll trennen. |
|||
|
|||
Moegliche Loesung: eine Factory, die ueber die Klasse des Models und |
|||
die Klasse der Datenbank eine solche konkrete Datenbank initialisiert. |
|||
|
|||
Variation: anstatt eine factory zu bauen koennte man eine generische |
|||
Datenbankklasse bauen die eine Klassenmethode bekommt ueber die mit |
|||
dem reingegebenen Model dann eine Instanz erzeugt wird. |
|||
|
|||
Problem: Die Datenbankklasse muss dann Initialisierungsinformationen |
|||
zu den entsprechenden Models kennen. (Implementierungsdetail) |
|||
Um die Datenbankklasse generisch zu halten sollte diese Information |
|||
woanders her kommen, allerdings nicht aus dem Model, da dann wiederum |
|||
die Model Implementierungsdetails der Datenbankklasse kennen muessen. |
|||
|
|||
Evtl.: laesst sich was ueber Name conventions machen. Sauberer scheint |
|||
mir aber zu sein das es zu jeder Datenbankklasse eine Konfigurationsdatei |
|||
gibt in der man die Eckdaten fuer die Abfragen der einzelnen Model |
|||
konfigurieren kann. |
|||
|
|||
ein yaml koennte evtl. so aussehen: (ldap.yml) |
|||
|
|||
ldap: # => wenn es pro Datenbank ne eigenen datei gibt ist das nicht noetig |
|||
host: host.one.virtual |
|||
port: 389 |
|||
queries: |
|||
User: |
|||
baseDn: ou=user,o=system,dc=weird-web-workers,dc=org |
|||
filter: (objectClass=posixAccount) |
|||
Group: |
|||
baseDn: ou=group,o=system,dc=weird-web-workers,dc=org |
|||
filter: (objectClass=posixGroup) |
|||
|
|||
... |
|||
|
|||
alternativ zu einer Datei koennte man eine Mapping Datei zu jeder Kombination |
|||
aus Model und Datenbanktyp anlegen...diese waeren schoen klein schnell gelesen |
|||
und geschrieben. |
|||
|
|||
Dateistruktur: |
|||
|
|||
- model - user.rb |
|||
- group.rb |
|||
- site.rb |
|||
- mailalias_role.rb |
|||
- mailalias_person.rb |
|||
- mailaccount.rb |
|||
- data - ldap.rb |
|||
- data - config - ldap.yml |
|||
- adapter - ldap.rb |
|||
- config - ldap - user.yml |
|||
- group.yml |
|||
- site.yml |
|||
- mailalias_role.yml |
|||
- mailalias_person.yml |
|||
- mailaccount.yml |
|||
|
|||
@ -0,0 +1,4 @@ |
|||
module DsAdmin |
|||
DsAdmin.autoload(:Model, 'model') |
|||
DsAdmin.autoload(:Storage, 'storage') |
|||
end |
|||
@ -1,197 +0,0 @@ |
|||
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_MAILALIASPERSON_MAP = { |
|||
:sn => :surname, |
|||
:cn => :name |
|||
} |
|||
|
|||
LDAP_MAP = { |
|||
:User => LDAP_USER_MAP, |
|||
:Group => LDAP_GROUP_MAP, |
|||
:Site => { :o => :name }, |
|||
:MailAliasRole => { :cn => :user }, |
|||
:MailAliasPerson => LDAP_MAILALIASPERSON_MAP, |
|||
:mailAccount => { :homedirectory => :home } |
|||
} |
|||
|
|||
LDAP_FILTER = { |
|||
:User => '(objectClass=posixAccount)', |
|||
:Group => '(objectClass=posixGroup)', |
|||
:Site => '(&(objectClass=organization)(!(o=hosting)))', |
|||
:MailAliasRole => '(&(objectClass=MailAlias)(objectClass=organizationalrole))', |
|||
:MailAliasPerson => '(&(objectClass=MailAlias)(objectClass=person))', |
|||
:MailAccount => '(objectClass=mailAccount)' |
|||
} |
|||
|
|||
LDAP_OBJECTCLASS = { |
|||
:User => [ 'account', 'posixAccount', 'shadowAccount' ], |
|||
:Group => 'posixGroup', |
|||
:Site => 'organization', |
|||
:MailAliasRole => [ 'organizationalRole', 'MailAlias' ], |
|||
:MailAliasPerson => [ 'person', 'MailAlias' ], |
|||
:MailAccount => [ 'person', 'MailAccount' ] |
|||
} |
|||
|
|||
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 |
|||
} |
|||
|
|||
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] |
|||
|
|||
@ldap = Net::LDAP.new(:host => host, :port => port) |
|||
@ldapData = Hash.new |
|||
end |
|||
|
|||
def load!(kind) |
|||
@ldapData[kind] = Hash.new if ! @ldapData[kind] |
|||
|
|||
@ldapData[kind][:int] = @ldap.search( |
|||
:base => ldapBase(kind), |
|||
:filter => Net::LDAP::Filter::construct(LDAP_FILTER[kind]) |
|||
) |
|||
end |
|||
|
|||
def load(kind) |
|||
load!(kind) if ! @ldapData[kind] |
|||
|
|||
@ldapData[kind][:ext] = @ldapData[kind][:int].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][:ext] && @ldapData[kind][:int] |
|||
|
|||
@ldapData[kind][:ext].each{|ydata| yield ydata} if @ldapData[kind][:ext] |
|||
end |
|||
|
|||
def update(kind, data) |
|||
map = {} |
|||
map.merge!(LDAP_MAP[kind].invert) if LDAP_MAP[kind] |
|||
|
|||
odata = @ldapData[kind][:ext].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) |
|||
|
|||
replace = Array.new |
|||
data.each do |key,value| |
|||
key = map[key] if map[key] |
|||
replace.push(key.to_s) |
|||
entry[key] = value |
|||
end |
|||
|
|||
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 |
|||
end |
|||
end |
|||
|
|||
def replace(kind, data) |
|||
puts 'INFO: do replace' |
|||
puts '----------------' |
|||
odata = @ldapData[kind][:ext].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) |
|||
case(kind) |
|||
when :User, :Group: @systemDn |
|||
when :Site, :MailAliasRole, :MailAliasPerson, :MailAccount: @hostingDn |
|||
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)}" |
|||
when :MailAliasRole |
|||
"cn=#{data[:user]},o=#{data[:mail].sub(/.*@/, '')},#{ldapBase(kind)}" |
|||
when :MailAliasPerson |
|||
"mail=#{data[:mail]},o=#{data[:mail].sub(/.*@/, '')},#{ldapBase(kind)}" |
|||
when :MailAccount |
|||
"mail=#{data[:mail]},o=#{data[:mail].sub(/.*@/, '')},#{ldapBase(kind)}" |
|||
end |
|||
end |
|||
|
|||
end |
|||
@ -1,16 +1,64 @@ |
|||
module SdAdmin::Model |
|||
module Interface |
|||
end |
|||
module DsAdmin::Model |
|||
include Enumerable |
|||
|
|||
class Base |
|||
require 'model/interface' |
|||
require 'database' |
|||
include SdAdmin::Model::Interface |
|||
end |
|||
DsAdmin::Model.autoload(:User, 'model/user') |
|||
DsAdmin::Model.autoload(:Group, 'model/group') |
|||
DsAdmin::Model.autoload(:Site, 'model/site') |
|||
DsAdmin::Model.autoload(:MailAliasRole, 'model/mail_alias_role') |
|||
DsAdmin::Model.autoload(:MailAliasPerson, 'model/mail_alias_person') |
|||
DsAdmin::Model.autoload(:MailAccount, 'model/mail_account') |
|||
|
|||
class User < Base |
|||
end |
|||
def (DsAdmin::Model).storage=(storage) |
|||
@@storage = storage |
|||
end |
|||
|
|||
require 'model/base' |
|||
require 'model/user' |
|||
def (DsAdmin::Model).storage |
|||
@@storage |
|||
end |
|||
|
|||
attr_accessor :id |
|||
|
|||
def initialize(args = {}) |
|||
@id = args[:id] if args[:id] |
|||
end |
|||
|
|||
def all |
|||
@@storage.config.model = self |
|||
|
|||
@@storage.map do |data| |
|||
self.class.new(data) |
|||
end |
|||
end |
|||
|
|||
def each(&block) |
|||
all.each(&block) |
|||
end |
|||
|
|||
def load(id) |
|||
self.class.new(_load(id)) |
|||
end |
|||
|
|||
def load!(id) |
|||
initialize(_load(id)) |
|||
end |
|||
|
|||
def save |
|||
@id = @storage.create_id(self) unless @id |
|||
@storage.write(self) |
|||
end |
|||
|
|||
def update |
|||
@storage.write(self) |
|||
end |
|||
|
|||
def to_sym |
|||
self.class.to_s.to_sym |
|||
end |
|||
|
|||
protected |
|||
def _load(id) |
|||
data = @@storage.find {|data| data[:id] == id} |
|||
throw "unknown id (#{id})" unless data |
|||
data |
|||
end |
|||
end |
|||
@ -1,9 +0,0 @@ |
|||
class SdAdmin::Model::Base |
|||
attr_reader :backend |
|||
|
|||
def initialize(backend) |
|||
@backend = SdAdmin::Database::Ldap.new |
|||
@backend = backend if backend |
|||
end |
|||
|
|||
end |
|||
@ -1,14 +1,14 @@ |
|||
require 'SystemData' |
|||
class DsAdmin::Model::Group |
|||
include DsAdmin::Model |
|||
|
|||
class Group < SystemData |
|||
attr_accessor :name, :gid, :members |
|||
|
|||
|
|||
def initialize(args = {}) |
|||
super(args) |
|||
return if args.empty? |
|||
super(args) |
|||
|
|||
@name = args[:name] |
|||
@gid = args[:gid] |
|||
@members = args[:members] |
|||
@members = Array.new if @members.nil? |
|||
@members = args[:members] ? args[:members] : Array.new |
|||
end |
|||
end |
|||
@ -1,7 +0,0 @@ |
|||
module SdAdmin::Model::Interface |
|||
|
|||
def all |
|||
Hash[self.backend.map{|key,entry| [key, entry]}] |
|||
end |
|||
|
|||
end |
|||
@ -1,24 +0,0 @@ |
|||
class SystemData |
|||
attr_reader :id |
|||
|
|||
def initialize(args = {}) |
|||
@backend = args[:backend] |
|||
@id = args[:id] |
|||
end |
|||
|
|||
def save |
|||
kind = self.class.to_s.to_sym |
|||
|
|||
if @id |
|||
@backend.update(kind, to_h) |
|||
else |
|||
@backend.insert(kind, to_h) |
|||
end |
|||
end |
|||
|
|||
def to_h |
|||
Hash[instance_variables.map do |var| |
|||
[var[1...var.size].to_sym, eval(var)] if var != '@backend' |
|||
end] |
|||
end |
|||
end |
|||
@ -1,19 +1,19 @@ |
|||
class SdAdmin::Model::User |
|||
attr_accessor :name, :pass, :uid, :gid, :shell, :home |
|||
class DsAdmin::Model::User |
|||
include DsAdmin::Model |
|||
|
|||
def initialize(args={}, backend=nil) |
|||
super(backend) |
|||
attr_accessor :name, :pass, :uid, :gid, :shell, :home |
|||
|
|||
@backend.base_dn = 'ou=user,o=system,dc=weird-web-workers,dc=org' |
|||
@backend.filter = '(objectClass=posixAccount)' |
|||
def initialize(args = {}) |
|||
return if args.empty? |
|||
super(args) |
|||
|
|||
@name = args[:name] |
|||
@pass = args[:pass] |
|||
@uid = args[:uid] |
|||
@gid = args[:gid] |
|||
@shell = args[:shell] |
|||
@home = args[:home] |
|||
@shadowmax = args[:shadowmax] |
|||
@shadowwarning = args[:shadowwarning] |
|||
end |
|||
@name = args[:name] |
|||
@pass = args[:pass] |
|||
@uid = args[:uid] |
|||
@gid = args[:gid] |
|||
@shell = args[:shell] |
|||
@home = args[:home] |
|||
@shadowmax = args[:shadowmax] |
|||
@shadowwarning = args[:shadowwarning] |
|||
end |
|||
end |
|||
@ -1,10 +0,0 @@ |
|||
module SdAdmin |
|||
module Model |
|||
end |
|||
|
|||
module Database |
|||
end |
|||
|
|||
require 'model' |
|||
require 'database' |
|||
end |
|||
@ -0,0 +1,37 @@ |
|||
module DsAdmin::Storage |
|||
include Enumerable |
|||
|
|||
DsAdmin::Storage.autoload(:Ldap, 'storage/ldap') |
|||
DsAdmin::Storage.autoload(:Mysql, 'storage/mysql') |
|||
DsAdmin::Storage.autoload(:Config, 'storage/config') |
|||
|
|||
attr_accessor :config |
|||
|
|||
def initialize(config) |
|||
@config = config |
|||
end |
|||
|
|||
def each(&block) |
|||
read.each(&block) |
|||
end |
|||
|
|||
## |
|||
# We don't need this....the 'id' is a storage id and as |
|||
# thus returned after successfully writing a new entry. |
|||
# |
|||
def create_id(model) |
|||
return "dummy id for #{model.inspect}" |
|||
end |
|||
|
|||
def read |
|||
throw "#{self.class}: read not implemented" |
|||
end |
|||
|
|||
def write(model) |
|||
throw "#{self.class}: write not implemented" |
|||
end |
|||
|
|||
def to_sym |
|||
self.class.to_s.to_sym |
|||
end |
|||
end |
|||
@ -0,0 +1,21 @@ |
|||
require 'yaml' |
|||
|
|||
class Test::Storage::Config |
|||
attr_accessor :model |
|||
|
|||
def initialize(yml_file) |
|||
@config = YAML.load_file(yml_file) |
|||
end |
|||
|
|||
def con(storage) |
|||
@config[storage.to_sym][:con] |
|||
end |
|||
|
|||
def query(storage) |
|||
@config[storage.to_sym][@model.to_sym][:query] |
|||
end |
|||
|
|||
def map(storage) |
|||
@config[storage.to_sym][@model.to_sym][:map] |
|||
end |
|||
end |
|||
@ -0,0 +1,34 @@ |
|||
require 'net/ldap' |
|||
|
|||
class DsAdmin::Storage::Ldap |
|||
include DsAdmin::Storage |
|||
|
|||
def initialize(config) |
|||
super(config) |
|||
@ldap = Net::LDAP.new(@config.con(self)) |
|||
end |
|||
|
|||
def read |
|||
query = @config.query(self) |
|||
|
|||
## |
|||
# two things. |
|||
# - create a hash from the ldap search result |
|||
# - map the id's from the ldap search resulte into id's used in |
|||
# the models. The mapping is read from the config. |
|||
# |
|||
foo = @ldap.search(query).map do |data| |
|||
map = { :dn => :id } |
|||
map.merge!(@config.map(self)) |
|||
|
|||
remapped = Hash.new |
|||
data.each do |key,value| |
|||
key = map[key] || key |
|||
value = value.size==1 ? value[0] : value.to_a |
|||
|
|||
remapped.merge!({ key => value }) |
|||
end |
|||
remapped |
|||
end |
|||
end |
|||
end |
|||
@ -0,0 +1,3 @@ |
|||
class DsAdmin::Storage::Mysql |
|||
include DsAdmin::Storage |
|||
end |
|||
@ -1,123 +0,0 @@ |
|||
require 'SystemDataBackend' |
|||
require 'SystemDataBackendLdap' |
|||
|
|||
ldap = SystemDataBackendLdap.new( |
|||
'host.one.virtual', |
|||
389, |
|||
'dc=weird-web-workers,dc=org' |
|||
) |
|||
backend = SystemDataBackend.new(ldap) |
|||
|
|||
backend.users.each do |user| |
|||
puts 'user: '+user.name+','+user.uid+','+user.gid+','+user.home |
|||
end |
|||
|
|||
puts |
|||
|
|||
backend.groups.each do |group| |
|||
members = backend.usersInGroup(group) |
|||
|
|||
puts 'group: '+group.name+','+group.gid |
|||
puts ' members:' |
|||
group.members.each do |name| |
|||
print ' ' + name + ': ' |
|||
print members[name].uid + ', ' + members[name].home if members[name] |
|||
puts |
|||
end |
|||
puts |
|||
end |
|||
|
|||
backend.sites.each do |site| |
|||
puts 'site: ' + site.name |
|||
puts ' MailAliasRoles:' |
|||
backend.mailAliasRolesBySite(site).each{|account| puts ' ' + account.mail} |
|||
puts |
|||
puts ' MailAliasPeople:' |
|||
backend.mailAliasPeopleBySite(site).each{|account| puts ' ' + account.mail} |
|||
puts |
|||
puts ' MailAccounts:' |
|||
backend.mailAccountsBySite(site).each{|account| puts ' ' + account.mail} |
|||
puts |
|||
end |
|||
|
|||
backend.mailAliasRoles.each do |mailAlias| |
|||
puts 'mailAliasRole: '+mailAlias.mail.inspect+','+mailAlias.maildrop.inspect |
|||
end |
|||
|
|||
puts |
|||
|
|||
backend.mailAliasPeople.each do |mailAlias| |
|||
puts 'mailAliasPerson: '+mailAlias.mail.inspect+','+mailAlias.maildrop.inspect |
|||
end |
|||
|
|||
puts |
|||
|
|||
backend.mailAccounts.each do |mailAccount| |
|||
puts 'mailAccount: '+mailAccount.mail.inspect+','+mailAccount.mailbox.inspect |
|||
end |
|||
|
|||
puts |
|||
|
|||
georg = backend.userByName('georg') |
|||
georg.save |
|||
|
|||
puts |
|||
|
|||
georg.uid = 1001 |
|||
georg.save |
|||
|
|||
puts |
|||
|
|||
wheel = backend.groupByName('wheel') |
|||
wheel.save |
|||
|
|||
puts |
|||
|
|||
wheel.gid = 100 |
|||
wheel.save |
|||
|
|||
puts |
|||
|
|||
site = backend.siteByName('kommandozeilenchef.de') |
|||
site.save |
|||
|
|||
puts |
|||
|
|||
site.name = 'wumbaba.de' |
|||
site.save |
|||
|
|||
puts |
|||
|
|||
mail = MailAliasRole.new({ |
|||
:backend => ldap, |
|||
:mail => 'newrole@kommandozeilenchef.de', |
|||
:maildrop => 'newrole', |
|||
:user => 'newrole' |
|||
}) |
|||
mail.save |
|||
|
|||
puts |
|||
|
|||
mail = MailAliasPerson.new({ |
|||
:backend => ldap, |
|||
:mail => 'ohotte@kommandozeilenchef.de', |
|||
:maildrop => 'ohotte', |
|||
:name => 'Onkel Hotte', |
|||
:surname => 'Hotte' |
|||
}) |
|||
mail.save |
|||
|
|||
puts |
|||
|
|||
mail = MailAccount.new({ |
|||
:backend => ldap, |
|||
:mail => 'foobar@kommandozeilenchef.de', |
|||
:mailbox => 'kommandozeilenchef.de/foobar', |
|||
:home => '/var/spool/vmail/domains' |
|||
}) |
|||
mail.save |
|||
|
|||
puts |
|||
puts '=====================================' |
|||
# -o vsz/vsize |
|||
puts 'Memory useage: ' + `ps -o rss= -p #{Process.pid}` |
|||
@ -1,5 +0,0 @@ |
|||
require 'sd_admin' |
|||
|
|||
user = SdAdmin::Model::User.new |
|||
|
|||
puts user.all.inspect |
|||
@ -0,0 +1,38 @@ |
|||
require 'ds_admin' |
|||
|
|||
config = DsAdmin::Storage::Config.new(File.dirname(__FILE__) + '/config/storage.yml') |
|||
DsAdmin::Model.storage = DsAdmin::Storage::Ldap.new(config) |
|||
|
|||
user = DsAdmin::Model::User.new |
|||
group = DsAdmin::Model::Group.new |
|||
site = DsAdmin::Model::Site.new |
|||
alias_role = DsAdmin::Model::MailAliasRole.new |
|||
alias_person = DsAdmin::Model::MailAliasPerson.new |
|||
account = DsAdmin::Model::MailAccount.new |
|||
|
|||
puts '=== DsAdmin each ===' |
|||
user.each {|user| puts user.inspect} |
|||
puts '---' |
|||
group.each {|group| puts group.inspect} |
|||
puts '---' |
|||
site.each {|site| puts site.inspect} |
|||
puts '---' |
|||
alias_role.each {|ma_role| puts ma_role.inspect} |
|||
puts '---' |
|||
alias_person.each {|ma_person| puts ma_person.inspect} |
|||
puts '---' |
|||
account.each {|macc| puts macc.inspect} |
|||
|
|||
puts |
|||
puts '=== DsAdmin Enumerable ===' |
|||
puts user.find {|user| user.uid == '1000'}.inspect |
|||
puts '---' |
|||
puts group.find {|group| group.gid == '10'}.inspect |
|||
puts '---' |
|||
puts site.find {|site| site.name == 'steffers.org'}.inspect |
|||
puts '---' |
|||
puts alias_role.find_all {|mar| mar.maildrop == 'abuse'}.inspect |
|||
puts '---' |
|||
puts alias_person.find {|map| map.mail == 'georg@steffers.org'}.inspect |
|||
puts '---' |
|||
puts account.find {|acc| acc.mail == 'drachenfrau@steffers.org'}.inspect |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue