1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
# -*- ruby encoding: utf-8 -*-
##
# An LDAP Dataset. Used primarily as an intermediate format for converting
# to and from LDIF strings and Net::LDAP::Entry objects.
class Net::LDAP::Dataset < Hash
##
# Dataset object version, comments.
attr_accessor :version
attr_reader :comments
def initialize(*args, &block) # :nodoc:
super
@version = nil
@comments = []
end
##
# Outputs an LDAP Dataset as an array of strings representing LDIF
# entries.
def to_ldif
ary = []
if version
ary << "version: #{version}"
ary << ""
end
ary += @comments unless @comments.empty?
keys.sort.each do |dn|
ary << "dn: #{dn}"
attributes = self[dn].keys.map(&:to_s).sort
attributes.each do |attr|
self[dn][attr.to_sym].each do |value|
if attr == "userpassword" or value_is_binary?(value)
value = [value].pack("m").chomp.gsub(/\n/m, "\n ")
ary << "#{attr}:: #{value}"
else
ary << "#{attr}: #{value}"
end
end
end
ary << ""
end
block_given? and ary.each { |line| yield line}
ary
end
##
# Outputs an LDAP Dataset as an LDIF string.
def to_ldif_string
to_ldif.join("\n")
end
##
# Convert the parsed LDIF objects to Net::LDAP::Entry objects.
def to_entries
ary = []
keys.each do |dn|
entry = Net::LDAP::Entry.new(dn)
self[dn].each do |attr, value|
entry[attr] = value
end
ary << entry
end
ary
end
##
# This is an internal convenience method to determine if a value requires
# base64-encoding before conversion to LDIF output. The standard approach
# in most LDAP tools is to check whether the value is a password, or if
# the first or last bytes are non-printable. Microsoft Active Directory,
# on the other hand, sometimes sends values that are binary in the middle.
#
# In the worst cases, this could be a nasty performance killer, which is
# why we handle the simplest cases first. Ideally, we would also test the
# first/last byte, but it's a bit harder to do this in a way that's
# compatible with both 1.8.6 and 1.8.7.
def value_is_binary?(value) # :nodoc:
value = value.to_s
return true if value[0] == ?: or value[0] == ?<
value.each_byte { |byte| return true if (byte < 32) || (byte > 126) }
false
end
private :value_is_binary?
class << self
class ChompedIO # :nodoc:
def initialize(io)
@io = io
end
def gets
s = @io.gets
s.chomp if s
end
end
##
# Creates a Dataset object from an Entry object. Used mostly to assist
# with the conversion of
def from_entry(entry)
dataset = Net::LDAP::Dataset.new
hash = {}
entry.each_attribute do |attribute, value|
next if attribute == :dn
hash[attribute] = value
end
dataset[entry.dn] = hash
dataset
end
##
# Reads an object that returns data line-wise (using #gets) and parses
# LDIF data into a Dataset object.
def read_ldif(io)
ds = Net::LDAP::Dataset.new
io = ChompedIO.new(io)
line = io.gets
dn = nil
while line
new_line = io.gets
if new_line =~ /^ /
line << $'
else
nextline = new_line
if line =~ /^#/
ds.comments << line
yield :comment, line if block_given?
elsif line =~ /^version:[\s]*([0-9]+)$/i
ds.version = $1
yield :version, line if block_given?
elsif line =~ /^dn:([\:]?)[\s]*/i
# $1 is a colon if the dn-value is base-64 encoded
# $' is the dn-value
# Avoid the Base64 class because not all Ruby versions have it.
dn = ($1 == ":") ? $'.unpack('m').shift : $'
ds[dn] = Hash.new { |k, v| k[v] = [] }
yield :dn, dn if block_given?
elsif line.empty?
dn = nil
yield :end, nil if block_given?
elsif line =~ /^([^:]+):([\:]?)[\s]*/
# $1 is the attribute name
# $2 is a colon iff the attr-value is base-64 encoded
# $' is the attr-value
# Avoid the Base64 class because not all Ruby versions have it.
attrvalue = ($2 == ":") ? $'.unpack('m').shift : $'
ds[dn][$1.downcase.to_sym] << attrvalue
yield :attr, [$1.downcase.to_sym, attrvalue] if block_given?
end
line = nextline
end
end
ds
end
end
end
|