Project

General

Profile

Download (9.36 KB) Statistics
| Branch: | Tag: | Revision:
89d8bebc Marc Dequènes (Duck)
#!/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'
bbb82941 Marc Dequènes (Duck)
require 'ldap_shadows/display_utils'
89d8bebc Marc Dequènes (Duck)
require 'yaml'
require 'cmdparse2'

bbb82941 Marc Dequènes (Duck)
include LdapShadows

b0304d30 Marc Dequènes (Duck)
89d8bebc Marc Dequènes (Duck)
config_str = IO.read(File.join(LdapShadows::Config::CFG_DIR, "test.conf"))
1744c478 Marc Dequènes (Duck)
config = YAML.load(config_str)
config_str_prv_filelist = [
File.join(ENV['HOME'], ".shadowwalker"),
File.join(LdapShadows::Config::CFG_DIR, "private.conf")
]
config_str_prv_filelist.each do |file|
if File.exists?(file)
config_str_prv = IO.read(file)
config.merge!(YAML.load(config_str_prv))
break
end
end
config.recursive_symbolize_keys!
89d8bebc Marc Dequènes (Duck)
ActiveLdap::Base.setup_connection(config[:ldap])

bbb82941 Marc Dequènes (Duck)
$program_options = {}

89d8bebc Marc Dequènes (Duck)
cmdparser = CmdParse::CommandParser.new(true)
bbb82941 Marc Dequènes (Duck)
cmdparser.banner = PRODUCT
5ca3fa56 Marc Dequènes (Duck)
cmdparser.program_name = File.basename(__FILE__)
bbb82941 Marc Dequènes (Duck)
cmdparser.program_version = VERSION.split(".")
89d8bebc Marc Dequènes (Duck)
cmdparser.options = CmdParse::OptionParserWrapper.new do |opt|
opt.separator "Global options:"
bbb82941 Marc Dequènes (Duck)
opt.on("--debug", "Output debug info without being formated") {|t| $program_options[:debug] = true }
opt.on("--expert", "Output extra info for expert users") {|t| $program_options[:expert] = true }
opt.on("--handles", "Output with handles (objects/field/... keys used for manipulations)") {|t| $program_options[:handles] = true }
89d8bebc Marc Dequènes (Duck)
end

cmdparser.add_command(CmdParse::HelpCommand.new)
cmdparser.add_command(CmdParse::VersionCommand.new)

bbb82941 Marc Dequènes (Duck)
ldapctl = Controller.new
1744c478 Marc Dequènes (Duck)
ldapctl.set_global_config(config[:presentation])
89d8bebc Marc Dequènes (Duck)
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|
6089b33a Marc Dequènes (Duck)
if args.size < 1
89d8bebc Marc Dequènes (Duck)
STDERR.puts "syntax error: no object name given"
exit 1
end

b0304d30 Marc Dequènes (Duck)
obj_hdl = args.shift.singularize
6089b33a Marc Dequènes (Duck)
case obj_hdl
when ':object'
puts "=== List of LDAP objects ==="
ldapctl.objects.each do |obj_name|
puts " - #{obj_name}"
end
when ':aspect'
if args.empty?
STDERR.puts "syntax error: no sub-object name given"
exit 1
end

subobj_hdl = args.shift.singularize
obj_klass = ldapctl.find_klass(subobj_hdl)
if obj_klass.nil?
STDERR.puts "No such object '#{obj_hdl}'."
exit 2
end

subobj_human_name = Translator.translate_object_name(subobj_hdl)
puts "=== List of LDAP aspects of #{subobj_human_name.pluralize} ==="
obj_klass.possible_aspects.each do |subobj_name|
puts " - #{subobj_name}"
end
else
obj_klass = ldapctl.find_klass(obj_hdl)
if obj_klass.nil?
STDERR.puts "No such object '#{obj_hdl}'."
exit 2
end

obj_human_name = Translator.translate_object_name(obj_hdl)
Display.display_item_list("List of #{obj_human_name.pluralize}", obj_klass.find(:all))
89d8bebc Marc Dequènes (Duck)
end
end
cmdparser.add_command(cmd)

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

b0304d30 Marc Dequènes (Duck)
obj_hdl = args.shift
89d8bebc Marc Dequènes (Duck)
obj_klass = ldapctl.find_klass(obj_hdl)
if obj_klass.nil?
STDERR.puts "No such object '#{obj_hdl}'."
exit 2
end

b0304d30 Marc Dequènes (Duck)
item_hdl = args.shift
89d8bebc Marc Dequènes (Duck)
begin
c6632e15 Marc Dequènes (Duck)
item = obj_klass.find(item_hdl, :attributes => ["*", "+"])
89d8bebc Marc Dequènes (Duck)
rescue ActiveLdap::EntryNotFound
STDERR.puts "No such item '#{obj_hdl}/#{item_hdl}'"
exit 2
end

bbb82941 Marc Dequènes (Duck)
Display.display_item(item, $program_options)
89d8bebc Marc Dequènes (Duck)
end
cmdparser.add_command(cmd)

0d75a0b6 Marc Dequènes (Duck)
cmd = CmdParse::Command.new('tree', false)
cmd.short_desc = "show skeleton objects tree"
cmd.set_execution_block do |args|
puts "Tree:"

bbb82941 Marc Dequènes (Duck)
base_dn = ActiveLdap::DistinguishedName.parse(LdapObject.base)
0d75a0b6 Marc Dequènes (Duck)
gconfig = ldapctl.get_global_config()
if gconfig.has_key?(:tree_objects)
tree = {}

gconfig[:tree_objects].each do |obj_hdl|
obj_klass = ldapctl.find_klass(obj_hdl)
raise "object '#{obj_hdl}' not defined" unless obj_klass

obj_klass.find(:all).each do |obj|
ptree = tree
pdn = nil
(obj.dn_obj - base_dn).to_s.split(',').reverse.each do |pdn|
ptree[pdn] = {} unless ptree.has_key?(pdn)
ptree = ptree[pdn]
end
ptree = nil
end
end
tree = {base_dn => tree}

bbb82941 Marc Dequènes (Duck)
Display.display_hash_tree(tree, 0)
0d75a0b6 Marc Dequènes (Duck)
end
end
cmdparser.add_command(cmd)

b0304d30 Marc Dequènes (Duck)
cmd = CmdParse::Command.new('mod', false)
cmd.short_desc = "Modify attributes of an object"
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.shift
obj_klass = ldapctl.find_klass(obj_hdl)
if obj_klass.nil?
STDERR.puts "No such object '#{obj_hdl}'."
exit 2
end

item_hdl = args.shift
begin
0814bfc3 Marc Dequènes (Duck)
item = obj_klass.find(item_hdl, :attributes => ["*",])
b0304d30 Marc Dequènes (Duck)
rescue ActiveLdap::EntryNotFound
STDERR.puts "No such item '#{obj_hdl}/#{item_hdl}'"
exit 2
end

34cb4054 Marc Dequènes (Duck)
modification_done = false
b0304d30 Marc Dequènes (Duck)
args.each do |mod_info|
34cb4054 Marc Dequènes (Duck)
mod_info =~ /^([a-zA-Z]+(?::[a-zA-Z]+)?)(=|\+=|-=)(.*)$/
0814bfc3 Marc Dequènes (Duck)
key = $1
op = $2
val = $3
43bd8057 Marc Dequènes (Duck)
puts "key: #{key}"
puts "op: #{op}"
puts "val: #{val}"
b0304d30 Marc Dequènes (Duck)
0814bfc3 Marc Dequènes (Duck)
if key.nil?
STDERR.puts "Syntax error in modification parameters: invalid field name"
exit 1
end

43bd8057 Marc Dequènes (Duck)
if key.index(":")
type, field = key.split(":")
else
type = nil
field = key
0814bfc3 Marc Dequènes (Duck)
end

43bd8057 Marc Dequènes (Duck)
case type
when nil
unless item.has_attribute?(field)
STDERR.puts "No such field '#{field}' in object '#{obj_hdl}'."
exit 2
end

attr_info = ActiveLdap::Base.schema.attribute(field)
if attr_info.read_only?
STDERR.puts "The field '#{field}' cannot be modified (read only), skipping."
next
end

old_val = item.send(field)
old_val = [old_val] unless old_val.is_a? Array
when 'rel'
unless item.relations.include?(field)
STDERR.puts "No such relation '#{field}' for object '#{obj_hdl}'."
exit 2
end

34cb4054 Marc Dequènes (Duck)
rel_info = item.info_for_relation(field)
if rel_info[:read_only]
STDERR.puts "The relation '#{field}' cannot be modified (read only), skipping."
next
end
43bd8057 Marc Dequènes (Duck)
# fetch remote object in relation, which will be the real 'val'
foreign_item_list = rel_info[:foreign_klass].find(:all, val)
if foreign_item_list.empty?
STDERR.puts "Foreign item '#{val}' for relation '#{field}' not found."
exit 2
end
if foreign_item_list.size > 1
STDERR.puts "Ambiguous item '#{val}' for relation '#{field}' (#{foreign_item_list.size} possible items)"
exit 4
end
val = foreign_item_list.first
else
STDERR.puts "Unknown type '#{type}' for field '#{field}'."
end
0814bfc3 Marc Dequènes (Duck)
43bd8057 Marc Dequènes (Duck)
# if val is nil or the latest value is removed, then the atribute is removed from the object,
# or the association's attribute is removed from one side
0814bfc3 Marc Dequènes (Duck)
case op
when '='
43bd8057 Marc Dequènes (Duck)
item.send(field + "=", [val])
0814bfc3 Marc Dequènes (Duck)
when '+='
43bd8057 Marc Dequènes (Duck)
case type
when nil
if attr_info.single_value?
STDERR.puts "The field '#{field}' cannot hold more than one value."
exit 3
end

new_val = old_val << val
item.send(field + "=", new_val)
when 'rel'
if rel_info[:single_value]
STDERR.puts "The relation '#{field}' cannot hold more than one foreign item."
exit 3
end

item.send(field) << val
0814bfc3 Marc Dequènes (Duck)
end
when '-='
43bd8057 Marc Dequènes (Duck)
case type
when nil
new_val = old_val - [val]
when 'rel'
item.send(field).delete(val)
end
0814bfc3 Marc Dequènes (Duck)
else
STDERR.puts "Syntax error in modification parameters: wrong operator"
exit 1
end
34cb4054 Marc Dequènes (Duck)
modification_done = true
b0304d30 Marc Dequènes (Duck)
end
0814bfc3 Marc Dequènes (Duck)
34cb4054 Marc Dequènes (Duck)
if modification_done
puts "Modified attributes:"
p item.modified_attributes
begin
item.save!
rescue ActiveLdap::OperationNotPermitted => e
STDERR.puts "You don't have enough rights to modify--at least--one of these attributes."
exit 3
rescue ActiveLdap::LdapError => e
STDERR.puts "LDAP error: " + e.to_s
exit 3
rescue ActiveLdap::EntryInvalid => e
STDERR.puts e.to_s
exit 3
end
b0304d30 Marc Dequènes (Duck)
34cb4054 Marc Dequènes (Duck)
puts "Modification done."
else
puts "Nothing to do."
end
b0304d30 Marc Dequènes (Duck)
end
cmdparser.add_command(cmd)

89d8bebc Marc Dequènes (Duck)
cmdparser.parse

0814bfc3 Marc Dequènes (Duck)
# ActiveLdap bugs:
# - fetching operational attributes in an object used for modification cause
# collect_modified_attributes() to catch them by mistake and triggers an
# ActiveLdap::LdapError::ConstraintViolation exception