prathe-net-ldap 0.2.20110317223538
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.autotest +11 -0
- data/.gemtest +0 -0
- data/.rspec +2 -0
- data/Contributors.rdoc +21 -0
- data/Hacking.rdoc +68 -0
- data/History.rdoc +172 -0
- data/License.rdoc +29 -0
- data/Manifest.txt +49 -0
- data/README.rdoc +52 -0
- data/Rakefile +75 -0
- data/autotest/discover.rb +1 -0
- data/lib/net-ldap.rb +2 -0
- data/lib/net/ber.rb +318 -0
- data/lib/net/ber/ber_parser.rb +168 -0
- data/lib/net/ber/core_ext.rb +62 -0
- data/lib/net/ber/core_ext/array.rb +82 -0
- data/lib/net/ber/core_ext/bignum.rb +22 -0
- data/lib/net/ber/core_ext/false_class.rb +10 -0
- data/lib/net/ber/core_ext/fixnum.rb +66 -0
- data/lib/net/ber/core_ext/string.rb +60 -0
- data/lib/net/ber/core_ext/true_class.rb +12 -0
- data/lib/net/ldap.rb +1556 -0
- data/lib/net/ldap/dataset.rb +154 -0
- data/lib/net/ldap/dn.rb +225 -0
- data/lib/net/ldap/entry.rb +185 -0
- data/lib/net/ldap/filter.rb +759 -0
- data/lib/net/ldap/password.rb +31 -0
- data/lib/net/ldap/pdu.rb +256 -0
- data/lib/net/snmp.rb +268 -0
- data/net-ldap.gemspec +59 -0
- data/spec/integration/ssl_ber_spec.rb +36 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/unit/ber/ber_spec.rb +109 -0
- data/spec/unit/ber/core_ext/string_spec.rb +51 -0
- data/spec/unit/ldap/dn_spec.rb +80 -0
- data/spec/unit/ldap/entry_spec.rb +51 -0
- data/spec/unit/ldap/filter_spec.rb +84 -0
- data/spec/unit/ldap_spec.rb +48 -0
- data/test/common.rb +3 -0
- data/test/test_entry.rb +59 -0
- data/test/test_filter.rb +122 -0
- data/test/test_ldap_connection.rb +24 -0
- data/test/test_ldif.rb +79 -0
- data/test/test_password.rb +17 -0
- data/test/test_rename.rb +77 -0
- data/test/test_snmp.rb +114 -0
- data/test/testdata.ldif +101 -0
- data/testserver/ldapserver.rb +210 -0
- data/testserver/testdata.ldif +101 -0
- metadata +206 -0
@@ -0,0 +1,154 @@
|
|
1
|
+
# -*- ruby encoding: utf-8 -*-
|
2
|
+
##
|
3
|
+
# An LDAP Dataset. Used primarily as an intermediate format for converting
|
4
|
+
# to and from LDIF strings and Net::LDAP::Entry objects.
|
5
|
+
class Net::LDAP::Dataset < Hash
|
6
|
+
##
|
7
|
+
# Dataset object comments.
|
8
|
+
attr_reader :comments
|
9
|
+
|
10
|
+
def initialize(*args, &block) # :nodoc:
|
11
|
+
super
|
12
|
+
@comments = []
|
13
|
+
end
|
14
|
+
|
15
|
+
##
|
16
|
+
# Outputs an LDAP Dataset as an array of strings representing LDIF
|
17
|
+
# entries.
|
18
|
+
def to_ldif
|
19
|
+
ary = []
|
20
|
+
ary += @comments unless @comments.empty?
|
21
|
+
keys.sort.each do |dn|
|
22
|
+
ary << "dn: #{dn}"
|
23
|
+
|
24
|
+
attributes = self[dn].keys.map { |attr| attr.to_s }.sort
|
25
|
+
attributes.each do |attr|
|
26
|
+
self[dn][attr.to_sym].each do |value|
|
27
|
+
if attr == "userpassword" or value_is_binary?(value)
|
28
|
+
value = [value].pack("m").chomp.gsub(/\n/m, "\n ")
|
29
|
+
ary << "#{attr}:: #{value}"
|
30
|
+
else
|
31
|
+
ary << "#{attr}: #{value}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
ary << ""
|
37
|
+
end
|
38
|
+
block_given? and ary.each { |line| yield line}
|
39
|
+
|
40
|
+
ary
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# Outputs an LDAP Dataset as an LDIF string.
|
45
|
+
def to_ldif_string
|
46
|
+
to_ldif.join("\n")
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# Convert the parsed LDIF objects to Net::LDAP::Entry objects.
|
51
|
+
def to_entries
|
52
|
+
ary = []
|
53
|
+
keys.each do |dn|
|
54
|
+
entry = Net::LDAP::Entry.new(dn)
|
55
|
+
self[dn].each do |attr, value|
|
56
|
+
entry[attr] = value
|
57
|
+
end
|
58
|
+
ary << entry
|
59
|
+
end
|
60
|
+
ary
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# This is an internal convenience method to determine if a value requires
|
65
|
+
# base64-encoding before conversion to LDIF output. The standard approach
|
66
|
+
# in most LDAP tools is to check whether the value is a password, or if
|
67
|
+
# the first or last bytes are non-printable. Microsoft Active Directory,
|
68
|
+
# on the other hand, sometimes sends values that are binary in the middle.
|
69
|
+
#
|
70
|
+
# In the worst cases, this could be a nasty performance killer, which is
|
71
|
+
# why we handle the simplest cases first. Ideally, we would also test the
|
72
|
+
# first/last byte, but it's a bit harder to do this in a way that's
|
73
|
+
# compatible with both 1.8.6 and 1.8.7.
|
74
|
+
def value_is_binary?(value) # :nodoc:
|
75
|
+
value = value.to_s
|
76
|
+
return true if value[0] == ?: or value[0] == ?<
|
77
|
+
value.each_byte { |byte| return true if (byte < 32) || (byte > 126) }
|
78
|
+
false
|
79
|
+
end
|
80
|
+
private :value_is_binary?
|
81
|
+
|
82
|
+
class << self
|
83
|
+
class ChompedIO # :nodoc:
|
84
|
+
def initialize(io)
|
85
|
+
@io = io
|
86
|
+
end
|
87
|
+
def gets
|
88
|
+
s = @io.gets
|
89
|
+
s.chomp if s
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
##
|
94
|
+
# Creates a Dataset object from an Entry object. Used mostly to assist
|
95
|
+
# with the conversion of
|
96
|
+
def from_entry(entry)
|
97
|
+
dataset = Net::LDAP::Dataset.new
|
98
|
+
hash = { }
|
99
|
+
entry.each_attribute do |attribute, value|
|
100
|
+
next if attribute == :dn
|
101
|
+
hash[attribute] = value
|
102
|
+
end
|
103
|
+
dataset[entry.dn] = hash
|
104
|
+
dataset
|
105
|
+
end
|
106
|
+
|
107
|
+
##
|
108
|
+
# Reads an object that returns data line-wise (using #gets) and parses
|
109
|
+
# LDIF data into a Dataset object.
|
110
|
+
def read_ldif(io)
|
111
|
+
ds = Net::LDAP::Dataset.new
|
112
|
+
io = ChompedIO.new(io)
|
113
|
+
|
114
|
+
line = io.gets
|
115
|
+
dn = nil
|
116
|
+
|
117
|
+
while line
|
118
|
+
new_line = io.gets
|
119
|
+
|
120
|
+
if new_line =~ /^ /
|
121
|
+
line << $'
|
122
|
+
else
|
123
|
+
nextline = new_line
|
124
|
+
|
125
|
+
if line =~ /^#/
|
126
|
+
ds.comments << line
|
127
|
+
yield :comment, line if block_given?
|
128
|
+
elsif line =~ /^dn:[\s]*/i
|
129
|
+
dn = $'
|
130
|
+
ds[dn] = Hash.new { |k,v| k[v] = [] }
|
131
|
+
yield :dn, dn if block_given?
|
132
|
+
elsif line.empty?
|
133
|
+
dn = nil
|
134
|
+
yield :end, nil if block_given?
|
135
|
+
elsif line =~ /^([^:]+):([\:]?)[\s]*/
|
136
|
+
# $1 is the attribute name
|
137
|
+
# $2 is a colon iff the attr-value is base-64 encoded
|
138
|
+
# $' is the attr-value
|
139
|
+
# Avoid the Base64 class because not all Ruby versions have it.
|
140
|
+
attrvalue = ($2 == ":") ? $'.unpack('m').shift : $'
|
141
|
+
ds[dn][$1.downcase.to_sym] << attrvalue
|
142
|
+
yield :attr, [$1.downcase.to_sym, attrvalue] if block_given?
|
143
|
+
end
|
144
|
+
|
145
|
+
line = nextline
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
ds
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
require 'net/ldap/entry' unless defined? Net::LDAP::Entry
|
data/lib/net/ldap/dn.rb
ADDED
@@ -0,0 +1,225 @@
|
|
1
|
+
# -*- ruby encoding: utf-8 -*-
|
2
|
+
|
3
|
+
##
|
4
|
+
# Objects of this class represent an LDAP DN ("Distinguished Name"). A DN
|
5
|
+
# ("Distinguished Name") is a unique identifier for an entry within an LDAP
|
6
|
+
# directory. It is made up of a number of other attributes strung together,
|
7
|
+
# to identify the entry in the tree.
|
8
|
+
#
|
9
|
+
# Each attribute that makes up a DN needs to have its value escaped so that
|
10
|
+
# the DN is valid. This class helps take care of that.
|
11
|
+
#
|
12
|
+
# A fully escaped DN needs to be unescaped when analysing its contents. This
|
13
|
+
# class also helps take care of that.
|
14
|
+
class Net::LDAP::DN
|
15
|
+
##
|
16
|
+
# Initialize a DN, escaping as required. Pass in attributes in name/value
|
17
|
+
# pairs. If there is a left over argument, it will be appended to the dn
|
18
|
+
# without escaping (useful for a base string).
|
19
|
+
#
|
20
|
+
# Most uses of this class will be to escape a DN, rather than to parse it,
|
21
|
+
# so storing the dn as an escaped String and parsing parts as required
|
22
|
+
# with a state machine seems sensible.
|
23
|
+
def initialize(*args)
|
24
|
+
buffer = StringIO.new
|
25
|
+
|
26
|
+
args.each_index do |index|
|
27
|
+
buffer << "=" if index % 2 == 1
|
28
|
+
buffer << "," if index % 2 == 0 && index != 0
|
29
|
+
|
30
|
+
if index < args.length - 1 || index % 2 == 1
|
31
|
+
buffer << Net::LDAP::DN.escape(args[index])
|
32
|
+
else
|
33
|
+
buffer << args[index]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
@dn = buffer.string
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
# Parse a DN into key value pairs using ASN from
|
42
|
+
# http://tools.ietf.org/html/rfc2253 section 3.
|
43
|
+
def each_pair
|
44
|
+
state = :key
|
45
|
+
key = StringIO.new
|
46
|
+
value = StringIO.new
|
47
|
+
hex_buffer = ""
|
48
|
+
|
49
|
+
@dn.each_char do |char|
|
50
|
+
case state
|
51
|
+
when :key then
|
52
|
+
case char
|
53
|
+
when 'a'..'z', 'A'..'Z' then
|
54
|
+
state = :key_normal
|
55
|
+
key << char
|
56
|
+
when '0'..'9' then
|
57
|
+
state = :key_oid
|
58
|
+
key << char
|
59
|
+
when ' ' then state = :key
|
60
|
+
else raise "DN badly formed"
|
61
|
+
end
|
62
|
+
when :key_normal then
|
63
|
+
case char
|
64
|
+
when '=' then state = :value
|
65
|
+
when 'a'..'z', 'A'..'Z', '0'..'9', '-', ' ' then key << char
|
66
|
+
else raise "DN badly formed"
|
67
|
+
end
|
68
|
+
when :key_oid then
|
69
|
+
case char
|
70
|
+
when '=' then state = :value
|
71
|
+
when '0'..'9', '.', ' ' then key << char
|
72
|
+
else raise "DN badly formed"
|
73
|
+
end
|
74
|
+
when :value then
|
75
|
+
case char
|
76
|
+
when '\\' then state = :value_normal_escape
|
77
|
+
when '"' then state = :value_quoted
|
78
|
+
when ' ' then state = :value
|
79
|
+
when '#' then
|
80
|
+
state = :value_hexstring
|
81
|
+
value << char
|
82
|
+
when ',' then
|
83
|
+
state = :key
|
84
|
+
yield key.string.strip, value.string.rstrip
|
85
|
+
key = StringIO.new
|
86
|
+
value = StringIO.new;
|
87
|
+
else
|
88
|
+
state = :value_normal
|
89
|
+
value << char
|
90
|
+
end
|
91
|
+
when :value_normal then
|
92
|
+
case char
|
93
|
+
when '\\' then state = :value_normal_escape
|
94
|
+
when ',' then
|
95
|
+
state = :key
|
96
|
+
yield key.string.strip, value.string.rstrip
|
97
|
+
key = StringIO.new
|
98
|
+
value = StringIO.new;
|
99
|
+
else value << char
|
100
|
+
end
|
101
|
+
when :value_normal_escape then
|
102
|
+
case char
|
103
|
+
when '0'..'9', 'a'..'f', 'A'..'F' then
|
104
|
+
state = :value_normal_escape_hex
|
105
|
+
hex_buffer = char
|
106
|
+
else state = :value_normal; value << char
|
107
|
+
end
|
108
|
+
when :value_normal_escape_hex then
|
109
|
+
case char
|
110
|
+
when '0'..'9', 'a'..'f', 'A'..'F' then
|
111
|
+
state = :value_normal
|
112
|
+
value << "#{hex_buffer}#{char}".to_i(16).chr
|
113
|
+
else raise "DN badly formed"
|
114
|
+
end
|
115
|
+
when :value_quoted then
|
116
|
+
case char
|
117
|
+
when '\\' then state = :value_quoted_escape
|
118
|
+
when '"' then state = :value_end
|
119
|
+
else value << char
|
120
|
+
end
|
121
|
+
when :value_quoted_escape then
|
122
|
+
case char
|
123
|
+
when '0'..'9', 'a'..'f', 'A'..'F' then
|
124
|
+
state = :value_quoted_escape_hex
|
125
|
+
hex_buffer = char
|
126
|
+
else
|
127
|
+
state = :value_quoted;
|
128
|
+
value << char
|
129
|
+
end
|
130
|
+
when :value_quoted_escape_hex then
|
131
|
+
case char
|
132
|
+
when '0'..'9', 'a'..'f', 'A'..'F' then
|
133
|
+
state = :value_quoted
|
134
|
+
value << "#{hex_buffer}#{char}".to_i(16).chr
|
135
|
+
else raise "DN badly formed"
|
136
|
+
end
|
137
|
+
when :value_hexstring then
|
138
|
+
case char
|
139
|
+
when '0'..'9', 'a'..'f', 'A'..'F' then
|
140
|
+
state = :value_hexstring_hex
|
141
|
+
value << char
|
142
|
+
when ' ' then state = :value_end
|
143
|
+
when ',' then
|
144
|
+
state = :key
|
145
|
+
yield key.string.strip, value.string.rstrip
|
146
|
+
key = StringIO.new
|
147
|
+
value = StringIO.new;
|
148
|
+
else raise "DN badly formed"
|
149
|
+
end
|
150
|
+
when :value_hexstring_hex then
|
151
|
+
case char
|
152
|
+
when '0'..'9', 'a'..'f', 'A'..'F' then
|
153
|
+
state = :value_hexstring
|
154
|
+
value << char
|
155
|
+
else raise "DN badly formed"
|
156
|
+
end
|
157
|
+
when :value_end then
|
158
|
+
case char
|
159
|
+
when ' ' then state = :value_end
|
160
|
+
when ',' then
|
161
|
+
state = :key
|
162
|
+
yield key.string.strip, value.string.rstrip
|
163
|
+
key = StringIO.new
|
164
|
+
value = StringIO.new;
|
165
|
+
else raise "DN badly formed"
|
166
|
+
end
|
167
|
+
else raise "Fell out of state machine"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# Last pair
|
172
|
+
if [:value, :value_normal, :value_hexstring, :value_end].include? state
|
173
|
+
yield key.string.strip, value.string.rstrip
|
174
|
+
else
|
175
|
+
raise "DN badly formed"
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
##
|
180
|
+
# Returns the DN as an array in the form expected by the constructor.
|
181
|
+
def to_a
|
182
|
+
a = []
|
183
|
+
self.each_pair { |key, value| a << key << value }
|
184
|
+
a
|
185
|
+
end
|
186
|
+
|
187
|
+
##
|
188
|
+
# Return the DN as an escaped string.
|
189
|
+
def to_s
|
190
|
+
@dn
|
191
|
+
end
|
192
|
+
|
193
|
+
# http://tools.ietf.org/html/rfc2253 section 2.4 lists these exceptions
|
194
|
+
# for dn values. All of the following must be escaped in any normal string
|
195
|
+
# using a single backslash ('\') as escape.
|
196
|
+
ESCAPES = {
|
197
|
+
',' => ',',
|
198
|
+
'+' => '+',
|
199
|
+
'"' => '"',
|
200
|
+
'\\' => '\\',
|
201
|
+
'<' => '<',
|
202
|
+
'>' => '>',
|
203
|
+
';' => ';',
|
204
|
+
}
|
205
|
+
|
206
|
+
# Compiled character class regexp using the keys from the above hash, and
|
207
|
+
# checking for a space or # at the start, or space at the end, of the
|
208
|
+
# string.
|
209
|
+
ESCAPE_RE = Regexp.new("(^ |^#| $|[" +
|
210
|
+
ESCAPES.keys.map { |e| Regexp.escape(e) }.join +
|
211
|
+
"])")
|
212
|
+
|
213
|
+
##
|
214
|
+
# Escape a string for use in a DN value
|
215
|
+
def self.escape(string)
|
216
|
+
string.gsub(ESCAPE_RE) { |char| "\\" + ESCAPES[char] }
|
217
|
+
end
|
218
|
+
|
219
|
+
##
|
220
|
+
# Proxy all other requests to the string object, because a DN is mainly
|
221
|
+
# used within the library as a string
|
222
|
+
def method_missing(method, *args, &block)
|
223
|
+
@dn.send(method, *args, &block)
|
224
|
+
end
|
225
|
+
end
|
@@ -0,0 +1,185 @@
|
|
1
|
+
# -*- ruby encoding: utf-8 -*-
|
2
|
+
##
|
3
|
+
# Objects of this class represent individual entries in an LDAP directory.
|
4
|
+
# User code generally does not instantiate this class. Net::LDAP#search
|
5
|
+
# provides objects of this class to user code, either as block parameters or
|
6
|
+
# as return values.
|
7
|
+
#
|
8
|
+
# In LDAP-land, an "entry" is a collection of attributes that are uniquely
|
9
|
+
# and globally identified by a DN ("Distinguished Name"). Attributes are
|
10
|
+
# identified by short, descriptive words or phrases. Although a directory is
|
11
|
+
# free to implement any attribute name, most of them follow rigorous
|
12
|
+
# standards so that the range of commonly-encountered attribute names is not
|
13
|
+
# large.
|
14
|
+
#
|
15
|
+
# An attribute name is case-insensitive. Most directories also restrict the
|
16
|
+
# range of characters allowed in attribute names. To simplify handling
|
17
|
+
# attribute names, Net::LDAP::Entry internally converts them to a standard
|
18
|
+
# format. Therefore, the methods which take attribute names can take Strings
|
19
|
+
# or Symbols, and work correctly regardless of case or capitalization.
|
20
|
+
#
|
21
|
+
# An attribute consists of zero or more data items called <i>values.</i> An
|
22
|
+
# entry is the combination of a unique DN, a set of attribute names, and a
|
23
|
+
# (possibly-empty) array of values for each attribute.
|
24
|
+
#
|
25
|
+
# Class Net::LDAP::Entry provides convenience methods for dealing with LDAP
|
26
|
+
# entries. In addition to the methods documented below, you may access
|
27
|
+
# individual attributes of an entry simply by giving the attribute name as
|
28
|
+
# the name of a method call. For example:
|
29
|
+
#
|
30
|
+
# ldap.search( ... ) do |entry|
|
31
|
+
# puts "Common name: #{entry.cn}"
|
32
|
+
# puts "Email addresses:"
|
33
|
+
# entry.mail.each {|ma| puts ma}
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# If you use this technique to access an attribute that is not present in a
|
37
|
+
# particular Entry object, a NoMethodError exception will be raised.
|
38
|
+
#
|
39
|
+
#--
|
40
|
+
# Ugly problem to fix someday: We key off the internal hash with a canonical
|
41
|
+
# form of the attribute name: convert to a string, downcase, then take the
|
42
|
+
# symbol. Unfortunately we do this in at least three places. Should do it in
|
43
|
+
# ONE place.
|
44
|
+
class Net::LDAP::Entry
|
45
|
+
##
|
46
|
+
# This constructor is not generally called by user code.
|
47
|
+
def initialize(dn = nil) #:nodoc:
|
48
|
+
@myhash = {}
|
49
|
+
@myhash[:dn] = [dn]
|
50
|
+
end
|
51
|
+
|
52
|
+
##
|
53
|
+
# Use the LDIF format for Marshal serialization.
|
54
|
+
def _dump(depth) #:nodoc:
|
55
|
+
to_ldif
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# Use the LDIF format for Marshal serialization.
|
60
|
+
def self._load(entry) #:nodoc:
|
61
|
+
from_single_ldif_string(entry)
|
62
|
+
end
|
63
|
+
|
64
|
+
class << self
|
65
|
+
##
|
66
|
+
# Converts a single LDIF entry string into an Entry object. Useful for
|
67
|
+
# Marshal serialization. If a string with multiple LDIF entries is
|
68
|
+
# provided, an exception will be raised.
|
69
|
+
def from_single_ldif_string(ldif)
|
70
|
+
ds = Net::LDAP::Dataset.read_ldif(::StringIO.new(ldif))
|
71
|
+
|
72
|
+
return nil if ds.empty?
|
73
|
+
|
74
|
+
raise Net::LDAP::LdapError, "Too many LDIF entries" unless ds.size == 1
|
75
|
+
|
76
|
+
entry = ds.to_entries.first
|
77
|
+
|
78
|
+
return nil if entry.dn.nil?
|
79
|
+
entry
|
80
|
+
end
|
81
|
+
|
82
|
+
##
|
83
|
+
# Canonicalizes an LDAP attribute name as a \Symbol. The name is
|
84
|
+
# lowercased and, if present, a trailing equals sign is removed.
|
85
|
+
def attribute_name(name)
|
86
|
+
name = name.to_s.downcase
|
87
|
+
name = name[0..-2] if name[-1] == ?=
|
88
|
+
name.to_sym
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
##
|
93
|
+
# Sets or replaces the array of values for the provided attribute. The
|
94
|
+
# attribute name is canonicalized prior to assignment.
|
95
|
+
#
|
96
|
+
# When an attribute is set using this, that attribute is now made
|
97
|
+
# accessible through methods as well.
|
98
|
+
#
|
99
|
+
# entry = Net::LDAP::Entry.new("dc=com")
|
100
|
+
# entry.foo # => NoMethodError
|
101
|
+
# entry["foo"] = 12345 # => [12345]
|
102
|
+
# entry.foo # => [12345]
|
103
|
+
def []=(name, value)
|
104
|
+
@myhash[self.class.attribute_name(name)] = Kernel::Array(value)
|
105
|
+
end
|
106
|
+
|
107
|
+
##
|
108
|
+
# Reads the array of values for the provided attribute. The attribute name
|
109
|
+
# is canonicalized prior to reading. Returns an empty array if the
|
110
|
+
# attribute does not exist.
|
111
|
+
def [](name)
|
112
|
+
name = self.class.attribute_name(name)
|
113
|
+
@myhash[name] || []
|
114
|
+
end
|
115
|
+
|
116
|
+
##
|
117
|
+
# Returns the first distinguished name (dn) of the Entry as a \String.
|
118
|
+
def dn
|
119
|
+
self[:dn].first.to_s
|
120
|
+
end
|
121
|
+
|
122
|
+
##
|
123
|
+
# Returns an array of the attribute names present in the Entry.
|
124
|
+
def attribute_names
|
125
|
+
@myhash.keys
|
126
|
+
end
|
127
|
+
|
128
|
+
##
|
129
|
+
# Accesses each of the attributes present in the Entry.
|
130
|
+
#
|
131
|
+
# Calls a user-supplied block with each attribute in turn, passing two
|
132
|
+
# arguments to the block: a Symbol giving the name of the attribute, and a
|
133
|
+
# (possibly empty) \Array of data values.
|
134
|
+
def each # :yields: attribute-name, data-values-array
|
135
|
+
if block_given?
|
136
|
+
attribute_names.each {|a|
|
137
|
+
attr_name,values = a,self[a]
|
138
|
+
yield attr_name, values
|
139
|
+
}
|
140
|
+
end
|
141
|
+
end
|
142
|
+
alias_method :each_attribute, :each
|
143
|
+
|
144
|
+
##
|
145
|
+
# Converts the Entry to an LDIF-formatted String
|
146
|
+
def to_ldif
|
147
|
+
Net::LDAP::Dataset.from_entry(self).to_ldif_string
|
148
|
+
end
|
149
|
+
|
150
|
+
def respond_to?(sym) #:nodoc:
|
151
|
+
return true if valid_attribute?(self.class.attribute_name(sym))
|
152
|
+
return super
|
153
|
+
end
|
154
|
+
|
155
|
+
def method_missing(sym, *args, &block) #:nodoc:
|
156
|
+
name = self.class.attribute_name(sym)
|
157
|
+
|
158
|
+
if valid_attribute?(name )
|
159
|
+
if setter?(sym) && args.size == 1
|
160
|
+
value = args.first
|
161
|
+
value = Array(value)
|
162
|
+
self[name]= value
|
163
|
+
return value
|
164
|
+
elsif args.empty?
|
165
|
+
return self[name]
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
super
|
170
|
+
end
|
171
|
+
|
172
|
+
# Given a valid attribute symbol, returns true.
|
173
|
+
def valid_attribute?(attr_name)
|
174
|
+
attribute_names.include?(attr_name)
|
175
|
+
end
|
176
|
+
private :valid_attribute?
|
177
|
+
|
178
|
+
# Returns true if the symbol ends with an equal sign.
|
179
|
+
def setter?(sym)
|
180
|
+
sym.to_s[-1] == ?=
|
181
|
+
end
|
182
|
+
private :setter?
|
183
|
+
end # class Entry
|
184
|
+
|
185
|
+
require 'net/ldap/dataset' unless defined? Net::LDAP::Dataset
|