ruby-activeldap 0.5.8 → 0.5.9
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/lib/activeldap.rb +26 -26
- data/lib/activeldap/associations.rb +1 -1
- data/lib/activeldap/base.rb +101 -82
- data/lib/activeldap/configuration.rb +2 -2
- data/lib/activeldap/schema2.rb +4 -3
- metadata +2 -2
data/lib/activeldap.rb
CHANGED
@@ -8,7 +8,7 @@
|
|
8
8
|
# Ruby/ActiveLDAP is a novel way of interacting with LDAP. Most interaction with
|
9
9
|
# LDAP is done using clunky LDIFs, web interfaces, or with painful APIs that
|
10
10
|
# required a thick reference manual nearby. Ruby/ActiveLDAP aims to fix that.
|
11
|
-
# Inspired by ActiveRecord[http://activerecord.rubyonrails.
|
11
|
+
# Inspired by ActiveRecord[http://activerecord.rubyonrails.org], Ruby/ActiveLDAP provides an
|
12
12
|
# object oriented interface to LDAP entries.
|
13
13
|
#
|
14
14
|
# The target audience is system administrators and LDAP users everywhere that
|
@@ -26,8 +26,8 @@
|
|
26
26
|
# against Microsoft's ActiveDirectory, despite what the name implies.)
|
27
27
|
#
|
28
28
|
# Further reading:
|
29
|
-
# * RFC1777[http://www.faqs.
|
30
|
-
# * OpenLDAP[http://www.openldap.
|
29
|
+
# * RFC1777[http://www.faqs.org/rfcs/rfc1777.html] - Lightweight Directory Access Protocol
|
30
|
+
# * OpenLDAP[http://www.openldap.org]
|
31
31
|
#
|
32
32
|
# === So why use Ruby/ActiveLDAP?
|
33
33
|
#
|
@@ -50,18 +50,18 @@
|
|
50
50
|
#
|
51
51
|
# === Requirements
|
52
52
|
#
|
53
|
-
# * Ruby[http://www.ruby-lang.
|
54
|
-
# * Ruby/LDAP[http://ruby-ldap.
|
55
|
-
# * Log4r[http://log4r.
|
56
|
-
# * (Optional) Ruby/LDAP+GSSAPI[http://caliban.
|
57
|
-
# * An LDAP server compatible with Ruby/LDAP: OpenLDAP[http://www.openldap.
|
53
|
+
# * Ruby[http://www.ruby-lang.org] 1.8.x
|
54
|
+
# * Ruby/LDAP[http://ruby-ldap.sourceforge.net]
|
55
|
+
# * Log4r[http://log4r.sourceforge.net]
|
56
|
+
# * (Optional) Ruby/LDAP+GSSAPI[http://caliban.org/files/redhat/RPMS/i386/ruby-ldap-0.8.2-4.i386.rpm]
|
57
|
+
# * An LDAP server compatible with Ruby/LDAP: OpenLDAP[http://www.openldap.org], etc
|
58
58
|
# - Your LDAP server must allow root_dse queries to allow for schema queries
|
59
|
-
# * Examples also require: Ruby/Password[http://raa.ruby-lang.
|
59
|
+
# * Examples also require: Ruby/Password[http://raa.ruby-lang.org/project/ruby-password/]
|
60
60
|
#
|
61
61
|
# === Installation
|
62
62
|
#
|
63
63
|
# Assuming all the requirements are installed, you can install by grabbing the latest tgz file from
|
64
|
-
# the download site[http://projects.
|
64
|
+
# the download site[http://projects.dataspill.org/libraries/ruby/activeldap/download.html].
|
65
65
|
#
|
66
66
|
# The following steps will get the Ruby/ActiveLDAP installed in no time!
|
67
67
|
#
|
@@ -183,23 +183,23 @@
|
|
183
183
|
# As you can see, this method is used for defining how this class maps in to LDAP. Let's say that
|
184
184
|
# my LDAP tree looks something like this:
|
185
185
|
#
|
186
|
-
# * dc=
|
187
|
-
# |- ou=People,dc=
|
188
|
-
# |+ ou=Groups,dc=
|
186
|
+
# * dc=dataspill,dc=org
|
187
|
+
# |- ou=People,dc=dataspill,dc=org
|
188
|
+
# |+ ou=Groups,dc=dataspill,dc=org
|
189
189
|
# \
|
190
|
-
# |- cn=develop,ou=Groups,dc=
|
191
|
-
# |- cn=root,ou=Groups,dc=
|
190
|
+
# |- cn=develop,ou=Groups,dc=dataspill,dc=org
|
191
|
+
# |- cn=root,ou=Groups,dc=dataspill,dc=org
|
192
192
|
# |- ...
|
193
193
|
#
|
194
194
|
# Under ou=People I store user objects, and under ou=Groups, I store group
|
195
195
|
# objects. What |ldap_mapping| has done is mapped the class in to the LDAP tree
|
196
196
|
# abstractly. With the given :dnattr and :prefix, it will only work for entries
|
197
|
-
# under ou=Groups,dc=
|
197
|
+
# under ou=Groups,dc=dataspill,dc=org using the primary attribute 'cn' as the
|
198
198
|
# beginning of the distinguished name.
|
199
199
|
#
|
200
200
|
# Just for clarity, here's how the arguments map out:
|
201
201
|
#
|
202
|
-
# cn=develop,ou=Groups,dc=
|
202
|
+
# cn=develop,ou=Groups,dc=dataspill,dc=org
|
203
203
|
# ^^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
|
204
204
|
# :dnattr | |
|
205
205
|
# :prefix |
|
@@ -233,11 +233,11 @@
|
|
233
233
|
# tying objects together across the LDAP tree. Often, user objects will be
|
234
234
|
# members of, or belong_to, Group objects.
|
235
235
|
#
|
236
|
-
# * dc=
|
237
|
-
# |+ ou=People,dc=
|
236
|
+
# * dc=dataspill,dc=org
|
237
|
+
# |+ ou=People,dc=dataspill,dc=org
|
238
238
|
# \
|
239
|
-
# |- uid=drewry,ou=People,dc=
|
240
|
-
# |- ou=Groups,dc=
|
239
|
+
# |- uid=drewry,ou=People,dc=dataspill,dc=org
|
240
|
+
# |- ou=Groups,dc=dataspill,dc=org
|
241
241
|
#
|
242
242
|
#
|
243
243
|
# In the above tree, one such example would be user 'drewry' who is a part of the
|
@@ -385,7 +385,7 @@
|
|
385
385
|
#
|
386
386
|
# irb> Base.search(:base => 'dc=example,dc=com', :filter => '(uid=roo*)',
|
387
387
|
# :scope => LDAP::LDAP_SCOPE_SUBTREE, :attrs => ['uid', 'cn'])
|
388
|
-
# => [{"dn"=>"uid=root,ou=People,dc=
|
388
|
+
# => [{"dn"=>"uid=root,ou=People,dc=dataspill,dc=org","cn"=>["root"], "uidNumber"=>["0"]}]
|
389
389
|
# You can specify the :filter, :base, :scope, and :attrs, but they all have defaults --
|
390
390
|
# * :filter defaults to objectClass=* - usually this isn't what you want
|
391
391
|
# * :base defaults to the base of the class this is executed from (as set in ldap_mapping)
|
@@ -443,10 +443,10 @@
|
|
443
443
|
# won't need to call Base.connect. Here is a fully parameterized call:
|
444
444
|
#
|
445
445
|
# Base.connect(
|
446
|
-
# :host => 'ldap.
|
446
|
+
# :host => 'ldap.dataspill.org',
|
447
447
|
# :port => 389,
|
448
|
-
# :base => 'dc=
|
449
|
-
# :bind_format => "uid=%s,ou=People,dc=
|
448
|
+
# :base => 'dc=dataspill,dc=org',
|
449
|
+
# :bind_format => "uid=%s,ou=People,dc=dataspill,dc=org",
|
450
450
|
# :logger => log4r_obj,
|
451
451
|
# :user => 'drewry',
|
452
452
|
# :password_block => Proc.new { 'password12345' },
|
@@ -909,7 +909,7 @@ require 'activeldap/schema2'
|
|
909
909
|
|
910
910
|
|
911
911
|
module ActiveLDAP
|
912
|
-
VERSION = "0.5.
|
912
|
+
VERSION = "0.5.9"
|
913
913
|
end
|
914
914
|
|
915
915
|
ActiveLDAP::Base.class_eval do
|
@@ -33,7 +33,7 @@ module ActiveLDAP
|
|
33
33
|
# class which can then be inherited, etc
|
34
34
|
# which describe the mapping to LDAP.
|
35
35
|
klass.class_eval <<-"end_eval"
|
36
|
-
class <<
|
36
|
+
class << self
|
37
37
|
# Return the list of required object classes
|
38
38
|
def required_classes
|
39
39
|
#{classes}
|
data/lib/activeldap/base.rb
CHANGED
@@ -34,7 +34,7 @@ require 'ldap/schema'
|
|
34
34
|
require 'log4r'
|
35
35
|
|
36
36
|
module ActiveLDAP
|
37
|
-
# OO-interface to LDAP assuming pam/nss_ldap-style
|
37
|
+
# OO-interface to LDAP assuming pam/nss_ldap-style organization with Active specifics
|
38
38
|
# Each subclass does a ldapsearch for the matching entry.
|
39
39
|
# If no exact match, raise an error.
|
40
40
|
# If match, change all LDAP attributes in accessor attributes on the object.
|
@@ -167,7 +167,7 @@ module ActiveLDAP
|
|
167
167
|
# +config+ must be a hash that may contain any of the following fields:
|
168
168
|
# :user, :password_block, :logger, :host, :port, :base, :bind_format, :try_sasl, :allow_anonymous
|
169
169
|
# :user specifies the username to bind with.
|
170
|
-
# :bind_format specifies the string to substitute the username into on bind. e.g. uid=%s,ou=People,dc=
|
170
|
+
# :bind_format specifies the string to substitute the username into on bind. e.g. uid=%s,ou=People,dc=dataspill,dc=org. Overrides @@bind_format.
|
171
171
|
# :password_block specifies a Proc object that will yield a String to be used as the password when called.
|
172
172
|
# :logger specifies a preconfigured Log4r::Logger to be used for all logging
|
173
173
|
# :host overrides the configuration.rb @@host setting with the LDAP server hostname
|
@@ -294,7 +294,7 @@ module ActiveLDAP
|
|
294
294
|
rescue RuntimeError => detail
|
295
295
|
#TODO# Check for 'No message' when retrying
|
296
296
|
# The connection may have gone stale. Let's reconnect and retry.
|
297
|
-
if tries >
|
297
|
+
if tries > @@config[:retries]
|
298
298
|
# Do nothing on failure
|
299
299
|
|
300
300
|
end
|
@@ -346,12 +346,12 @@ module ActiveLDAP
|
|
346
346
|
tries = 0
|
347
347
|
begin
|
348
348
|
# Get some attributes
|
349
|
-
@@conn.search(base(), LDAP::
|
349
|
+
@@conn.search(base(), LDAP::LDAP_SCOPE_ONELEVEL, "(#{attr}=#{val})") do |m|
|
350
350
|
# Extract the dnattr value
|
351
351
|
dnval = m.dn.split(/,/)[0].split(/=/)[1]
|
352
352
|
|
353
353
|
if objects
|
354
|
-
return
|
354
|
+
return real_klass.new(m)
|
355
355
|
else
|
356
356
|
return dnval
|
357
357
|
end
|
@@ -359,7 +359,7 @@ module ActiveLDAP
|
|
359
359
|
rescue RuntimeError => detail
|
360
360
|
#todo# check for 'no message' when retrying
|
361
361
|
# the connection may have gone stale. let's reconnect and retry.
|
362
|
-
if tries >
|
362
|
+
if tries > @@config[:retries]
|
363
363
|
# do nothing on failure
|
364
364
|
|
365
365
|
end
|
@@ -394,11 +394,12 @@ module ActiveLDAP
|
|
394
394
|
|
395
395
|
# Allow a single string argument
|
396
396
|
val = config
|
397
|
+
attr = dnattr()
|
397
398
|
objects = false
|
398
399
|
# Or a hash
|
399
400
|
if config.respond_to?"has_key?"
|
400
|
-
attr = config[:attribute] || dnattr()
|
401
401
|
val = config[:value] || '*'
|
402
|
+
attr = config[:attribute] || dnattr()
|
402
403
|
objects = config[:objects]
|
403
404
|
end
|
404
405
|
|
@@ -407,20 +408,23 @@ module ActiveLDAP
|
|
407
408
|
tries = 0
|
408
409
|
begin
|
409
410
|
# Get some attributes
|
410
|
-
@@conn.search(base(), LDAP::
|
411
|
+
@@conn.search(base(), LDAP::LDAP_SCOPE_ONELEVEL, "(#{attr}=#{val})") do |m|
|
411
412
|
# Extract the dnattr value
|
412
413
|
dnval = m.dn.split(/,/)[0].split(/=/)[1]
|
413
414
|
|
414
415
|
if objects
|
415
|
-
matches.push(
|
416
|
+
matches.push(real_klass.new(m))
|
416
417
|
else
|
417
418
|
matches.push(dnval)
|
418
419
|
end
|
419
420
|
end
|
420
421
|
rescue RuntimeError => detail
|
421
422
|
#todo# check for 'no message' when retrying
|
423
|
+
|
424
|
+
#TODO# This is broken because search gives bad messages.
|
425
|
+
|
422
426
|
# the connection may have gone stale. let's reconnect and retry.
|
423
|
-
if tries >
|
427
|
+
if tries > @@config[:retries]
|
424
428
|
# do nothing on failure
|
425
429
|
|
426
430
|
end
|
@@ -508,7 +512,10 @@ module ActiveLDAP
|
|
508
512
|
@data = {} # where the r/w entry data is stored
|
509
513
|
@ldap_data = {} # original ldap entry data
|
510
514
|
@attr_methods = {} # list of valid method calls for attributes used for dereferencing
|
511
|
-
@last_oc =
|
515
|
+
@last_oc = false # for use in other methods for "caching"
|
516
|
+
if dnattr().empty?
|
517
|
+
raise RuntimeError, "dnattr() not set for this class."
|
518
|
+
end
|
512
519
|
|
513
520
|
# Break val apart if it is a dn
|
514
521
|
if val.match(/^#{dnattr()}=([^,=]+),#{base()}$/i)
|
@@ -529,7 +536,7 @@ module ActiveLDAP
|
|
529
536
|
tries = 0
|
530
537
|
begin
|
531
538
|
# Get some attributes
|
532
|
-
Base.connection.search("#{dnattr()}=#{val}
|
539
|
+
Base.connection.search(base(), LDAP::LDAP_SCOPE_ONELEVEL, "(#{dnattr()}=#{val})") do |m|
|
533
540
|
# Save DN
|
534
541
|
@dn = m.dn
|
535
542
|
# Load up data into tmp
|
@@ -557,24 +564,24 @@ module ActiveLDAP
|
|
557
564
|
@ldap_data.each do |pair|
|
558
565
|
send(:attribute_method=, pair[0], pair[1].dup)
|
559
566
|
end
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
567
|
+
rescue RuntimeError => detail
|
568
|
+
#todo# check for 'no message' when retrying
|
569
|
+
# the connection may have gone stale. let's reconnect and retry.
|
570
|
+
if tries > @@config[:retries]
|
571
|
+
@exists = false
|
572
|
+
# Create what should be the authoritative DN
|
573
|
+
@dn = "#{dnattr()}=#{val},#{base()}"
|
574
|
+
send(:apply_objectclass, required_classes())
|
575
|
+
|
576
|
+
# Setup dn attribute (later rdn too!)
|
577
|
+
attr_sym = "#{dnattr()}=".to_sym
|
578
|
+
|
579
|
+
send(attr_sym, val)
|
580
|
+
end
|
581
|
+
tries += 1
|
582
|
+
# reconnect and rebind.
|
583
|
+
do_connect()
|
584
|
+
retry
|
578
585
|
rescue LDAP::ResultError
|
579
586
|
@exists = false
|
580
587
|
# Create what should be the authoritative DN
|
@@ -672,16 +679,16 @@ module ActiveLDAP
|
|
672
679
|
begin
|
673
680
|
@@conn.delete(@dn)
|
674
681
|
@exists = false
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
682
|
+
rescue RuntimeError => detail
|
683
|
+
#todo# check for 'no message' when retrying
|
684
|
+
# the connection may have gone stale. let's reconnect and retry.
|
685
|
+
if tries > @@config[:retries]
|
679
686
|
raise DeleteError, "Failed to delete LDAP entry: '#{@dn}'"
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
687
|
+
end
|
688
|
+
tries += 1
|
689
|
+
# reconnect and rebind.
|
690
|
+
do_connect()
|
691
|
+
retry
|
685
692
|
rescue LDAP::ResultError => detail
|
686
693
|
raise DeleteError, "Failed to delete LDAP entry: '#{@dn}'"
|
687
694
|
end
|
@@ -812,16 +819,16 @@ module ActiveLDAP
|
|
812
819
|
|
813
820
|
@@conn.modify(@dn, entry)
|
814
821
|
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
822
|
+
rescue RuntimeError => detail
|
823
|
+
#todo# check for 'no message' when retrying
|
824
|
+
# the connection may have gone stale. let's reconnect and retry.
|
825
|
+
if tries > @@config[:retries]
|
826
|
+
raise WriteError, "Could not update LDAP entry: #{detail}"
|
827
|
+
end
|
828
|
+
tries += 1
|
829
|
+
# reconnect and rebind.
|
830
|
+
do_connect()
|
831
|
+
retry
|
825
832
|
rescue => detail
|
826
833
|
raise WriteError, "Could not update LDAP entry: #{detail}"
|
827
834
|
end
|
@@ -853,7 +860,7 @@ module ActiveLDAP
|
|
853
860
|
@exists = true
|
854
861
|
rescue RuntimeError => e
|
855
862
|
# The connection may have gone stale. Let's reconnect and retry.
|
856
|
-
if tries >
|
863
|
+
if tries > @@config[:retries]
|
857
864
|
raise WriteError, "Could not add LDAP entry[#{Base.connection.err2string(Base.connection.err)}]: #{detail}"
|
858
865
|
end
|
859
866
|
tries += 1
|
@@ -984,6 +991,9 @@ module ActiveLDAP
|
|
984
991
|
|
985
992
|
new_oc = val
|
986
993
|
new_oc = [val] if new_oc.class != Array
|
994
|
+
if defined?(@last_oc).nil?
|
995
|
+
@last_oc = false
|
996
|
+
end
|
987
997
|
return new_oc if @last_oc == new_oc
|
988
998
|
|
989
999
|
# Store for caching purposes
|
@@ -996,16 +1006,16 @@ module ActiveLDAP
|
|
996
1006
|
# Build |data| from schema
|
997
1007
|
# clear attr_method mapping first
|
998
1008
|
@attr_methods = {}
|
999
|
-
|
1000
|
-
|
1009
|
+
@must = []
|
1010
|
+
@may = []
|
1001
1011
|
new_oc.each do |objc|
|
1002
1012
|
# get all attributes for the class
|
1003
1013
|
attributes = Base.schema.class_attributes(objc.to_s)
|
1004
|
-
|
1005
|
-
|
1014
|
+
@must += attributes[:must]
|
1015
|
+
@may += attributes[:may]
|
1006
1016
|
end
|
1007
|
-
|
1008
|
-
|
1017
|
+
@must.uniq!
|
1018
|
+
@may.uniq!
|
1009
1019
|
(@must+@may).each do |attr|
|
1010
1020
|
# Update attr_method with appropriate
|
1011
1021
|
define_attribute_methods(attr)
|
@@ -1116,31 +1126,40 @@ module ActiveLDAP
|
|
1116
1126
|
# Performs the actually connection. This separate so that it may
|
1117
1127
|
# be called to refresh stale connections.
|
1118
1128
|
def Base.do_connect()
|
1119
|
-
|
1120
|
-
|
1121
|
-
|
1122
|
-
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1129
|
+
# Wrap the whole thing an try retries times
|
1130
|
+
tries = 0
|
1131
|
+
begin
|
1132
|
+
# Connect to LDAP
|
1133
|
+
begin
|
1134
|
+
# SSL using START_TLS
|
1135
|
+
@@conn = LDAP::SSLConn.new(@@config[:host], @@config[:port], true)
|
1136
|
+
rescue
|
1137
|
+
@@logger.warn "Warning: Failed to connect using TLS!"
|
1138
|
+
begin
|
1139
|
+
@@logger.warn "Warning: Attempting SSL connection . . ."
|
1140
|
+
@@conn = LDAP::SSLConn.new(@@config[:host], @@config[:port], false)
|
1141
|
+
# HACK: Load the schema here because otherwise you can't tell if the
|
1142
|
+
# HACK: SSLConn is a real SSL connection.
|
1143
|
+
@@schema = @@conn.schema() if @@schema.nil?
|
1144
|
+
rescue
|
1145
|
+
@@logger.warn "Warning: Attempting unencrypted connection . . ."
|
1146
|
+
@@conn = LDAP::Conn.new(@@config[:host], @@config[:port])
|
1147
|
+
end
|
1148
|
+
end
|
1149
|
+
|
1150
|
+
|
1151
|
+
# Enforce LDAPv3
|
1152
|
+
@@conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
|
1153
|
+
|
1154
|
+
# Authenticate
|
1155
|
+
do_bind
|
1156
|
+
rescue => e
|
1157
|
+
# Retry
|
1158
|
+
tries += 1
|
1159
|
+
raise e if tries > @@config[:retries]
|
1160
|
+
retry
|
1161
|
+
end
|
1162
|
+
end
|
1144
1163
|
|
1145
1164
|
|
1146
1165
|
# Wrapper all bind activity
|
@@ -1205,7 +1224,7 @@ module ActiveLDAP
|
|
1205
1224
|
mechanisms = @@conn.root_dse[0]['supportedSASLMechanisms']
|
1206
1225
|
# Use GSSAPI if available
|
1207
1226
|
# Currently only GSSAPI is supported with Ruby/LDAP from
|
1208
|
-
# http://caliban.
|
1227
|
+
# http://caliban.org/files/redhat/RPMS/i386/ruby-ldap-0.8.2-4.i386.rpm
|
1209
1228
|
# TODO: Investigate further SASL support
|
1210
1229
|
if mechanisms.respond_to? :member? and mechanisms.member? 'GSSAPI'
|
1211
1230
|
begin
|
@@ -8,11 +8,11 @@ module ActiveLDAP
|
|
8
8
|
module Configuration
|
9
9
|
@@host = "127.0.0.1"
|
10
10
|
@@port = 389
|
11
|
-
@@bind_format = "uid=%s,ou=People,dc=
|
11
|
+
@@bind_format = "uid=%s,ou=People,dc=localdomain"
|
12
12
|
|
13
13
|
# Make the return value the string that is your LDAP base
|
14
14
|
def Base.base
|
15
|
-
'dc=
|
15
|
+
'dc=localdomain'
|
16
16
|
end
|
17
17
|
|
18
18
|
# This is optionally set to the array of objectClass names
|
data/lib/activeldap/schema2.rb
CHANGED
@@ -14,9 +14,9 @@ module LDAP
|
|
14
14
|
# attr('attributeTypes', 'cn', 'DESC')
|
15
15
|
# attr('ldapSyntaxes', '1.3.6.1.4.1.1466.115.121.1.5', 'DESC')
|
16
16
|
def attr(sub, type, at)
|
17
|
-
return
|
18
|
-
return
|
19
|
-
return
|
17
|
+
return [] if sub.empty?
|
18
|
+
return [] if type.empty?
|
19
|
+
return [] if at.empty?
|
20
20
|
|
21
21
|
# Check already parsed options first
|
22
22
|
if @@attr_cache.has_key? sub \
|
@@ -169,6 +169,7 @@ module LDAP
|
|
169
169
|
sups.each do |sup|
|
170
170
|
new_sups += attr('objectClasses', sup, 'SUP')
|
171
171
|
end
|
172
|
+
|
172
173
|
sups += new_sups
|
173
174
|
sups.uniq!
|
174
175
|
break if sups.size == start_size
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: ruby-activeldap
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.5.
|
7
|
-
date: 2005-
|
6
|
+
version: 0.5.9
|
7
|
+
date: 2005-11-01
|
8
8
|
summary: Ruby/ActiveLDAP is a object-oriented API to LDAP
|
9
9
|
require_paths:
|
10
10
|
- lib
|