net-ldap 0.1.0 → 0.1.1
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.
Potentially problematic release.
This version of net-ldap might be problematic. Click here for more details.
- data/History.txt +4 -1
- data/Rakefile +0 -4
- data/lib/net/ldap.rb +7 -4
- data/lib/net/ldap/core_ext/bignum.rb +3 -3
- data/lib/net/ldap/core_ext/fixnum.rb +19 -9
- data/lib/net/ldap/entry.rb +97 -91
- data/spec/integration/ssl_ber_spec.rb +0 -3
- data/spec/spec_helper.rb +2 -0
- metadata +3 -3
data/History.txt
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
-
=== Net::LDAP 0.1.
|
1
|
+
=== Net::LDAP 0.1.1 / 2010-03-18
|
2
|
+
* Fixing a critical problem with sockets.
|
3
|
+
|
4
|
+
=== Net::LDAP 0.1.0 / 2010-03-17
|
2
5
|
* Small fixes throughout, more to come.
|
3
6
|
* Ruby 1.9 support added.
|
4
7
|
* Ruby 1.8.6 and below support removed. If we can figure out a compatible way
|
data/Rakefile
CHANGED
@@ -1,14 +1,10 @@
|
|
1
1
|
require "rubygems"
|
2
|
-
require 'hanna/rdoctask'
|
3
2
|
require 'hoe'
|
4
3
|
|
5
4
|
$LOAD_PATH.unshift('lib')
|
6
5
|
|
7
6
|
require 'net/ldap'
|
8
7
|
|
9
|
-
require "rake/gempackagetask"
|
10
|
-
require "rake/rdoctask"
|
11
|
-
|
12
8
|
PKG_NAME = 'net-ldap'
|
13
9
|
PKG_VERSION = Net::LDAP::VERSION
|
14
10
|
PKG_DIST = "#{PKG_NAME}-#{PKG_VERSION}"
|
data/lib/net/ldap.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'openssl'
|
2
2
|
require 'ostruct'
|
3
|
+
require 'socket'
|
3
4
|
|
4
5
|
require 'net/ber'
|
5
6
|
require 'net/ldap/pdu'
|
@@ -232,9 +233,9 @@ module Net
|
|
232
233
|
# to the server and then keeps it open while it executes a user-supplied block. Net::LDAP#open
|
233
234
|
# closes the connection on completion of the block.
|
234
235
|
class LDAP
|
235
|
-
|
236
|
+
VERSION = "0.1.1"
|
236
237
|
|
237
|
-
|
238
|
+
class LdapError < StandardError; end
|
238
239
|
|
239
240
|
SearchScope_BaseObject = 0
|
240
241
|
SearchScope_SingleLevel = 1
|
@@ -1120,8 +1121,10 @@ module Net
|
|
1120
1121
|
def initialize server
|
1121
1122
|
begin
|
1122
1123
|
@conn = TCPSocket.new( server[:host], server[:port] )
|
1123
|
-
rescue
|
1124
|
-
raise LdapError
|
1124
|
+
rescue SocketError
|
1125
|
+
raise LdapError, "No such address or other socket error."
|
1126
|
+
rescue Errno::ECONNREFUSED
|
1127
|
+
raise LdapError, "Server #{server[:host]} refused connection on port #{server[:port]}."
|
1125
1128
|
end
|
1126
1129
|
|
1127
1130
|
if server[:encryption]
|
@@ -4,9 +4,9 @@ module Net
|
|
4
4
|
module Bignum
|
5
5
|
|
6
6
|
def to_ber
|
7
|
-
# NOTE: Array#pack's 'w' is a BER _compressed_ integer. We need
|
8
|
-
# BER integers, so we're not using that.
|
9
|
-
#
|
7
|
+
# NOTE: Array#pack's 'w' is a BER _compressed_ integer. We need
|
8
|
+
# uncompressed BER integers, so we're not using that. See also:
|
9
|
+
# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/228864
|
10
10
|
result = []
|
11
11
|
|
12
12
|
n = self
|
@@ -36,23 +36,33 @@ module Net
|
|
36
36
|
end
|
37
37
|
|
38
38
|
#--
|
39
|
-
# Called internally to BER-encode the length and content bytes of a
|
40
|
-
# The caller will prepend the tag byte.
|
39
|
+
# Called internally to BER-encode the length and content bytes of a
|
40
|
+
# Fixnum. The caller will prepend the tag byte.
|
41
|
+
#
|
41
42
|
MAX_SIZE = 0.size
|
42
43
|
def to_ber_internal
|
44
|
+
# CAUTION: Bit twiddling ahead. You might want to shield your eyes
|
45
|
+
# or something.
|
46
|
+
|
47
|
+
# Looks for the first byte in the fixnum that is not all zeroes. It
|
48
|
+
# does this by masking one byte after another, checking the result
|
49
|
+
# for bits that are left on.
|
43
50
|
size = MAX_SIZE
|
44
51
|
while size>1
|
45
|
-
|
46
|
-
|
52
|
+
break if (self & (0xff << (size-1)*8)) > 0
|
53
|
+
size -= 1
|
47
54
|
end
|
48
|
-
|
55
|
+
|
56
|
+
# Store the size of the fixnum in the result
|
49
57
|
result = [size]
|
50
58
|
|
59
|
+
# Appends bytes to result, starting with higher orders first.
|
60
|
+
# Extraction of bytes is done by right shifting the original fixnum
|
61
|
+
# by an amount and then masking that with 0xff.
|
51
62
|
while size>0
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
size -= 1
|
63
|
+
# right shift size-1 bytes, mask with 0xff
|
64
|
+
result << ((self >> ((size-1)*8)) & 0xff)
|
65
|
+
size -= 1
|
56
66
|
end
|
57
67
|
|
58
68
|
result.pack('C*')
|
data/lib/net/ldap/entry.rb
CHANGED
@@ -27,60 +27,53 @@ module Net
|
|
27
27
|
class LDAP
|
28
28
|
|
29
29
|
|
30
|
-
# Objects of this class represent individual entries in an LDAP
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
30
|
+
# Objects of this class represent individual entries in an LDAP directory.
|
31
|
+
# User code generally does not instantiate this class. Net::LDAP#search
|
32
|
+
# provides objects of this class to user code, either as block parameters or
|
33
|
+
# as return values.
|
34
34
|
#
|
35
|
-
# In LDAP-land, an "entry" is a collection of attributes that are
|
36
|
-
#
|
37
|
-
#
|
38
|
-
# Although a directory is
|
35
|
+
# In LDAP-land, an "entry" is a collection of attributes that are uniquely
|
36
|
+
# and globally identified by a DN ("Distinguished Name"). Attributes are
|
37
|
+
# identified by short, descriptive words or phrases. Although a directory is
|
39
38
|
# free to implement any attribute name, most of them follow rigorous
|
40
|
-
# standards so that the range of commonly-encountered attribute
|
41
|
-
#
|
39
|
+
# standards so that the range of commonly-encountered attribute names is not
|
40
|
+
# large.
|
42
41
|
#
|
43
|
-
# An attribute name is case-insensitive. Most directories also
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
# and work correctly regardless of case or capitalization.
|
42
|
+
# An attribute name is case-insensitive. Most directories also restrict the
|
43
|
+
# range of characters allowed in attribute names. To simplify handling
|
44
|
+
# attribute names, Net::LDAP::Entry internally converts them to a standard
|
45
|
+
# format. Therefore, the methods which take attribute names can take Strings
|
46
|
+
# or Symbols, and work correctly regardless of case or capitalization.
|
49
47
|
#
|
50
|
-
# An attribute consists of zero or more data items called
|
51
|
-
#
|
52
|
-
#
|
48
|
+
# An attribute consists of zero or more data items called <i>values.</i> An
|
49
|
+
# entry is the combination of a unique DN, a set of attribute names, and a
|
50
|
+
# (possibly-empty) array of values for each attribute.
|
53
51
|
#
|
54
|
-
# Class Net::LDAP::Entry provides convenience methods for dealing
|
55
|
-
#
|
56
|
-
#
|
57
|
-
# attributes of an entry simply by giving the attribute name as
|
52
|
+
# Class Net::LDAP::Entry provides convenience methods for dealing with LDAP
|
53
|
+
# entries. In addition to the methods documented below, you may access
|
54
|
+
# individual attributes of an entry simply by giving the attribute name as
|
58
55
|
# the name of a method call. For example:
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
56
|
+
#
|
57
|
+
# ldap.search( ... ) do |entry|
|
58
|
+
# puts "Common name: #{entry.cn}"
|
59
|
+
# puts "Email addresses:"
|
60
|
+
# entry.mail.each {|ma| puts ma}
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# If you use this technique to access an attribute that is not present in a
|
64
|
+
# particular Entry object, a NoMethodError exception will be raised.
|
66
65
|
#
|
67
66
|
#--
|
68
|
-
# Ugly problem to fix someday: We key off the internal hash with
|
69
|
-
#
|
70
|
-
#
|
71
|
-
#
|
67
|
+
# Ugly problem to fix someday: We key off the internal hash with a canonical
|
68
|
+
# form of the attribute name: convert to a string, downcase, then take the
|
69
|
+
# symbol. Unfortunately we do this in at least three places. Should do it in
|
70
|
+
# ONE place.
|
71
|
+
#
|
72
72
|
class Entry
|
73
|
-
|
74
|
-
|
75
73
|
# This constructor is not generally called by user code.
|
76
|
-
|
77
|
-
# Originally, myhash took a block so we wouldn't have to
|
78
|
-
# make sure its elements returned empty arrays when necessary.
|
79
|
-
# Got rid of that to enable marshalling of Entry objects,
|
80
|
-
# but that doesn't work anyway, because Entry objects have
|
81
|
-
# singleton methods. So we define a custom dump and load.
|
74
|
+
#
|
82
75
|
def initialize dn = nil # :nodoc:
|
83
|
-
@myhash = {}
|
76
|
+
@myhash = {}
|
84
77
|
@myhash[:dn] = [dn]
|
85
78
|
end
|
86
79
|
|
@@ -97,20 +90,18 @@ class LDAP
|
|
97
90
|
#--
|
98
91
|
# Discovered bug, 26Aug06: I noticed that we're not converting the
|
99
92
|
# incoming value to an array if it isn't already one.
|
100
|
-
def []=
|
101
|
-
sym = name
|
93
|
+
def []=(name, value) # :nodoc:
|
94
|
+
sym = attribute_name(name)
|
102
95
|
value = [value] unless value.is_a?(Array)
|
103
96
|
@myhash[sym] = value
|
104
97
|
end
|
105
98
|
|
106
|
-
|
107
99
|
#--
|
108
|
-
# We have to deal with this one as we do with []=
|
109
|
-
#
|
110
|
-
# in formulations like entry["CN"] << cn.
|
100
|
+
# We have to deal with this one as we do with []= because this one and not
|
101
|
+
# the other one gets called in formulations like entry["CN"] << cn.
|
111
102
|
#
|
112
|
-
def []
|
113
|
-
name = name
|
103
|
+
def [](name) # :nodoc:
|
104
|
+
name = attribute_name(name) unless name.is_a?(Symbol)
|
114
105
|
@myhash[name] || []
|
115
106
|
end
|
116
107
|
|
@@ -141,8 +132,6 @@ class LDAP
|
|
141
132
|
|
142
133
|
alias_method :each_attribute, :each
|
143
134
|
|
144
|
-
|
145
|
-
|
146
135
|
# Converts the Entry to a String, representing the
|
147
136
|
# Entry's attributes in LDIF format.
|
148
137
|
#--
|
@@ -168,24 +157,15 @@ class LDAP
|
|
168
157
|
|
169
158
|
#--
|
170
159
|
# TODO, doesn't support broken lines.
|
171
|
-
# It generates a SINGLE Entry object from an incoming LDIF stream
|
172
|
-
#
|
173
|
-
#
|
160
|
+
# It generates a SINGLE Entry object from an incoming LDIF stream which is
|
161
|
+
# of course useless for big LDIF streams that encode many objects.
|
162
|
+
#
|
174
163
|
# DO NOT DOCUMENT THIS METHOD UNTIL THESE RESTRICTIONS ARE LIFTED.
|
175
|
-
# As it is, it's useful for unmarshalling objects that we create,
|
176
|
-
# but not for reading arbitrary LDIF files.
|
177
|
-
# Eventually, we should have a class method that parses large LDIF
|
178
|
-
# streams into individual LDIF blocks (delimited by blank lines)
|
179
|
-
# and passes them here.
|
180
164
|
#
|
181
|
-
#
|
182
|
-
#
|
183
|
-
#
|
184
|
-
#
|
185
|
-
# without a DN attribute so it adds one: nil. The workaround here is
|
186
|
-
# to wipe out the nil DN after creating the Entry object, and trust the
|
187
|
-
# LDIF string to fill it in. If it doesn't we return a nil at the end.
|
188
|
-
# (30Sep06, FCianfrocca)
|
165
|
+
# As it is, it's useful for unmarshalling objects that we create, but not
|
166
|
+
# for reading arbitrary LDIF files. Eventually, we should have a class
|
167
|
+
# method that parses large LDIF streams into individual LDIF blocks
|
168
|
+
# (delimited by blank lines) and passes them here.
|
189
169
|
#
|
190
170
|
class << self
|
191
171
|
def from_single_ldif_string ldif
|
@@ -204,35 +184,42 @@ class LDAP
|
|
204
184
|
entry.dn ? entry : nil
|
205
185
|
end
|
206
186
|
end
|
187
|
+
|
188
|
+
#--
|
189
|
+
# Part of the support for getter and setter style access to attributes.
|
190
|
+
#
|
191
|
+
def respond_to?(sym)
|
192
|
+
name = attribute_name(sym)
|
193
|
+
return true if valid_attribute?(name)
|
194
|
+
return super
|
195
|
+
end
|
207
196
|
|
208
197
|
#--
|
209
|
-
#
|
210
|
-
#
|
211
|
-
# comes to us as a symbol, so let's save a little time
|
212
|
-
# and not bother with the to_s.downcase two-step.
|
213
|
-
# Of course that means that a method name like mAIL
|
214
|
-
# won't work, but we shouldn't be encouraging that
|
215
|
-
# kind of bad behavior in the first place.
|
216
|
-
# Maybe we should thow something if the caller sends
|
217
|
-
# arguments or a block...
|
198
|
+
# Supports getter and setter style access for all the attributes that this
|
199
|
+
# entry holds.
|
218
200
|
#
|
219
|
-
def method_missing *args, &block # :nodoc:
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
201
|
+
def method_missing sym, *args, &block # :nodoc:
|
202
|
+
name = attribute_name(sym)
|
203
|
+
|
204
|
+
if valid_attribute? name
|
205
|
+
if setter?(sym) && args.size == 1
|
206
|
+
value = args.first
|
207
|
+
value = [value] unless value.instance_of?(Array)
|
208
|
+
self[name]= value
|
209
|
+
|
210
|
+
return value
|
211
|
+
elsif args.empty?
|
212
|
+
return self[name]
|
213
|
+
end
|
230
214
|
end
|
215
|
+
|
216
|
+
super
|
231
217
|
end
|
232
218
|
|
233
219
|
def write
|
234
220
|
end
|
235
221
|
|
222
|
+
private
|
236
223
|
|
237
224
|
#--
|
238
225
|
# Internal convenience method. It seems like the standard
|
@@ -251,8 +238,27 @@ class LDAP
|
|
251
238
|
end
|
252
239
|
false
|
253
240
|
end
|
254
|
-
|
255
|
-
|
241
|
+
|
242
|
+
# Returns the symbol that can be used to access the attribute that
|
243
|
+
# sym_or_str designates.
|
244
|
+
#
|
245
|
+
def attribute_name(sym_or_str)
|
246
|
+
str = sym_or_str.to_s.downcase
|
247
|
+
|
248
|
+
# Does str match 'something='? Still only returns :something
|
249
|
+
return str[0...-1].to_sym if str.size>1 && str[-1] == ?=
|
250
|
+
return str.to_sym
|
251
|
+
end
|
252
|
+
|
253
|
+
# Given a valid attribute symbol, returns true.
|
254
|
+
#
|
255
|
+
def valid_attribute?(attr_name)
|
256
|
+
attribute_names.include?(attr_name)
|
257
|
+
end
|
258
|
+
|
259
|
+
def setter?(sym)
|
260
|
+
sym.to_s[-1] == ?=
|
261
|
+
end
|
256
262
|
end # class Entry
|
257
263
|
|
258
264
|
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
8
|
+
- 1
|
9
|
+
version: 0.1.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Francis Cianfrocca
|
@@ -18,7 +18,7 @@ autorequire:
|
|
18
18
|
bindir: bin
|
19
19
|
cert_chain: []
|
20
20
|
|
21
|
-
date: 2010-03-
|
21
|
+
date: 2010-03-18 00:00:00 -04:00
|
22
22
|
default_executable:
|
23
23
|
dependencies:
|
24
24
|
- !ruby/object:Gem::Dependency
|