net-ldap 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
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
|