ruby-activeldap 0.5.8 → 0.5.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|