Project

General

Profile

Download (9.13 KB) Statistics
| Branch: | Tag: | Revision:
#--
# LdapShadows, a Medium-level LDAP Access Library and Tool.
# Copyright (c) 2009-2010 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
module Manipulation
def self.item_modify_from_strings(item, str_list)
str_list = [str_list] unless str_list.is_a? Array

modification_done = false
str_list.each do |str|
unless str =~ /^([a-zA-Z]*(?::[a-zA-Z]+)?)(=|\+=|-=)(.*)$/
raise SyntaxError, _("modification parameter '%s' is invalid") % str
end
key = $1
op = $2
val = $3

mod_done = item.modify(key, op, val)
modification_done ||= mod_done
end

modification_done
end

def self.items_find_from_strings(shadow, str_list)
ldap_search_objects = "(objectClass=*)"
ldap_search_aspects = ""
ldap_search_fields = []
ldap_search_where = []
ldap_search_exclude = []
str_list.each do |str|
unless str =~ /^([a-zA-Z]*(?::[a-zA-Z]+)?)(=|~=)(.*)$/
raise SyntaxError, _("search parameter '%s' is invalid") % str
end
key = $1
op = $2
val = $3

if key.index(":")
type, field = key.split(":")
else
type = nil
field = key
end

case type
when nil
ldap_search_fields << ldap_search_string_field(field, op, val)
when 'rel'
raise PreProcessingError, _("Searching relations is not implemented yet")
when ''
case field
when 'objects'
ldap_search_objects = ldap_search_string_objects(shadow, field, op, val)
when 'aspects'
ldap_search_aspects = ldap_search_string_aspects(shadow, field, op, val)
when 'parents'
val.split(",").each do |parent_fh|
parent = find_item_by_full_handle(shadow, parent_fh)
ldap_search_where << [parent.dn.to_s, :one]
end
when 'siblings'
val.split(",").each do |sibling_fh|
sibling = find_item_by_full_handle(shadow, sibling_fh)
ldap_search_where << [sibling.family_parent_dn.to_s, :one]
ldap_search_exclude << sibling.dn.to_s
end
when 'children'
val.split(",").each do |child_fh|
child = find_item_by_full_handle(shadow, child_fh)
ldap_search_where << [child.family_parent_dn.to_s, :base]
end
when 'ancestors'
val.split(",").each do |parent_fh|
parent = find_item_by_full_handle(shadow, parent_fh)
ldap_search_where << [parent.dn.to_s, :sub]
ldap_search_exclude << parent.dn.to_s
end
when 'successors'
val.split(",").each do |child_fh|
child = find_item_by_full_handle(shadow, child_fh)
dn = child.dn_obj.dup
while dn.to_s != ActiveLdap::Base.base.to_s
dn.shift
ldap_search_where << [dn.to_s, :base]
end
end
else
raise PreProcessingError, _("Unknown core field '%s'") % field
end
else
raise PreProcessingError, _("Unknown type '%s' for field '%s'") % [type, field]
end
end
ldap_search_string = "(&" + ldap_search_objects + ldap_search_aspects + ldap_search_fields.join + ")"

if ldap_search_where.empty?
ldap_search_where << [ActiveLdap::Base.base.to_s, :sub]
end
res = []
ldap_search_where.each do |where|
res += ActiveLdap::Base.find(:all, :base => where[0], :scope => where[1], :filter => ldap_search_string, :attributes => ["objectClass"])
end

res.uniq.select {|item| not ldap_search_exclude.include?(item.dn.to_s) }
end

def self.find_raw_item_object(shadow, raw_item)
# easy case
base_obj_klass = LdapShadows::Elements::LdapObject
if raw_item.class != base_obj_klass and raw_item.class.ancestors.include?(base_obj_klass)
return raw_item.class.handle
end

shadow.objects.each do |obj_hdl|
obj_klass = shadow.get_object(obj_hdl)
ldap_classes = obj_klass.required_classes.sort
item_classes = (raw_item.classes - ['top']).sort
return obj_hdl if (item_classes & ldap_classes == ldap_classes) and (obj_klass.excluded_classes & item_classes).empty?
end
nil
end

def self.raw_item_info(shadow, raw_item, dn = nil)
is_root = false

if raw_item
is_root = true if raw_item.dn == ActiveLdap::Base.base

obj_hdl = self.find_raw_item_object(shadow, raw_item)
if obj_hdl
obj_klass = shadow.get_object(obj_hdl)
item = obj_klass.new(raw_item.dn)

name = item.full_handle
name = "root|" + name if is_root
return {:full_handle => item.full_handle, :name => name, :item => item, :object => obj_klass, :is_root => is_root}
end

item_fake_hdl = raw_item.dn
else
item_fake_hdl = dn || "???"
end

{:full_handle => nil, :name => "unknown/#{item_fake_hdl}", :is_root => is_root}
end

def self.interpret_field_value(shadow, syntax, val)
case syntax
when "1.3.6.1.4.1.1466.115.121.1.12"
raw_item = ActiveLdap::Base.find(:first, :base => val.to_s, :scope => :base)
LdapShadows::Manipulation.raw_item_info(shadow, raw_item, val.to_s)[:full_handle]
else
val
end
end

def self.looks_like_full_handle?(full_handle)
full_handle =~ LdapShadows::Elements::LdapObject::FULL_HANDLE_PATTERN
res = $~
res = res.to_a if res
res
end

def self.find_item_by_full_handle(shadow, full_handle, with_admin_fields = false)
if full_handle == "root"
raw_item_dn = ActiveLdap::Base.base.to_s
raw_item = ActiveLdap::Base.find(:first, :base => raw_item_dn, :scope => :base)
info = raw_item_info(shadow, raw_item, raw_item_dn)
if info.nil?
raise PreProcessingError, _("No such item 'root'")
elsif info[:object].nil?
raise PreProcessingError, _("Root item found, but no corresponding object defined")
else
full_handle = info[:full_handle]
end
end

m = looks_like_full_handle?(full_handle)
raise SyntaxError, _("Bad handle '%s'") % full_handle unless m
obj_hdl = m[1].downcase.singularize
item_hdl = m[2]

obj_klass = shadow.get_object(obj_hdl)
raise PreProcessingError, _("No such object '%s'") % obj_hdl if obj_klass.nil?

attr_list = ["*"]
attr_list << "+" if with_admin_fields

begin
obj_klass.find(item_hdl, :attributes => attr_list)
rescue ActiveLdap::EntryNotFound
raise PreProcessingError, _("No such item '%s/%s'") % [obj_klass.handle, item_hdl]
end
end

protected

def self.ldap_search_string_field(field, op, val)
esc_val = ActiveLdap::Base.connection.escape_filter_value(val)
case op
when "="
"(#{field}=#{esc_val})"

when "~="
raise PreProcessingError, _("Searching with regex is not implemented yet")

else
raise SyntaxError, _("Unknown operator '%s'") % op
end
end

def self.ldap_search_string_objects(shadow, field, op, val_list)
ldap_search_parts = val_list.split(",").collect do |val|
obj_hdl = val.downcase.singularize
obj_klass = shadow.get_object(obj_hdl)
raise PreProcessingError, _("No such object '%s'") % val if obj_klass.nil?

ldap_classes = obj_klass.required_classes

case op
when "="
"(&" + ldap_classes.collect{|cl| "(objectClass=#{cl})" }.join + ")"

when "~="
raise PreProcessingError, _("Searching with regex is not possible with objects")

else
raise SyntaxError, _("Unknown operator '%s'") % op
end
end
"(|" + ldap_search_parts.join + ")"
end

def self.ldap_search_string_aspects(shadow, field, op, val_list)
ldap_search_parts = val_list.split(",").collect do |val|
aspect = shadow.get_aspect(val)
raise PreProcessingError, _("No such aspect '%s'") % val if aspect.nil?

ldap_classes = aspect.parameters[:mapping][:classes]

case op
when "="
"(&" + ldap_classes.collect{|cl| "(objectClass=#{cl})" }.join + ")"

when "~="
raise PreProcessingError, _("Searching with regex is not possible with aspects")

else
raise SyntaxError, _("Unknown operator '%s'") % op
end
end
"(&" + ldap_search_parts.join + ")"
end
end
end
(8-8/9)