scashin133-net-ldap 0.1.2
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/COPYING +272 -0
- data/Hacking.rdoc +16 -0
- data/History.txt +137 -0
- data/LICENSE +56 -0
- data/Manifest.txt +42 -0
- data/README.txt +70 -0
- data/Rakefile +124 -0
- data/lib/net/ber/ber_parser.rb +168 -0
- data/lib/net/ber/core_ext/array.rb +79 -0
- data/lib/net/ber/core_ext/bignum.rb +19 -0
- data/lib/net/ber/core_ext/false_class.rb +7 -0
- data/lib/net/ber/core_ext/fixnum.rb +63 -0
- data/lib/net/ber/core_ext/string.rb +45 -0
- data/lib/net/ber/core_ext/true_class.rb +9 -0
- data/lib/net/ber/core_ext.rb +72 -0
- data/lib/net/ber.rb +339 -0
- data/lib/net/ldap/dataset.rb +174 -0
- data/lib/net/ldap/entry.rb +208 -0
- data/lib/net/ldap/filter.rb +720 -0
- data/lib/net/ldap/password.rb +52 -0
- data/lib/net/ldap/pdu.rb +278 -0
- data/lib/net/ldap.rb +1536 -0
- data/lib/net/ldif.rb +34 -0
- data/lib/net/snmp.rb +295 -0
- data/lib/net-ldap.rb +1 -0
- data/spec/integration/ssl_ber_spec.rb +33 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/unit/ber/ber_spec.rb +93 -0
- data/spec/unit/ber/core_ext/string_spec.rb +51 -0
- data/spec/unit/ldap/entry_spec.rb +51 -0
- data/spec/unit/ldap/filter_spec.rb +48 -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 +115 -0
- data/test/test_ldif.rb +68 -0
- data/test/test_password.rb +17 -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 +218 -0
data/lib/net/ber.rb
ADDED
@@ -0,0 +1,339 @@
|
|
1
|
+
# NET::BER
|
2
|
+
# Mixes ASN.1/BER convenience methods into several standard classes. Also
|
3
|
+
# provides BER parsing functionality.
|
4
|
+
#
|
5
|
+
#--
|
6
|
+
# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved.
|
7
|
+
#
|
8
|
+
# Gmail: garbagecat10
|
9
|
+
#
|
10
|
+
# This program is free software; you can redistribute it and/or modify it
|
11
|
+
# under the terms of the GNU General Public License as published by the Free
|
12
|
+
# Software Foundation; either version 2 of the License, or (at your option)
|
13
|
+
# any later version.
|
14
|
+
#
|
15
|
+
# This program is distributed in the hope that it will be useful, but
|
16
|
+
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
17
|
+
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
18
|
+
# for more details.
|
19
|
+
#
|
20
|
+
# You should have received a copy of the GNU General Public License along
|
21
|
+
# with this program; if not, write to the Free Software Foundation, Inc., 51
|
22
|
+
# Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
23
|
+
#++
|
24
|
+
|
25
|
+
module Net
|
26
|
+
##
|
27
|
+
# == Basic Encoding Rules (BER) Support Module
|
28
|
+
#
|
29
|
+
# Much of the text below is cribbed from Wikipedia:
|
30
|
+
# http://en.wikipedia.org/wiki/Basic_Encoding_Rules
|
31
|
+
#
|
32
|
+
# The ITU Specification is also worthwhile reading:
|
33
|
+
# http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
|
34
|
+
#
|
35
|
+
# The Basic Encoding Rules were the original rules laid out by the ASN.1
|
36
|
+
# standard for encoding abstract information into a concrete data stream.
|
37
|
+
# The rules, collectively referred to as a transfer syntax in ASN.1
|
38
|
+
# parlance, specify the exact octet sequences which are used to encode a
|
39
|
+
# given data item. The syntax defines such elements as: the
|
40
|
+
# representations for basic data types, the structure of length
|
41
|
+
# information, and the means for defining complex or compound types based
|
42
|
+
# on more primitive types. The BER syntax, along with two subsets of BER
|
43
|
+
# (the Canonical Encoding Rules and the Distinguished Encoding Rules), are
|
44
|
+
# defined by the ITU-T's X.690 standards document, which is part of the
|
45
|
+
# ASN.1 document series.
|
46
|
+
#
|
47
|
+
# == Encoding
|
48
|
+
# The BER format specifies a self-describing and self-delimiting format
|
49
|
+
# for encoding ASN.1 data structures. Each data element is encoded as a
|
50
|
+
# type identifier, a length description, the actual data elements, and
|
51
|
+
# where necessary, an end-of-content marker. This format allows a receiver
|
52
|
+
# to decode the ASN.1 information from an incomplete stream, without
|
53
|
+
# requiring any pre-knowledge of the size, content, or semantic meaning of
|
54
|
+
# the data.
|
55
|
+
#
|
56
|
+
# <Type | Length | Value [| End-of-Content]>
|
57
|
+
#
|
58
|
+
# == Protocol Data Units (PDU)
|
59
|
+
# Protocols are defined with schema represented in BER, such that a PDU
|
60
|
+
# consists of cascaded type-length-value encodings.
|
61
|
+
#
|
62
|
+
# === Type Tags
|
63
|
+
# BER type tags are represented as single octets (bytes). The lower five
|
64
|
+
# bits of the octet are tag identifier numbers and the upper three bits of
|
65
|
+
# the octet are used to distinguish the type as native to ASN.1,
|
66
|
+
# application-specific, context-specific, or private. See
|
67
|
+
# Net::BER::TAG_CLASS and Net::BER::ENCODING_TYPE for more information.
|
68
|
+
#
|
69
|
+
# If Class is set to Universal (0b00______), the value is of a type native
|
70
|
+
# to ASN.1 (e.g. INTEGER). The Application class (0b01______) is only
|
71
|
+
# valid for one specific application. Context_specific (0b10______)
|
72
|
+
# depends on the context and private (0b11_______) can be defined in
|
73
|
+
# private specifications
|
74
|
+
#
|
75
|
+
# If the primitive/constructed bit is zero (0b__0_____), it specifies that
|
76
|
+
# the value is primitive like an INTEGER. If it is one (0b__1_____), the
|
77
|
+
# value is a constructed value that contains type-length-value encoded
|
78
|
+
# types like a SET or a SEQUENCE.
|
79
|
+
#
|
80
|
+
# === Defined Universal (ASN.1 Native) Types
|
81
|
+
# There are a number of pre-defined universal (native) types.
|
82
|
+
#
|
83
|
+
# <table>
|
84
|
+
# <tr><th>Name</th><th>Primitive<br />Constructed</th><th>Number</th></tr>
|
85
|
+
# <tr><th>EOC (End-of-Content)</th><th>P</th><td>0: 0 (0x0, 0b00000000)</td></tr>
|
86
|
+
# <tr><th>BOOLEAN</th><th>P</th><td>1: 1 (0x01, 0b00000001)</td></tr>
|
87
|
+
# <tr><th>INTEGER</th><th>P</th><td>2: 2 (0x02, 0b00000010)</td></tr>
|
88
|
+
# <tr><th>BIT STRING</th><th>P</th><td>3: 3 (0x03, 0b00000011)</td></tr>
|
89
|
+
# <tr><th>BIT STRING</th><th>C</th><td>3: 35 (0x23, 0b00100011)</td></tr>
|
90
|
+
# <tr><th>OCTET STRING</th><th>P</th><td>4: 4 (0x04, 0b00000100)</td></tr>
|
91
|
+
# <tr><th>OCTET STRING</th><th>C</th><td>4: 36 (0x24, 0b00100100)</td></tr>
|
92
|
+
# <tr><th>NULL</th><th>P</th><td>5: 5 (0x05, 0b00000101)</td></tr>
|
93
|
+
# <tr><th>OBJECT IDENTIFIER</th><th>P</th><td>6: 6 (0x06, 0b00000110)</td></tr>
|
94
|
+
# <tr><th>Object Descriptor</th><th>P</th><td>7: 7 (0x07, 0b00000111)</td></tr>
|
95
|
+
# <tr><th>EXTERNAL</th><th>C</th><td>8: 40 (0x28, 0b00101000)</td></tr>
|
96
|
+
# <tr><th>REAL (float)</th><th>P</th><td>9: 9 (0x09, 0b00001001)</td></tr>
|
97
|
+
# <tr><th>ENUMERATED</th><th>P</th><td>10: 10 (0x0a, 0b00001010)</td></tr>
|
98
|
+
# <tr><th>EMBEDDED PDV</th><th>C</th><td>11: 43 (0x2b, 0b00101011)</td></tr>
|
99
|
+
# <tr><th>UTF8String</th><th>P</th><td>12: 12 (0x0c, 0b00001100)</td></tr>
|
100
|
+
# <tr><th>UTF8String</th><th>C</th><td>12: 44 (0x2c, 0b00101100)</td></tr>
|
101
|
+
# <tr><th>RELATIVE-OID</th><th>P</th><td>13: 13 (0x0d, 0b00001101)</td></tr>
|
102
|
+
# <tr><th>SEQUENCE and SEQUENCE OF</th><th>C</th><td>16: 48 (0x30, 0b00110000)</td></tr>
|
103
|
+
# <tr><th>SET and SET OF</th><th>C</th><td>17: 49 (0x31, 0b00110001)</td></tr>
|
104
|
+
# <tr><th>NumericString</th><th>P</th><td>18: 18 (0x12, 0b00010010)</td></tr>
|
105
|
+
# <tr><th>NumericString</th><th>C</th><td>18: 50 (0x32, 0b00110010)</td></tr>
|
106
|
+
# <tr><th>PrintableString</th><th>P</th><td>19: 19 (0x13, 0b00010011)</td></tr>
|
107
|
+
# <tr><th>PrintableString</th><th>C</th><td>19: 51 (0x33, 0b00110011)</td></tr>
|
108
|
+
# <tr><th>T61String</th><th>P</th><td>20: 20 (0x14, 0b00010100)</td></tr>
|
109
|
+
# <tr><th>T61String</th><th>C</th><td>20: 52 (0x34, 0b00110100)</td></tr>
|
110
|
+
# <tr><th>VideotexString</th><th>P</th><td>21: 21 (0x15, 0b00010101)</td></tr>
|
111
|
+
# <tr><th>VideotexString</th><th>C</th><td>21: 53 (0x35, 0b00110101)</td></tr>
|
112
|
+
# <tr><th>IA5String</th><th>P</th><td>22: 22 (0x16, 0b00010110)</td></tr>
|
113
|
+
# <tr><th>IA5String</th><th>C</th><td>22: 54 (0x36, 0b00110110)</td></tr>
|
114
|
+
# <tr><th>UTCTime</th><th>P</th><td>23: 23 (0x17, 0b00010111)</td></tr>
|
115
|
+
# <tr><th>UTCTime</th><th>C</th><td>23: 55 (0x37, 0b00110111)</td></tr>
|
116
|
+
# <tr><th>GeneralizedTime</th><th>P</th><td>24: 24 (0x18, 0b00011000)</td></tr>
|
117
|
+
# <tr><th>GeneralizedTime</th><th>C</th><td>24: 56 (0x38, 0b00111000)</td></tr>
|
118
|
+
# <tr><th>GraphicString</th><th>P</th><td>25: 25 (0x19, 0b00011001)</td></tr>
|
119
|
+
# <tr><th>GraphicString</th><th>C</th><td>25: 57 (0x39, 0b00111001)</td></tr>
|
120
|
+
# <tr><th>VisibleString</th><th>P</th><td>26: 26 (0x1a, 0b00011010)</td></tr>
|
121
|
+
# <tr><th>VisibleString</th><th>C</th><td>26: 58 (0x3a, 0b00111010)</td></tr>
|
122
|
+
# <tr><th>GeneralString</th><th>P</th><td>27: 27 (0x1b, 0b00011011)</td></tr>
|
123
|
+
# <tr><th>GeneralString</th><th>C</th><td>27: 59 (0x3b, 0b00111011)</td></tr>
|
124
|
+
# <tr><th>UniversalString</th><th>P</th><td>28: 28 (0x1c, 0b00011100)</td></tr>
|
125
|
+
# <tr><th>UniversalString</th><th>C</th><td>28: 60 (0x3c, 0b00111100)</td></tr>
|
126
|
+
# <tr><th>CHARACTER STRING</th><th>P</th><td>29: 29 (0x1d, 0b00011101)</td></tr>
|
127
|
+
# <tr><th>CHARACTER STRING</th><th>C</th><td>29: 61 (0x3d, 0b00111101)</td></tr>
|
128
|
+
# <tr><th>BMPString</th><th>P</th><td>30: 30 (0x1e, 0b00011110)</td></tr>
|
129
|
+
# <tr><th>BMPString</th><th>C</th><td>30: 62 (0x3e, 0b00111110)</td></tr>
|
130
|
+
# </table>
|
131
|
+
module BER
|
132
|
+
VERSION = '0.1.0'
|
133
|
+
|
134
|
+
##
|
135
|
+
# Used for BER-encoding the length and content bytes of a Fixnum integer
|
136
|
+
# values.
|
137
|
+
MAX_FIXNUM_SIZE = 0.size
|
138
|
+
|
139
|
+
##
|
140
|
+
# BER tag classes are kept in bits seven and eight of the tag type
|
141
|
+
# octet.
|
142
|
+
#
|
143
|
+
# <table>
|
144
|
+
# <tr><th>Bitmask</th><th>Definition</th></tr>
|
145
|
+
# <tr><th><tt>0b00______</tt></th><td>Universal (ASN.1 Native) Types</td></tr>
|
146
|
+
# <tr><th><tt>0b01______</tt></th><td>Application Types</td></tr>
|
147
|
+
# <tr><th><tt>0b10______</tt></th><td>Context-Specific Types</td></tr>
|
148
|
+
# <tr><th><tt>0b11______</tt></th><td>Private Types</td></tr>
|
149
|
+
# </table>
|
150
|
+
TAG_CLASS = {
|
151
|
+
:universal => 0b00000000, # 0
|
152
|
+
:application => 0b01000000, # 64
|
153
|
+
:context_specific => 0b10000000, # 128
|
154
|
+
:private => 0b11000000, # 192
|
155
|
+
}
|
156
|
+
|
157
|
+
##
|
158
|
+
# BER encoding type is kept in bit 6 of the tag type octet.
|
159
|
+
#
|
160
|
+
# <table>
|
161
|
+
# <tr><th>Bitmask</th><th>Definition</th></tr>
|
162
|
+
# <tr><th><tt>0b__0_____</tt></th><td>Primitive</td></tr>
|
163
|
+
# <tr><th><tt>0b__1_____</tt></th><td>Constructed</td></tr>
|
164
|
+
# </table>
|
165
|
+
ENCODING_TYPE = {
|
166
|
+
:primitive => 0b00000000, # 0
|
167
|
+
:constructed => 0b00100000, # 32
|
168
|
+
}
|
169
|
+
|
170
|
+
##
|
171
|
+
# Accepts a hash of hashes describing a BER syntax and converts it into
|
172
|
+
# a byte-keyed object for fast BER conversion lookup. The resulting
|
173
|
+
# "compiled" syntax is used by Net::BER::BERParser.
|
174
|
+
#
|
175
|
+
# This method should be called only by client classes of Net::BER (e.g.,
|
176
|
+
# Net::LDAP and Net::SNMP) and not by clients of those classes.
|
177
|
+
#
|
178
|
+
# The hash-based syntax uses TAG_CLASS keys that contain hashes of
|
179
|
+
# ENCODING_TYPE keys that contain tag numbers with object type markers.
|
180
|
+
#
|
181
|
+
# :<TAG_CLASS> => {
|
182
|
+
# :<ENCODING_TYPE> => {
|
183
|
+
# <number> => <object-type>
|
184
|
+
# },
|
185
|
+
# },
|
186
|
+
#
|
187
|
+
# === Permitted Object Types
|
188
|
+
# <tt>:string</tt>:: A string value, represented as BerIdentifiedString.
|
189
|
+
# <tt>:integer</tt>:: An integer value, represented with Fixnum.
|
190
|
+
# <tt>:oid</tt>:: An Object Identifier value; see X.690 section
|
191
|
+
# 8.19. Currently represented with a standard array,
|
192
|
+
# but may be better represented as a
|
193
|
+
# BerIdentifiedOID object.
|
194
|
+
# <tt>:array</tt>:: A sequence, represented as BerIdentifiedArray.
|
195
|
+
# <tt>:boolean</tt>:: A boolean value, represented as +true+ or +false+.
|
196
|
+
# <tt>:null</tt>:: A null value, represented as BerIdentifiedNull.
|
197
|
+
#
|
198
|
+
# === Example
|
199
|
+
# Net::LDAP defines its ASN.1 BER syntax something like this:
|
200
|
+
#
|
201
|
+
# class Net::LDAP
|
202
|
+
# AsnSyntax = Net::BER.compile_syntax({
|
203
|
+
# :application => {
|
204
|
+
# :primitive => {
|
205
|
+
# 2 => :null,
|
206
|
+
# },
|
207
|
+
# :constructed => {
|
208
|
+
# 0 => :array,
|
209
|
+
# # ...
|
210
|
+
# },
|
211
|
+
# },
|
212
|
+
# :context_specific => {
|
213
|
+
# :primitive => {
|
214
|
+
# 0 => :string,
|
215
|
+
# # ...
|
216
|
+
# },
|
217
|
+
# :constructed => {
|
218
|
+
# 0 => :array,
|
219
|
+
# # ...
|
220
|
+
# },
|
221
|
+
# }
|
222
|
+
# })
|
223
|
+
# end
|
224
|
+
#
|
225
|
+
# NOTE:: For readability and formatting purposes, Net::LDAP and its
|
226
|
+
# siblings actually construct their syntaxes more deliberately,
|
227
|
+
# as shown below. Since a hash is passed in the end in any case,
|
228
|
+
# the format does not matter.
|
229
|
+
#
|
230
|
+
# primitive = { 2 => :null }
|
231
|
+
# constructed = {
|
232
|
+
# 0 => :array,
|
233
|
+
# # ...
|
234
|
+
# }
|
235
|
+
# application = {
|
236
|
+
# :primitive => primitive,
|
237
|
+
# :constructed => constructed
|
238
|
+
# }
|
239
|
+
#
|
240
|
+
# primitive = {
|
241
|
+
# 0 => :string,
|
242
|
+
# # ...
|
243
|
+
# }
|
244
|
+
# constructed = {
|
245
|
+
# 0 => :array,
|
246
|
+
# # ...
|
247
|
+
# }
|
248
|
+
# context_specific = {
|
249
|
+
# :primitive => primitive,
|
250
|
+
# :constructed => constructed
|
251
|
+
# }
|
252
|
+
# AsnSyntax = Net::BER.compile_syntax(:application => application,
|
253
|
+
# :context_specific => context_specific)
|
254
|
+
def self.compile_syntax(syntax)
|
255
|
+
# TODO 20100327 AZ: Should we be allocating an array of 256 values
|
256
|
+
# that will either be +nil+ or an object type symbol, or should we
|
257
|
+
# allocate an empty Hash since unknown values return +nil+ anyway?
|
258
|
+
out = [ nil ] * 256
|
259
|
+
syntax.each do |tag_class_id, encodings|
|
260
|
+
tag_class = TAG_CLASS[tag_class_id]
|
261
|
+
encodings.each do |encoding_id, classes|
|
262
|
+
encoding = ENCODING_TYPE[encoding_id]
|
263
|
+
object_class = tag_class + encoding
|
264
|
+
classes.each do |number, object_type|
|
265
|
+
out[object_class + number] = object_type
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
out
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
class Net::BER::BerError < RuntimeError; end
|
275
|
+
|
276
|
+
##
|
277
|
+
# An Array object with a BER identifier attached.
|
278
|
+
class Net::BER::BerIdentifiedArray < Array
|
279
|
+
attr_accessor :ber_identifier
|
280
|
+
|
281
|
+
def initialize(*args)
|
282
|
+
super
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
##
|
287
|
+
# A BER object identifier.
|
288
|
+
class Net::BER::BerIdentifiedOid
|
289
|
+
attr_accessor :ber_identifier
|
290
|
+
|
291
|
+
def initialize(oid)
|
292
|
+
if oid.is_a?(String)
|
293
|
+
oid = oid.split(/\./).map {|s| s.to_i }
|
294
|
+
end
|
295
|
+
@value = oid
|
296
|
+
end
|
297
|
+
|
298
|
+
def to_ber
|
299
|
+
to_ber_oid
|
300
|
+
end
|
301
|
+
|
302
|
+
def to_ber_oid
|
303
|
+
@value.to_ber_oid
|
304
|
+
end
|
305
|
+
|
306
|
+
def to_s
|
307
|
+
@value.join(".")
|
308
|
+
end
|
309
|
+
|
310
|
+
def to_arr
|
311
|
+
@value.dup
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
##
|
316
|
+
# A String object with a BER identifier attached.
|
317
|
+
class Net::BER::BerIdentifiedString < String
|
318
|
+
attr_accessor :ber_identifier
|
319
|
+
def initialize args
|
320
|
+
super args
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
module Net::BER
|
325
|
+
##
|
326
|
+
# A BER null object.
|
327
|
+
class BerIdentifiedNull
|
328
|
+
attr_accessor :ber_identifier
|
329
|
+
def to_ber
|
330
|
+
"\005\000"
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
##
|
335
|
+
# The default BerIdentifiedNull object.
|
336
|
+
Null = Net::BER::BerIdentifiedNull.new
|
337
|
+
end
|
338
|
+
|
339
|
+
require 'net/ber/core_ext'
|
@@ -0,0 +1,174 @@
|
|
1
|
+
#----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved.
|
4
|
+
#
|
5
|
+
# Gmail: garbagecat10
|
6
|
+
#
|
7
|
+
# This program is free software; you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation; either version 2 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with this program; if not, write to the Free Software
|
19
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
20
|
+
#
|
21
|
+
#---------------------------------------------------------------------------
|
22
|
+
|
23
|
+
##
|
24
|
+
# An LDAP Dataset. Used primarily as an intermediate format for converting
|
25
|
+
# to and from LDIF strings and Net::LDAP::Entry objects.
|
26
|
+
class Net::LDAP::Dataset < Hash
|
27
|
+
##
|
28
|
+
# Dataset object comments.
|
29
|
+
attr_reader :comments
|
30
|
+
|
31
|
+
class << self
|
32
|
+
class ChompedIO #:nodoc:
|
33
|
+
def initialize(io)
|
34
|
+
@io = io
|
35
|
+
end
|
36
|
+
def gets
|
37
|
+
s = @io.gets
|
38
|
+
s.chomp if s
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# Reads an object that returns data line-wise (using #gets) and parses
|
44
|
+
# LDIF data into a Dataset object.
|
45
|
+
def read_ldif(io) #:yields: entry-type, value Used mostly for debugging.
|
46
|
+
ds = Net::LDAP::Dataset.new
|
47
|
+
io = ChompedIO.new(io)
|
48
|
+
|
49
|
+
line = io.gets
|
50
|
+
dn = nil
|
51
|
+
|
52
|
+
while line
|
53
|
+
new_line = io.gets
|
54
|
+
|
55
|
+
if new_line =~ /^[\s]+/
|
56
|
+
line << " " << $'
|
57
|
+
else
|
58
|
+
nextline = new_line
|
59
|
+
|
60
|
+
if line =~ /^#/
|
61
|
+
ds.comments << line
|
62
|
+
yield :comment, line if block_given?
|
63
|
+
elsif line =~ /^dn:[\s]*/i
|
64
|
+
dn = $'
|
65
|
+
ds[dn] = Hash.new { |k,v| k[v] = [] }
|
66
|
+
yield :dn, dn if block_given?
|
67
|
+
elsif line.empty?
|
68
|
+
dn = nil
|
69
|
+
yield :end, nil if block_given?
|
70
|
+
elsif line =~ /^([^:]+):([\:]?)[\s]*/
|
71
|
+
# $1 is the attribute name
|
72
|
+
# $2 is a colon iff the attr-value is base-64 encoded
|
73
|
+
# $' is the attr-value
|
74
|
+
# Avoid the Base64 class because not all Ruby versions have it.
|
75
|
+
attrvalue = ($2 == ":") ? $'.unpack('m').shift : $'
|
76
|
+
ds[dn][$1.downcase.to_sym] << attrvalue
|
77
|
+
yield :attr, [$1.downcase.to_sym, attrvalue] if block_given?
|
78
|
+
end
|
79
|
+
|
80
|
+
line = nextline
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
ds
|
85
|
+
end
|
86
|
+
|
87
|
+
##
|
88
|
+
# Creates a Dataset object from an Entry object. Used mostly to assist
|
89
|
+
# with the conversion of
|
90
|
+
def from_entry(entry)
|
91
|
+
dataset = Net::LDAP::Dataset.new
|
92
|
+
hash = { }
|
93
|
+
entry.each_attribute do |attribute, value|
|
94
|
+
next if attribute == :dn
|
95
|
+
hash[attribute] = value
|
96
|
+
end
|
97
|
+
dataset[entry.dn] = hash
|
98
|
+
dataset
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def initialize(*args, &block) #:nodoc:
|
103
|
+
super
|
104
|
+
@comments = []
|
105
|
+
end
|
106
|
+
|
107
|
+
##
|
108
|
+
# Outputs an LDAP Dataset as an array of strings representing LDIF
|
109
|
+
# entries.
|
110
|
+
def to_ldif
|
111
|
+
ary = []
|
112
|
+
ary += @comments unless @comments.empty?
|
113
|
+
keys.sort.each do |dn|
|
114
|
+
ary << "dn: #{dn}"
|
115
|
+
|
116
|
+
attributes = self[dn].keys.map { |attr| attr.to_s }.sort
|
117
|
+
attributes.each do |attr|
|
118
|
+
self[dn][attr.to_sym].each do |value|
|
119
|
+
if attr == "userpassword" or value_is_binary?(value)
|
120
|
+
value = [value].pack("m").chomp.gsub(/\n/m, "\n ")
|
121
|
+
ary << "#{attr}:: #{value}"
|
122
|
+
else
|
123
|
+
ary << "#{attr}: #{value}"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
ary << ""
|
129
|
+
end
|
130
|
+
block_given? and ary.each { |line| yield line}
|
131
|
+
|
132
|
+
ary
|
133
|
+
end
|
134
|
+
|
135
|
+
##
|
136
|
+
# Outputs an LDAP Dataset as an LDIF string.
|
137
|
+
def to_ldif_string
|
138
|
+
to_ldif.join("\n")
|
139
|
+
end
|
140
|
+
|
141
|
+
##
|
142
|
+
# Convert the parsed LDIF objects to Net::LDAP::Entry objects.
|
143
|
+
def to_entries
|
144
|
+
ary = []
|
145
|
+
keys.each do |dn|
|
146
|
+
entry = Net::LDAP::Entry.new(dn)
|
147
|
+
self[dn].each do |attr, value|
|
148
|
+
entry[attr] = value
|
149
|
+
end
|
150
|
+
ary << entry
|
151
|
+
end
|
152
|
+
ary
|
153
|
+
end
|
154
|
+
|
155
|
+
# This is an internal convenience method to determine if a value requires
|
156
|
+
# base64-encoding before conversion to LDIF output. The standard approach
|
157
|
+
# in most LDAP tools is to check whether the value is a password, or if
|
158
|
+
# the first or last bytes are non-printable. Microsoft Active Directory,
|
159
|
+
# on the other hand, sometimes sends values that are binary in the middle.
|
160
|
+
#
|
161
|
+
# In the worst cases, this could be a nasty performance killer, which is
|
162
|
+
# why we handle the simplest cases first. Ideally, we would also test the
|
163
|
+
# first/last byte, but it's a bit harder to do this in a way that's
|
164
|
+
# compatible with both 1.8.6 and 1.8.7.
|
165
|
+
def value_is_binary?(value)
|
166
|
+
value = value.to_s
|
167
|
+
return true if value[0] == ?: or value[0] == ?<
|
168
|
+
value.each_byte { |byte| return true if (byte < 32) || (byte > 126) }
|
169
|
+
false
|
170
|
+
end
|
171
|
+
private :value_is_binary?
|
172
|
+
end
|
173
|
+
|
174
|
+
require 'net/ldap/entry' unless defined? Net::LDAP::Entry
|