Project

General

Profile

« Previous | Next » 

Revision 89d8bebc

Added by Marc Dequènes almost 15 years ago

  • ID 89d8bebc58e8c69d8fb03685e4875eba3bc9d86e

[evol] files/code reorganization, and added a proper installer

View differences:

.gitignore
\#*#
# generated by installer
.config
lib/ldapshadows/config.rb
lib/ldap_shadows/config.rb
data/locale
#
conf
conf/ldap_shadows/private.conf
var
#
config/private.conf
INSTALL
# for a real install in /usr/local
ruby setup.rb config
ruby setup.rb setup
ruby setup.rb install
ruby setup.rb clean
# for packagers
ruby setup.rb config --installdirs=std
ruby setup.rb setup
ruby setup.rb install --prefix=debian/cyborghood
ruby setup.rb clean
# for in-place tests
ruby setup.rb config --bindir=bin --rbdir=lib --datadir=data --sysconfdir=conf --localstatedir=var --shebang=never
ruby setup.rb setup
# and when finished...
ruby setup.rb clean
bin/shadowwalker
#!/usr/bin/ruby -Ku
#--
# LdapShadows, a Medium-level LDAP Access Library and Tool.
# Copyright (c) 2009 Marc Dequènes (Duck) <Duck@DuckCorp.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#++
# to allow in-place run for test
$: << File.join(File.dirname(__FILE__), "..", "lib")
require 'ldap_shadows'
require 'yaml'
require 'cmdparse2'
config_str_prv = IO.read(File.join(LdapShadows::Config::CFG_DIR, "private.conf"))
config_str = IO.read(File.join(LdapShadows::Config::CFG_DIR, "test.conf"))
config = YAML.load(config_str_prv).merge(YAML.load(config_str)).recursive_symbolize_keys!
ActiveLdap::Base.setup_connection(config[:ldap])
cmdparser = CmdParse::CommandParser.new(true)
cmdparser.program_name = ""
cmdparser.program_version = [0, 0, 1]
cmdparser.options = CmdParse::OptionParserWrapper.new do |opt|
opt.separator "Global options:"
opt.on("--debug", "Output debug info without being formated") {|t| $debug_opt = true }
opt.on("--expert", "Output extra info for expert users") {|t| $expert_opt = true }
opt.on("--handles", "Output with handles (objects/field/... keys used for manipulations)") {|t| $handles_opt = true }
end
cmdparser.add_command(CmdParse::HelpCommand.new)
cmdparser.add_command(CmdParse::VersionCommand.new)
I18n.load_path += Dir[File.join(LdapShadows::Config::DATA_DIR, "*.yml")]
I18n.default_locale = :en
ldapctl = LdapShadows::Controller.new
config[:aspects].each_pair do |aspect_name, aspect_data|
ldapctl.set_aspect(aspect_name, aspect_data)
end
config[:objects].each_pair do |obj_name, obj_data|
ldapctl.load_object(obj_name, obj_data)
end
ldapctl.load_relations
cmd = CmdParse::Command.new('list', false)
cmd.short_desc = "list objects"
cmd.set_execution_block do |args|
if args.size != 1
STDERR.puts "syntax error: no object name given"
exit 1
end
obj_hdl = args[0]
obj_klass = ldapctl.find_klass(obj_hdl)
if obj_klass.nil?
STDERR.puts "No such object '#{obj_hdl}'."
exit 2
end
obj_human_name = I18n.t(obj_hdl, :scope => 'objects', :default => "Object '#{obj_hdl}'")
puts "=== List of #{obj_human_name.pluralize} ==="
obj_klass.find(:all).each do |obj|
str = obj.human_name
str += " [#{obj.name}]" if $handles_opt
str += ": #{obj.description}" unless obj.description.empty?
puts str
end
end
cmdparser.add_command(cmd)
def translate_data_key(name)
if name.index(":")
type, key = name.split(":")
case type
when 'rel'
I18n.t(key, :scope => 'relations', :default => name)
else
raise "Cannot translate unknown data key type"
end
else
att = ActiveLdap::Base.schema.attribute(name)
I18n.t(att.human_attribute_name, :scope => 'attribute_types', :default => att.human_attribute_description)
end
end
def display_data(attr_data)
attr_data.each_pair do |key, val|
field_name = translate_data_key(key)
field_name += " [#{key}]" if $handles_opt
puts field_name + ": " + (val.is_a?(Array) ? val.sort.collect{|v| v.to_s }.join(", ") : val.to_s)
end
end
cmd = CmdParse::Command.new('show', false)
cmd.short_desc = "show object information"
cmd.set_execution_block do |args|
if args.size < 1
STDERR.puts "syntax error: no object name given"
exit 1
end
if args.size < 2
STDERR.puts "syntax error: no item name given"
exit 1
end
obj_hdl = args[0]
obj_klass = ldapctl.find_klass(obj_hdl)
if obj_klass.nil?
STDERR.puts "No such object '#{obj_hdl}'."
exit 2
end
item_hdl = args[1]
begin
item = obj_klass.find(item_hdl)
rescue ActiveLdap::EntryNotFound
STDERR.puts "No such item '#{obj_hdl}/#{item_hdl}'"
exit 2
end
obj_human_name = I18n.t(obj_hdl, :scope => 'objects', :default => "Object '#{obj_hdl}'")
name = item.human_name
name += " [#{item.name}]" if $handles_opt
puts "=== #{obj_human_name}: #{name} ==="
if $debug_opt
puts item.to_s
puts "--- Detected Info ---"
puts "aspects: " + item.aspects.sort.join(", ")
puts "--- Family ---"
puts "parent: " + item.family_parent_dn.to_s
puts "siblings: " + item.family_siblings_dn.join(", ")
puts "children: " + item.family_children_dn.join(", ")
puts "--- Relations ---"
item.relations.each do |rel|
puts "#{rel}: " + item.send(rel).collect{|g| g.name }.join(", ")
end
else
obj_info, obj_aspects = item.organized_data(:expert => $expert_opt, :skip_binary => true)
display_data(obj_info)
obj_aspects.each_pair do |aspect_name, aspect_data|
aspect_display_name = I18n.t(aspect_name, :scope => 'aspects', :default => "Aspect '#{aspect_name}'")
puts "--- #{aspect_display_name} ---"
display_data(aspect_data)
end
end
end
cmdparser.add_command(cmd)
cmdparser.parse
conf/ldap_shadows/test.conf
---
objects:
bot:
mapping:
dn_attribute: uid
prefix: ''
classes: ['bot']
sort_by: uid
presentation:
optional_classes: []
allowed_aspects: ['primary', 'mail', 'fs', 'shell', 'ftp', 'web', 'jabber']
hidden_attributes: ['objectClass', 'uid']
expert_attributes: ['uidNumber', 'gidNumber', 'gecos']
individual:
mapping:
dn_attribute: uid
prefix: ''
classes: ['individual']
sort_by: uid
presentation:
optional_classes: []
allowed_aspects: ['primary', 'mail', 'fs', 'shell', 'ftp', 'web', 'jabber']
hidden_attributes: ['objectClass', 'uid']
expert_attributes: ['uidNumber', 'gidNumber', 'gecos']
group:
mapping:
dn_attribute: cn
prefix: ''
classes: ['posixGroup', 'groupOfMembers']
sort_by: cn
presentation:
optional_classes: []
allowed_aspects: []
hidden_attributes: ['objectClass', 'uniqueMember']
expert_attributes: ['gidNumber']
associated_relations: ['individualsPrimaryMembers', 'botsPrimaryMembers', 'individualsSecondaryMembers', 'botsSecondaryMembers']
relations:
individualsPrimaryMembers:
type: :belongs_to
object: individual
many: gidNumber
foreign_key: gidNumber
botsPrimaryMembers:
type: :belongs_to
object: bot
many: gidNumber
foreign_key: gidNumber
individualsSecondaryMembers:
type: :has_many
object: individual
foreign_key: uniqueMember
primary_key: dn
botsSecondaryMembers:
type: :has_many
object: bot
foreign_key: uniqueMember
primary_key: dn
entity:
mapping:
dn_attribute: o
prefix: ''
classes: ['entity']
excluded_classes: ['dcObject']
sort_by: o
presentation:
name_attribute: o
hidden_attributes: ['objectClass', 'founder']
associated_relations: ['foundersIndividuals', 'foundersEntities']
relations:
foundersIndividuals:
type: :has_many
object: individual
foreign_key: founder
primary_key: dn
foundersEntities:
type: :has_many
object: entity
foreign_key: founder
primary_key: dn
aspects:
mail:
mapping:
classes: ['emailUser']
presentation:
relations:
fs:
mapping:
classes: ['fsUser']
presentation:
associated_relations: ['primaryGroup', 'secondaryGroups']
relations:
primaryGroup:
type: :has_many
object: group
foreign_key: gidNumber
primary_key: gidNumber
secondaryGroups:
type: :belongs_to
object: group
many: uniqueMember
foreign_key: dn
shell:
mapping:
classes: ['shellUser']
depend_aspects: ['primary', 'fs']
presentation:
associated_attributes: ['loginShell']
relations:
ftp:
mapping:
classes: ['ftpUser']
depend_aspects: ['primary', 'fs']
presentation:
relations:
web:
mapping:
classes: ['webUser']
depend_aspects: ['primary']
presentation:
relations:
jabber:
mapping:
classes: ['jabberUser']
presentation:
relations:
primary:
mapping:
classes: ['primaryAccount']
presentation:
associated_attributes: ['uid']
relations:
config/test.conf
---
objects:
bot:
mapping:
dn_attribute: uid
prefix: ''
classes: ['bot']
sort_by: uid
presentation:
optional_classes: []
allowed_aspects: ['primary', 'mail', 'fs', 'shell', 'ftp', 'web', 'jabber']
hidden_attributes: ['objectClass', 'uid']
expert_attributes: ['uidNumber', 'gidNumber', 'gecos']
individual:
mapping:
dn_attribute: uid
prefix: ''
classes: ['individual']
sort_by: uid
presentation:
optional_classes: []
allowed_aspects: ['primary', 'mail', 'fs', 'shell', 'ftp', 'web', 'jabber']
hidden_attributes: ['objectClass', 'uid']
expert_attributes: ['uidNumber', 'gidNumber', 'gecos']
group:
mapping:
dn_attribute: cn
prefix: ''
classes: ['posixGroup', 'groupOfMembers']
sort_by: cn
presentation:
optional_classes: []
allowed_aspects: []
hidden_attributes: ['objectClass', 'uniqueMember']
expert_attributes: ['gidNumber']
associated_relations: ['individualsPrimaryMembers', 'botsPrimaryMembers', 'individualsSecondaryMembers', 'botsSecondaryMembers']
relations:
individualsPrimaryMembers:
type: :belongs_to
object: individual
many: gidNumber
foreign_key: gidNumber
botsPrimaryMembers:
type: :belongs_to
object: bot
many: gidNumber
foreign_key: gidNumber
individualsSecondaryMembers:
type: :has_many
object: individual
foreign_key: uniqueMember
primary_key: dn
botsSecondaryMembers:
type: :has_many
object: bot
foreign_key: uniqueMember
primary_key: dn
entity:
mapping:
dn_attribute: o
prefix: ''
classes: ['entity']
excluded_classes: ['dcObject']
sort_by: o
presentation:
name_attribute: o
hidden_attributes: ['objectClass', 'founder']
associated_relations: ['foundersIndividuals', 'foundersEntities']
relations:
foundersIndividuals:
type: :has_many
object: individual
foreign_key: founder
primary_key: dn
foundersEntities:
type: :has_many
object: entity
foreign_key: founder
primary_key: dn
aspects:
mail:
mapping:
classes: ['emailUser']
presentation:
relations:
fs:
mapping:
classes: ['fsUser']
presentation:
associated_relations: ['primaryGroup', 'secondaryGroups']
relations:
primaryGroup:
type: :has_many
object: group
foreign_key: gidNumber
primary_key: gidNumber
secondaryGroups:
type: :belongs_to
object: group
many: uniqueMember
foreign_key: dn
shell:
mapping:
classes: ['shellUser']
depend_aspects: ['primary', 'fs']
presentation:
associated_attributes: ['loginShell']
relations:
ftp:
mapping:
classes: ['ftpUser']
depend_aspects: ['primary', 'fs']
presentation:
relations:
web:
mapping:
classes: ['webUser']
depend_aspects: ['primary']
presentation:
relations:
jabber:
mapping:
classes: ['jabberUser']
presentation:
relations:
primary:
mapping:
classes: ['primaryAccount']
presentation:
associated_attributes: ['uid']
relations:
data/ldap_shadows/en.yml
---
en:
objects:
individual: "Individual"
bot: "Bot"
group: "Group"
entity: "Entity"
attribute_types:
allowGlobalDirectory: "Disclose Own Contact Information in GLobal Directory"
cn: "Full Name"
birthday: "Birthday"
birthlocation: "Birth Location"
description: "Description"
foundingDate: "Founding Date"
gecos: "GECOS"
gidNumber: "Primary Group (numeric)"
givenName: "FirstName"
homeDirectory: "Home Directory"
homePostalAddress: "Home Postal Address"
host: "Shell Allowed Hosts"
jid: "Jabber ID"
jpegPhoto: "Photo"
keyFingerPrint: "GPG/PGP Key Fingerprint"
labeledURI: "Web Site"
loginShell: "Shell Interpreter"
mail: "eMail address(es)"
mailForward: "eMail Forward Adress(es)"
mailQuota: "Maximum Mailbox Size"
manager: "Manager(s)"
mobile: "Mobile Phone"
occupation: "Job / Studies"
o: "Organization(s)"
owner: "Owner(s)"
preferredLanguage: "Language Preference"
sn: "Surname"
sshAuthKey: "SSH Public Key(s)"
uid: "Identifier (Login)"
uidNumber: "Identifier (numeric)"
uniqueAbbreviation: "Unique Abbreviation"
uniqueMember: "Group member"
webVirtualHost: "Hosted Web Sites"
relations:
primaryGroup: "Primary Group"
secondaryGroups: "Secondary Groups"
individualsPrimaryMembers: "Primary Member(s) Individual(s)"
botsPrimaryMembers: "Primary Member(s) Bot(s)"
individualsSecondaryMembers: "Secondary Member(s) Individual(s)"
botsSecondaryMembers: "Secondary Member(s) Bot(s)"
foundersIndividuals: "Founder(s) Individual(s)"
foundersEntities: "Founder(s) Entity(ies)"
aspects:
primary: "Primary Account"
ftp: "FTP Account"
web: "Web Account"
shell: "Shell Account"
fs: "FileSystem Account"
mail: "eMail Account"
jabber: "Jabber Account"
lib/ldap_shadows.rb
#--
# LdapShadows, a Medium-level LDAP Access Library and Tool.
# Copyright (c) 2009 Marc Dequènes (Duck) <Duck@DuckCorp.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#++
require 'ldap_shadows/info'
require 'ldap_shadows/config'
require 'ldap_shadows/lang_additions'
require 'ldap_shadows/controller'
lib/ldap_shadows/controller.rb
#--
# LdapShadows, a Medium-level LDAP Access Library and Tool.
# Copyright (c) 2009 Marc Dequènes (Duck) <Duck@DuckCorp.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#++
$KCODE = 'UTF8'
require 'jcode'
require 'active_ldap'
require 'ldap_shadows/object'
module LdapShadows
class Controller
def initialize(mod_container = LdapShadows::Objects)
@mod_container = mod_container
@object_definitions = {}
@aspects = {}
end
def set_aspect(aspect_name, aspect_def)
@aspects[aspect_name] = aspect_def
end
def get_aspect(aspect_name)
@aspects[aspect_name.to_sym]
end
def self.object_name_to_klass_name(obj_name)
"LdapObject" + obj_name.to_s.capitalize
end
def load_object(obj_name, obj_def)
obj_mapping = obj_def[:mapping]
klass_name = self.class.object_name_to_klass_name(obj_name)
# create class
@mod_container.module_eval(<<-EOS)
class #{klass_name} < LdapShadows::LdapObject; end
EOS
# configure class
klass = find_klass(obj_name)
klass.presentation = obj_def[:presentation]
klass.mapper = self
klass.ldap_mapping obj_mapping.reject {|key, val| not ActiveLdap::Base::VALID_LDAP_MAPPING_OPTIONS.include?(key) }
# store definition for later relations processing
@object_definitions[obj_name] = obj_def
end
def find_klass(obj_name)
klass_name = self.class.object_name_to_klass_name(obj_name)
return nil unless @mod_container.const_defined?(klass_name)
@mod_container.const_get(klass_name)
end
# run it _once_ when all objects are loaded
def load_relations
@object_definitions.each_pair do |obj_name, obj_def|
obj_rel = {}
obj_rel.merge!(obj_def[:relations]) if obj_def.include?(:relations)
if obj_def[:presentation].has_key?(:allowed_aspects)
obj_def[:presentation][:allowed_aspects].each do |rel|
rel_data = get_aspect(rel)
obj_rel.merge!(rel_data[:relations]) if rel_data.has_key?(:relations) and rel_data[:relations]
end
end
next if obj_rel.empty?
klass = find_klass(obj_name)
obj_rel.each_pair do |field_name, rel|
foreign_klass = find_klass(rel[:object])
rel[:class_name] = foreign_klass.to_s
case rel[:type]
when :belongs_to
klass.belongs_to field_name, rel.reject {|key, val| not ActiveLdap::Associations::ClassMethods::VALID_BELONGS_TO_OPTIONS.include?(key) }
when :has_many
klass.has_many field_name, rel.reject {|key, val| not ActiveLdap::Associations::ClassMethods::VALID_HAS_MANY_OPTIONS.include?(key) }
else
raise "bug in '#{obj_name}' object relations (wrong type)"
end
end
end
end
end
# default location for mapped objects
module Objects
end
end
lib/ldap_shadows/info.rb
module LdapShadows
PRODUCT = "LDAP Shadows"
VERSION = "0.1.0~dev"
end
lib/ldap_shadows/lang_additions.rb
#--
# LdapShadows, a Medium-level LDAP Access Library and Tool.
# Copyright (c) 2009 Marc Dequènes (Duck) <Duck@DuckCorp.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#++
# for Rails
class Hash
def recursive_symbolize_keys!
symbolize_keys!
values.select { |v| v.is_a?(Hash) }.each { |h| h.recursive_symbolize_keys! }
self
end
end
# for ActiveLDAP
module ActiveLdap
class DistinguishedName
def shift
@rdns.shift
end
end
end
lib/ldap_shadows/object.rb
#--
# LdapShadows, a Medium-level LDAP Access Library and Tool.
# Copyright (c) 2009 Marc Dequènes (Duck) <Duck@DuckCorp.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#++
module LdapShadows
class LdapObject < ActiveLdap::Base
class_inheritable_accessor :presentation, :mapper
ldap_mapping :prefix => '', :classes => ['top'], :scope => :sub
# temporary method until active_ldap is fixed: return a DN object (see #23932)
def dn_obj
ActiveLdap::DistinguishedName.parse(self.dn)
end
def name
name = self[dn_attribute].is_a?(Array) ? self[dn_attribute][0] : self[dn_attribute]
name.strip
end
def human_name
[self.class.presentation[:name_attribute], 'displayName', 'cn'].each do |attr|
if self.has_attribute?(attr) and self.attribute_present?(attr)
name = self[attr].is_a?(Array) ? self[attr][0] : self[attr]
return name.strip
end
end
return ""
end
def description
[self.class.presentation[:desc_attribute], 'description'].each do |attr|
if self.has_attribute?(attr) and self.attribute_present?(attr)
return self[attr].is_a?(Array) ? self[attr][0] : self[attr]
end
end
return ""
end
def possible_relations
self.associations.collect {|assoc| assoc.to_s } - ['children']
end
def relations
rel_list = []
rel_list += self.class.presentation[:associated_relations] if self.class.presentation[:associated_relations]
aspects.each do |aspect|
aspect_data = self.class.mapper.get_aspect(aspect)
if defined?(aspect_data[:presentation][:associated_relations]) and aspect_data[:presentation][:associated_relations]
rel_list += aspect_data[:presentation][:associated_relations]
end
end
rel_list & possible_relations
end
def aspects
present_aspects = []
(self.class.presentation[:allowed_aspects] || []).each do |aspect|
aspect_data = self.class.mapper.get_aspect(aspect)
aspect_mapping = aspect_data[:mapping]
present_aspects << aspect if self.classes & aspect_mapping[:classes] == aspect_mapping[:classes]
end
present_aspects
end
def objectclasses_attr_list(objectclass_list)
objectclass_list = [objectclass_list] unless objectclass_list.is_a? Array
list = []
objectclass_list.each do |objectclass|
objectclass_obj = ActiveLdap::Base.schema.object_class(objectclass)
attr_list = objectclass_obj.must + objectclass_obj.may
list += attr_list.collect{|attr| attr.human_attribute_name }
end
list
end
def organized_data(options = {})
options.symbolize_keys!
options[:expert] ||= false;
options[:skip_binary] ||= false;
ignored_attrs = self.class.presentation[:hidden_attributes] || []
ignored_attrs += (self.class.presentation[:expert_attributes] || []) unless options[:expert]
attr_list = self.attributes.keys - ignored_attrs
aspects = self.aspects
rel_list = self.possible_relations
# first pass to take aspects forced relations into account
obj_aspects = {}
aspects.each do |aspect|
aspect_data = self.class.mapper.get_aspect(aspect)
if defined?(aspect_data[:presentation][:associated_attributes]) and aspect_data[:presentation][:associated_attributes]
taken_attr_list = aspect_data[:presentation][:associated_attributes] & (attr_list + ignored_attrs)
unless taken_attr_list.empty?
obj_aspects[aspect] ||= {}
obj_aspects[aspect].merge!(fetch_attributes_data(taken_attr_list, options))
attr_list -= taken_attr_list
end
end
if defined?(aspect_data[:presentation][:associated_relations]) and aspect_data[:presentation][:associated_relations]
taken_rel_list = aspect_data[:presentation][:associated_relations] & rel_list
unless taken_rel_list.empty?
obj_aspects[aspect] ||= {}
obj_aspects[aspect].merge!(fetch_relations_data(taken_rel_list, options))
rel_list -= taken_rel_list
end
end
end
# manage general attributes
obj_info = {}
if self.class.presentation[:associate_unclaimed_attributes]
taken_attr_list = attr_list
else
taken_attr_list = []
if self.class.presentation.has_key?(:associated_attributes)
taken_attr_list += self.class.presentation[:associated_attributes]
end
taken_attr_list += objectclasses_attr_list(self.required_classes + (self.class.presentation[:optional_classes] || []))
end
taken_attr_list = taken_attr_list.uniq & attr_list
obj_info = fetch_attributes_data(taken_attr_list, options)
attr_list -= taken_attr_list
# manage general relations
if self.class.presentation[:associated_relations]
taken_rel_list = self.class.presentation[:associated_relations] & rel_list
unless taken_rel_list.empty?
obj_info.merge!(fetch_relations_data(taken_rel_list, options))
rel_list -= taken_rel_list
end
end
# second pass to dispath the remaining attributes
unless attr_list.empty?
aspects.each do |aspect|
aspect_data = self.class.mapper.get_aspect(aspect)
taken_attr_list = (objectclasses_attr_list(aspect_data[:mapping][:classes]) & attr_list)
obj_aspects[aspect] ||= {}
obj_aspects[aspect].merge!(fetch_attributes_data(taken_attr_list, options))
attr_list -= taken_attr_list
break if attr_list.empty?
end
end
[obj_info, obj_aspects]
end
def family_parent_dn
pdn = self.dn_obj.dup
pdn.shift
pdn
end
def family_children
LdapObject.find(:all, :base => self.dn, :scope => :one)
end
def family_children_dn
self.family_children.collect {|obj| obj.dn }
end
def family_siblings
# cannot substract, as the ruby object signature may be different
LdapObject.find(:all, :base => self.family_parent_dn.to_s, :scope => :one).select{|obj| obj.dn != self.dn }
end
def family_siblings_dn
self.family_siblings.collect {|obj| obj.dn }
end
protected
def fetch_attributes_data(attr_list, options = {})
attr_data = self.attributes.select {|key, val| attr_list.include?(key) and not (options[:skip_binary] and ActiveLdap::Base.schema.attribute(key).binary?) }
Hash[attr_data]
end
def fetch_relations_data(rel_list, options = {})
rel_data = rel_list.collect do |rel|
data = self.send(rel).collect{|g| g.name }
data.empty? ? nil : ["rel:" + rel, data]
end
Hash[rel_data.compact]
end
end
end
locale/en.yml
---
en:
objects:
individual: "Individual"
bot: "Bot"
group: "Group"
entity: "Entity"
attribute_types:
allowGlobalDirectory: "Disclose Own Contact Information in GLobal Directory"
cn: "Full Name"
birthday: "Birthday"
birthlocation: "Birth Location"
description: "Description"
foundingDate: "Founding Date"
gecos: "GECOS"
gidNumber: "Primary Group (numeric)"
givenName: "FirstName"
homeDirectory: "Home Directory"
homePostalAddress: "Home Postal Address"
host: "Shell Allowed Hosts"
jid: "Jabber ID"
jpegPhoto: "Photo"
keyFingerPrint: "GPG/PGP Key Fingerprint"
labeledURI: "Web Site"
loginShell: "Shell Interpreter"
mail: "eMail address(es)"
mailForward: "eMail Forward Adress(es)"
mailQuota: "Maximum Mailbox Size"
manager: "Manager(s)"
mobile: "Mobile Phone"
occupation: "Job / Studies"
o: "Organization(s)"
owner: "Owner(s)"
preferredLanguage: "Language Preference"
sn: "Surname"
sshAuthKey: "SSH Public Key(s)"
uid: "Identifier (Login)"
uidNumber: "Identifier (numeric)"
uniqueAbbreviation: "Unique Abbreviation"
uniqueMember: "Group member"
webVirtualHost: "Hosted Web Sites"
relations:
primaryGroup: "Primary Group"
secondaryGroups: "Secondary Groups"
individualsPrimaryMembers: "Primary Member(s) Individual(s)"
botsPrimaryMembers: "Primary Member(s) Bot(s)"
individualsSecondaryMembers: "Secondary Member(s) Individual(s)"
botsSecondaryMembers: "Secondary Member(s) Bot(s)"
foundersIndividuals: "Founder(s) Individual(s)"
foundersEntities: "Founder(s) Entity(ies)"
aspects:
primary: "Primary Account"
ftp: "FTP Account"
web: "Web Account"
shell: "Shell Account"
fs: "FileSystem Account"
mail: "eMail Account"
jabber: "Jabber Account"
post-clean.rb
# post-clean.rb - setup config generation cleanup
#--
# LdapShadows, a Medium-level LDAP Access Library and Tool.
# Copyright (c) 2009 Marc Dequènes (Duck) <Duck@DuckCorp.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#++
conffile = "lib/cyborghood/config.rb"
File.unlink(conffile) if FileTest.exists?(conffile)
post-config.rb
# post-config.rb - setup config generation
#--
# LdapShadows, a Medium-level LDAP Access Library and Tool.
# Copyright (c) 2009 Marc Dequènes (Duck) <Duck@DuckCorp.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#++
# General header.
header = <<HEADER
# config.rb - Coin-diff setup configuration
#--
# LdapShadows, a Medium-level LDAP Access Library and Tool.
# Copyright (c) 2009 Marc Dequènes (Duck) <Duck@DuckCorp.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#++
# This file is automatically generated by the installer.
# Do not edit by hand.
HEADER
# Generate config.rb containing general compile/setup time configuration
# information (in the CoinDiff::Config module).
File.open('lib/ldap_shadows/config.rb', 'w') do |file|
file.print header
file.print <<-CONFIG
module LdapShadows
class Config
BIN_DIR = '#{config('bindir')}'
CFG_DIR = '#{File.join(config('sysconfdir'), 'ldap_shadows')}'
DATA_DIR = '#{File.join(config('datadir'), 'ldap_shadows')}'
LIB_DIR = '#{config('rbdir')}'
LOG_DIR = '#{File.join(config('localstatedir'), 'log', 'ldap_shadows')}'
RUN_DIR = '#{File.join(config('localstatedir'), 'run', 'ldap_shadows')}'
VAR_DIR = '#{File.join(config('localstatedir'), 'lib', 'ldap_shadows')}'
L10N_DIR = '#{File.join(config('datadir'), 'locale')}'
end
end
CONFIG
end # File.open
setup.rb
#
# setup.rb
#
# Copyright (c) 2000-2005 Minero Aoki
#
# This program is free software.
# You can distribute/modify this program under the terms of
# the GNU LGPL, Lesser General Public License version 2.1.
#
unless Enumerable.method_defined?(:map) # Ruby 1.4.6
module Enumerable
alias map collect
end
end
unless File.respond_to?(:read) # Ruby 1.6
def File.read(fname)
open(fname) {|f|
return f.read
}
end
end
unless Errno.const_defined?(:ENOTEMPTY) # Windows?
module Errno
class ENOTEMPTY
# We do not raise this exception, implementation is not needed.
end
end
end
def File.binread(fname)
open(fname, 'rb') {|f|
return f.read
}
end
# for corrupted Windows' stat(2)
def File.dir?(path)
File.directory?((path[-1,1] == '/') ? path : path + '/')
end
class ConfigTable
include Enumerable
def initialize(rbconfig)
@rbconfig = rbconfig
@items = []
@table = {}
# options
@install_prefix = nil
@config_opt = nil
@verbose = true
@no_harm = false
end
attr_accessor :install_prefix
attr_accessor :config_opt
attr_writer :verbose
def verbose?
@verbose
end
attr_writer :no_harm
def no_harm?
@no_harm
end
def [](key)
lookup(key).resolve(self)
end
def []=(key, val)
lookup(key).set val
end
def names
@items.map {|i| i.name }
end
def each(&block)
@items.each(&block)
end
def key?(name)
@table.key?(name)
end
def lookup(name)
@table[name] or setup_rb_error "no such config item: #{name}"
end
def add(item)
@items.push item
@table[item.name] = item
end
def remove(name)
item = lookup(name)
@items.delete_if {|i| i.name == name }
@table.delete_if {|name, i| i.name == name }
item
end
def load_script(path, inst = nil)
if File.file?(path)
MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path
end
end
def savefile
'.config'
end
def load_savefile
begin
File.foreach(savefile()) do |line|
k, v = *line.split(/=/, 2)
self[k] = v.strip
end
rescue Errno::ENOENT
setup_rb_error $!.message + "\n#{File.basename($0)} config first"
end
end
def save
@items.each {|i| i.value }
File.open(savefile(), 'w') {|f|
@items.each do |i|
f.printf "%s=%s\n", i.name, i.value if i.value? and i.value
end
}
end
def load_standard_entries
standard_entries(@rbconfig).each do |ent|
add ent
end
end
def standard_entries(rbconfig)
c = rbconfig
rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT'])
major = c['MAJOR'].to_i
minor = c['MINOR'].to_i
teeny = c['TEENY'].to_i
version = "#{major}.#{minor}"
# ruby ver. >= 1.4.4?
newpath_p = ((major >= 2) or
((major == 1) and
((minor >= 5) or
((minor == 4) and (teeny >= 4)))))
if c['rubylibdir']
# V > 1.6.3
libruby = "#{c['prefix']}/lib/ruby"
librubyver = c['rubylibdir']
librubyverarch = c['archdir']
siteruby = c['sitedir']
siterubyver = c['sitelibdir']
siterubyverarch = c['sitearchdir']
elsif newpath_p
# 1.4.4 <= V <= 1.6.3
libruby = "#{c['prefix']}/lib/ruby"
librubyver = "#{c['prefix']}/lib/ruby/#{version}"
librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
siteruby = c['sitedir']
siterubyver = "$siteruby/#{version}"
siterubyverarch = "$siterubyver/#{c['arch']}"
else
# V < 1.4.4
libruby = "#{c['prefix']}/lib/ruby"
librubyver = "#{c['prefix']}/lib/ruby/#{version}"
librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby"
siterubyver = siteruby
siterubyverarch = "$siterubyver/#{c['arch']}"
end
parameterize = lambda {|path|
path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')
}
if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
else
makeprog = 'make'
end
[
ExecItem.new('installdirs', 'std/site/home',
'std: install under libruby; site: install under site_ruby; home: install under $HOME')\
{|val, table|
case val
when 'std'
table['rbdir'] = '$librubyver'
table['sodir'] = '$librubyverarch'
when 'site'
table['rbdir'] = '$siterubyver'
table['sodir'] = '$siterubyverarch'
when 'home'
setup_rb_error '$HOME was not set' unless ENV['HOME']
table['prefix'] = ENV['HOME']
table['rbdir'] = '$libdir/ruby'
table['sodir'] = '$libdir/ruby'
end
},
PathItem.new('prefix', 'path', c['prefix'],
'path prefix of target environment'),
PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
'the directory for commands'),
PathItem.new('libdir', 'path', parameterize.call(c['libdir']),
'the directory for libraries'),
PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
'the directory for shared data'),
PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
'the directory for man pages'),
PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
'the directory for system configuration files'),
PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']),
'the directory for local state data'),
PathItem.new('libruby', 'path', libruby,
'the directory for ruby libraries'),
PathItem.new('librubyver', 'path', librubyver,
'the directory for standard ruby libraries'),
PathItem.new('librubyverarch', 'path', librubyverarch,
'the directory for standard ruby extensions'),
PathItem.new('siteruby', 'path', siteruby,
'the directory for version-independent aux ruby libraries'),
PathItem.new('siterubyver', 'path', siterubyver,
'the directory for aux ruby libraries'),
PathItem.new('siterubyverarch', 'path', siterubyverarch,
'the directory for aux ruby binaries'),
PathItem.new('rbdir', 'path', '$siterubyver',
'the directory for ruby scripts'),
PathItem.new('sodir', 'path', '$siterubyverarch',
'the directory for ruby extentions'),
PathItem.new('rubypath', 'path', rubypath,
'the path to set to #! line'),
ProgramItem.new('rubyprog', 'name', rubypath,
'the ruby program using for installation'),
ProgramItem.new('makeprog', 'name', makeprog,
'the make program to compile ruby extentions'),
SelectItem.new('shebang', 'all/ruby/never', 'ruby',
'shebang line (#!) editing mode'),
BoolItem.new('without-ext', 'yes/no', 'no',
'does not compile/install ruby extentions')
]
end
private :standard_entries
def load_multipackage_entries
multipackage_entries().each do |ent|
add ent
end
end
def multipackage_entries
[
PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
'package names that you want to install'),
PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
'package names that you do not want to install')
]
end
private :multipackage_entries
ALIASES = {
'std-ruby' => 'librubyver',
'stdruby' => 'librubyver',
'rubylibdir' => 'librubyver',
'archdir' => 'librubyverarch',
'site-ruby-common' => 'siteruby', # For backward compatibility
'site-ruby' => 'siterubyver', # For backward compatibility
'bin-dir' => 'bindir',
'bin-dir' => 'bindir',
'rb-dir' => 'rbdir',
'so-dir' => 'sodir',
'data-dir' => 'datadir',
'ruby-path' => 'rubypath',
'ruby-prog' => 'rubyprog',
'ruby' => 'rubyprog',
'make-prog' => 'makeprog',
'make' => 'makeprog'
}
def fixup
ALIASES.each do |ali, name|
@table[ali] = @table[name]
end
end
def options_re
/\A--(#{@table.keys.join('|')})(?:=(.*))?\z/
end
def parse_opt(opt)
m = options_re().match(opt) or setup_rb_error "config: unknown option #{opt}"
m.to_a[1,2]
end
def dllext
@rbconfig['DLEXT']
end
def value_config?(name)
lookup(name).value?
end
class Item
def initialize(name, template, default, desc)
@name = name.freeze
@template = template
@value = default
@default = default
@description = desc
end
attr_reader :name
attr_reader :description
attr_accessor :default
alias help_default default
def help_opt
"--#{@name}=#{@template}"
end
def value?
true
end
def value
@value
end
def resolve(table)
@value.gsub(%r<\$([^/]+)>) { table[$1] }
end
def set(val)
@value = check(val)
end
private
def check(val)
setup_rb_error "config: --#{name} requires argument" unless val
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff