net-ldap 0.3.1 → 0.5.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.

@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 38e2a66893eef1d93e64fda3d84dc70e51b504f2
4
+ data.tar.gz: e15b5c72e9fd9a38fcf058a9c432e77320d3fcb7
5
+ SHA512:
6
+ metadata.gz: 6bae92818e1c80d15b731d5f8b28ec39f332a0359e8eed3c704e7b4606d5c3ce8f29a7a46bb511b2963a2c30f8085529431a1bcef6780db09f018dd61049ff74
7
+ data.tar.gz: 7277e94a5fcd96fa2cf53e32727ac67b7a8feef5fb7f12190b5fc4dcf1c1c07d0f62a398daa726d776c988372308b1e964a54b0241312515d243a5f88709be41
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ - jruby-19mode
6
+ - rbx-19mode
7
+ script: bundle exec rake spec
@@ -19,3 +19,4 @@ Contributions since:
19
19
  * Derek Harmel (derekharmel)
20
20
  * Erik Hetzner (egh)
21
21
  * nowhereman
22
+ * David J. Lee (DavidJLee)
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
@@ -1,3 +1,15 @@
1
+ === Net::LDAP 0.5.0 / 2013-07-22
2
+ * Major changes:
3
+ * Required Ruby version is >=1.9.3
4
+ * Major enhancements:
5
+ * Added alias dereferencing (@ngwilson)
6
+ * BER now unescapes characters that are already escaped in the source string (@jzinn)
7
+ * BerIdentifiedString will now fall back to ASCII-8 encoding if the source Ruby object cannot be encoded in UTF-8 (@lfu)
8
+ * Bug fixes:
9
+ * Fixed nil variable error when following a reference response (@cmdrclueless)
10
+ * Fixed FilterParser unable to parse multibyte strings (@satoryu)
11
+ * Return ConverterNotFound when dealing with a potentially corrupt data response (@jamuc)
12
+
1
13
  === Net::LDAP 0.3.1 / 2012-02-15
2
14
  * Bug Fixes:
3
15
  * Bundler should now work again
@@ -1,6 +1,8 @@
1
1
  .autotest
2
2
  .rspec
3
+ .travis.yml
3
4
  Contributors.rdoc
5
+ Gemfile
4
6
  Hacking.rdoc
5
7
  History.rdoc
6
8
  License.rdoc
@@ -25,16 +27,20 @@ lib/net/ldap/entry.rb
25
27
  lib/net/ldap/filter.rb
26
28
  lib/net/ldap/password.rb
27
29
  lib/net/ldap/pdu.rb
30
+ lib/net/ldap/version.rb
28
31
  lib/net/snmp.rb
29
32
  net-ldap.gemspec
30
33
  spec/integration/ssl_ber_spec.rb
31
34
  spec/spec.opts
32
35
  spec/spec_helper.rb
33
36
  spec/unit/ber/ber_spec.rb
37
+ spec/unit/ber/core_ext/array_spec.rb
34
38
  spec/unit/ber/core_ext/string_spec.rb
35
39
  spec/unit/ldap/dn_spec.rb
36
40
  spec/unit/ldap/entry_spec.rb
41
+ spec/unit/ldap/filter_parser_spec.rb
37
42
  spec/unit/ldap/filter_spec.rb
43
+ spec/unit/ldap/search_spec.rb
38
44
  spec/unit/ldap_spec.rb
39
45
  test/common.rb
40
46
  test/test_entry.rb
@@ -1,4 +1,4 @@
1
- = Net::LDAP for Ruby
1
+ = Net::LDAP for Ruby {<img src="https://travis-ci.org/ruby-ldap/ruby-net-ldap.png" />}[https://travis-ci.org/ruby-ldap/ruby-net-ldap]
2
2
 
3
3
  == Description
4
4
 
@@ -30,7 +30,7 @@ See Net::LDAP for documentation and usage samples.
30
30
 
31
31
  == Requirements
32
32
 
33
- Net::LDAP requires a Ruby 1.8.7 interpreter or better.
33
+ Net::LDAP requires a Ruby 1.9.3 compatible interpreter or better.
34
34
 
35
35
  == Install
36
36
 
@@ -42,11 +42,6 @@ sources.
42
42
 
43
43
  Simply require either 'net-ldap' or 'net/ldap'.
44
44
 
45
- For non-RubyGems installations of Net::LDAP, you can use Minero Aoki's
46
- {setup.rb}[http://i.loveruby.net/en/projects/setup/] as the layout of
47
- Net::LDAP is compliant. The setup installer is not included in the
48
- Net::LDAP repository.
49
-
50
45
  :include: Contributors.rdoc
51
46
 
52
47
  :include: License.rdoc
data/Rakefile CHANGED
@@ -8,18 +8,20 @@ Hoe.plugin :git
8
8
  Hoe.plugin :gemspec
9
9
 
10
10
  Hoe.spec 'net-ldap' do |spec|
11
- spec.rubyforge_name = spec.name
11
+ # spec.rubyforge_name = spec.name
12
12
 
13
13
  spec.developer("Francis Cianfrocca", "blackhedd@rubyforge.org")
14
14
  spec.developer("Emiel van de Laar", "gemiel@gmail.com")
15
15
  spec.developer("Rory O'Connell", "rory.ocon@gmail.com")
16
16
  spec.developer("Kaspar Schiess", "kaspar.schiess@absurd.li")
17
17
  spec.developer("Austin Ziegler", "austin@rubyforge.org")
18
+ spec.developer("Michael Schaarschmidt", "michael@schaaryworks.com")
18
19
 
19
20
  spec.remote_rdoc_dir = ''
20
21
  spec.rsync_args << ' --exclude=statsvn/'
21
22
 
22
- spec.url = %W(http://rubyldap.com/ https://github.com/ruby-ldap/ruby-net-ldap)
23
+ spec.urls = %w(http://rubyldap.com/' 'https://github.com/ruby-ldap/ruby-net-ldap)
24
+ spec.licenses = ['MIT']
23
25
 
24
26
  spec.history_file = 'History.rdoc'
25
27
  spec.readme_file = 'README.rdoc'
@@ -29,7 +31,7 @@ Hoe.spec 'net-ldap' do |spec|
29
31
  spec.extra_dev_deps << [ "hoe-git", "~> 1" ]
30
32
  spec.extra_dev_deps << [ "hoe-gemspec", "~> 1" ]
31
33
  spec.extra_dev_deps << [ "metaid", "~> 1" ]
32
- spec.extra_dev_deps << [ "flexmock", "~> 0.9.0" ]
34
+ spec.extra_dev_deps << [ "flexmock", ">= 1.3.0" ]
33
35
  spec.extra_dev_deps << [ "rspec", "~> 2.0" ]
34
36
 
35
37
  spec.clean_globs << "coverage"
@@ -1,4 +1,6 @@
1
1
  # -*- ruby encoding: utf-8 -*-
2
+ require 'net/ldap/version'
3
+
2
4
  module Net # :nodoc:
3
5
  ##
4
6
  # == Basic Encoding Rules (BER) Support Module
@@ -106,7 +108,7 @@ module Net # :nodoc:
106
108
  # <tr><th>BMPString</th><th>C</th><td>30: 62 (0x3e, 0b00111110)</td></tr>
107
109
  # </table>
108
110
  module BER
109
- VERSION = '0.3.1'
111
+ VERSION = Net::LDAP::VERSION
110
112
 
111
113
  ##
112
114
  # Used for BER-encoding the length and content bytes of a Fixnum integer
@@ -296,7 +298,7 @@ class Net::BER::BerIdentifiedString < String
296
298
  def initialize args
297
299
  super args
298
300
  # LDAP uses UTF-8 encoded strings
299
- force_encoding('UTF-8') if respond_to?(:encoding)
301
+ self.encode('UTF-8') if self.respond_to?(:encoding) rescue self
300
302
  end
301
303
  end
302
304
 
@@ -79,4 +79,18 @@ module Net::BER::Extensions::Array
79
79
  oid = ary.pack("w*")
80
80
  [6, oid.length].pack("CC") + oid
81
81
  end
82
+
83
+ ##
84
+ # Converts an array into a set of ber control codes
85
+ # The expected format is [[control_oid, criticality, control_value(optional)]]
86
+ # [['1.2.840.113556.1.4.805',true]]
87
+ #
88
+ def to_ber_control
89
+ #if our array does not contain at least one array then wrap it in an array before going forward
90
+ ary = self[0].kind_of?(Array) ? self : [self]
91
+ ary = ary.collect do |control_sequence|
92
+ control_sequence.collect{|element| element.to_ber}.to_ber_sequence.reject_empty_ber_arrays
93
+ end
94
+ ary.to_ber_sequence.reject_empty_ber_arrays
95
+ end
82
96
  end
@@ -16,11 +16,25 @@ module Net::BER::Extensions::String
16
16
  [code].pack('C') + raw_string.length.to_ber_length_encoding + raw_string
17
17
  end
18
18
 
19
+ ##
20
+ # Converts a string to a BER string but does *not* encode to UTF-8 first.
21
+ # This is required for proper representation of binary data for Microsoft
22
+ # Active Directory
23
+ def to_ber_bin(code = 0x04)
24
+ [code].pack('C') + length.to_ber_length_encoding + self
25
+ end
26
+
19
27
  def raw_utf8_encoded
20
28
  if self.respond_to?(:encode)
21
29
  # Strings should be UTF-8 encoded according to LDAP.
22
30
  # However, the BER code is not necessarily valid UTF-8
23
- self.encode('UTF-8').force_encoding('ASCII-8BIT')
31
+ begin
32
+ self.encode('UTF-8').force_encoding('ASCII-8BIT')
33
+ rescue Encoding::UndefinedConversionError
34
+ self
35
+ rescue Encoding::ConverterNotFoundError
36
+ return self
37
+ end
24
38
  else
25
39
  self
26
40
  end
@@ -46,15 +60,19 @@ module Net::BER::Extensions::String
46
60
  def read_ber(syntax = nil)
47
61
  StringIO.new(self).read_ber(syntax)
48
62
  end
49
-
63
+
50
64
  ##
51
- # Destructively reads a BER object from the string.
65
+ # Destructively reads a BER object from the string.
52
66
  def read_ber!(syntax = nil)
53
67
  io = StringIO.new(self)
54
68
 
55
69
  result = io.read_ber(syntax)
56
70
  self.slice!(0...io.pos)
57
-
71
+
58
72
  return result
59
73
  end
74
+
75
+ def reject_empty_ber_arrays
76
+ self.gsub(/0\000/n,'')
77
+ end
60
78
  end
@@ -23,6 +23,7 @@ require 'net/ldap/filter'
23
23
  require 'net/ldap/dataset'
24
24
  require 'net/ldap/password'
25
25
  require 'net/ldap/entry'
26
+ require 'net/ldap/version'
26
27
 
27
28
  # == Quick-start for the Impatient
28
29
  # === Quick Example of a user-authentication against an LDAP directory:
@@ -241,7 +242,6 @@ require 'net/ldap/entry'
241
242
  # and then keeps it open while it executes a user-supplied block.
242
243
  # Net::LDAP#open closes the connection on completion of the block.
243
244
  class Net::LDAP
244
- VERSION = "0.3.1"
245
245
 
246
246
  class LdapError < StandardError; end
247
247
 
@@ -251,6 +251,12 @@ class Net::LDAP
251
251
  SearchScopes = [ SearchScope_BaseObject, SearchScope_SingleLevel,
252
252
  SearchScope_WholeSubtree ]
253
253
 
254
+ DerefAliases_Never = 0
255
+ DerefAliases_Search = 1
256
+ DerefAliases_Find = 2
257
+ DerefAliases_Always = 3
258
+ DerefAliasesArray = [ DerefAliases_Never, DerefAliases_Search, DerefAliases_Find, DerefAliases_Always ]
259
+
254
260
  primitive = { 2 => :null } # UnbindRequest body
255
261
  constructed = {
256
262
  0 => :array, # BindRequest
@@ -308,6 +314,7 @@ class Net::LDAP
308
314
  DefaultPort = 389
309
315
  DefaultAuth = { :method => :anonymous }
310
316
  DefaultTreebase = "dc=com"
317
+ DefaultForceNoPage = false
311
318
 
312
319
  StartTlsOid = "1.3.6.1.4.1.1466.20037"
313
320
 
@@ -322,6 +329,7 @@ class Net::LDAP
322
329
  14 => "saslBindInProgress",
323
330
  16 => "No Such Attribute",
324
331
  17 => "Undefined Attribute Type",
332
+ 19 => "Constraint Violation",
325
333
  20 => "Attribute or Value Exists",
326
334
  32 => "No Such Object",
327
335
  34 => "Invalid DN Syntax",
@@ -335,8 +343,11 @@ class Net::LDAP
335
343
  68 => "Entry Already Exists"
336
344
  }
337
345
 
338
- module LdapControls
339
- PagedResults = "1.2.840.113556.1.4.319" # Microsoft evil from RFC 2696
346
+ module LDAPControls
347
+ PAGED_RESULTS = "1.2.840.113556.1.4.319" # Microsoft evil from RFC 2696
348
+ SORT_REQUEST = "1.2.840.113556.1.4.473"
349
+ SORT_RESPONSE = "1.2.840.113556.1.4.474"
350
+ DELETE_TREE = "1.2.840.113556.1.4.805"
340
351
  end
341
352
 
342
353
  def self.result2string(code) #:nodoc:
@@ -370,6 +381,8 @@ class Net::LDAP
370
381
  # specifying the Hash {:method => :simple_tls}. There is a fairly large
371
382
  # range of potential values that may be given for this parameter. See
372
383
  # #encryption for details.
384
+ # * :force_no_page => Set to true to prevent paged results even if your
385
+ # server says it supports them. This is a fix for MS Active Directory
373
386
  #
374
387
  # Instantiating a Net::LDAP object does <i>not</i> result in network
375
388
  # traffic to the LDAP server. It simply stores the connection and binding
@@ -380,6 +393,7 @@ class Net::LDAP
380
393
  @verbose = false # Make this configurable with a switch on the class.
381
394
  @auth = args[:auth] || DefaultAuth
382
395
  @base = args[:base] || DefaultTreebase
396
+ @force_no_page = args[:force_no_page] || DefaultForceNoPage
383
397
  encryption args[:encryption] # may be nil
384
398
 
385
399
  if pr = @auth[:password] and pr.respond_to?(:call)
@@ -516,15 +530,17 @@ class Net::LDAP
516
530
  # response codes instead of a simple numeric code.
517
531
  #++
518
532
  def get_operation_result
533
+ result = @result
534
+ result = result.result if result.is_a?(Net::LDAP::PDU)
519
535
  os = OpenStruct.new
520
- if @result.is_a?(Hash)
536
+ if result.is_a?(Hash)
521
537
  # We might get a hash of LDAP response codes instead of a simple
522
538
  # numeric code.
523
- os.code = (@result[:resultCode] || "").to_i
524
- os.error_message = @result[:errorMessage]
525
- os.matched_dn = @result[:matchedDN]
526
- elsif @result
527
- os.code = @result
539
+ os.code = (result[:resultCode] || "").to_i
540
+ os.error_message = result[:errorMessage]
541
+ os.matched_dn = result[:matchedDN]
542
+ elsif result
543
+ os.code = result
528
544
  else
529
545
  os.code = 0
530
546
  end
@@ -582,6 +598,8 @@ class Net::LDAP
582
598
  # Net::LDAP::SearchScope_WholeSubtree. Default is WholeSubtree.)
583
599
  # * :size (an integer indicating the maximum number of search entries to
584
600
  # return. Default is zero, which signifies no limit.)
601
+ # * :deref (one of: Net::LDAP::DerefAliases_Never, Net::LDAP::DerefAliases_Search,
602
+ # Net::LDAP::DerefAliases_Find, Net::LDAP::DerefAliases_Always. Default is Never.)
585
603
  #
586
604
  # #search queries the LDAP server and passes <i>each entry</i> to the
587
605
  # caller-supplied block, as an object of type Net::LDAP::Entry. If the
@@ -629,11 +647,10 @@ class Net::LDAP
629
647
  yield entry if block_given?
630
648
  }
631
649
  else
632
- @result = 0
633
650
  begin
634
651
  conn = Net::LDAP::Connection.new(:host => @host, :port => @port,
635
652
  :encryption => @encryption)
636
- if (@result = conn.bind(args[:auth] || @auth)) == 0
653
+ if (@result = conn.bind(args[:auth] || @auth)).result_code == 0
637
654
  @result = conn.search(args) { |entry|
638
655
  result_set << entry if result_set
639
656
  yield entry if block_given?
@@ -645,9 +662,9 @@ class Net::LDAP
645
662
  end
646
663
 
647
664
  if return_result_set
648
- @result == 0 ? result_set : nil
665
+ (!@result.nil? && @result.result_code == 0) ? result_set : nil
649
666
  else
650
- @result == 0
667
+ @result.success?
651
668
  end
652
669
  end
653
670
 
@@ -721,7 +738,7 @@ class Net::LDAP
721
738
  end
722
739
  end
723
740
 
724
- @result == 0
741
+ @result.success?
725
742
  end
726
743
 
727
744
  # #bind_as is for testing authentication credentials.
@@ -816,14 +833,14 @@ class Net::LDAP
816
833
  begin
817
834
  conn = Connection.new(:host => @host, :port => @port,
818
835
  :encryption => @encryption)
819
- if (@result = conn.bind(args[:auth] || @auth)) == 0
836
+ if (@result = conn.bind(args[:auth] || @auth)).result_code == 0
820
837
  @result = conn.add(args)
821
838
  end
822
839
  ensure
823
840
  conn.close if conn
824
841
  end
825
842
  end
826
- @result == 0
843
+ @result.success?
827
844
  end
828
845
 
829
846
  # Modifies the attribute values of a particular entry on the LDAP
@@ -914,14 +931,15 @@ class Net::LDAP
914
931
  begin
915
932
  conn = Connection.new(:host => @host, :port => @port,
916
933
  :encryption => @encryption)
917
- if (@result = conn.bind(args[:auth] || @auth)) == 0
934
+ if (@result = conn.bind(args[:auth] || @auth)).result_code == 0
918
935
  @result = conn.modify(args)
919
936
  end
920
937
  ensure
921
938
  conn.close if conn
922
939
  end
923
940
  end
924
- @result == 0
941
+
942
+ @result.success?
925
943
  end
926
944
 
927
945
  # Add a value to an attribute. Takes the full DN of the entry to modify,
@@ -985,14 +1003,14 @@ class Net::LDAP
985
1003
  begin
986
1004
  conn = Connection.new(:host => @host, :port => @port,
987
1005
  :encryption => @encryption)
988
- if (@result = conn.bind(args[:auth] || @auth)) == 0
1006
+ if (@result = conn.bind(args[:auth] || @auth)).result_code == 0
989
1007
  @result = conn.rename(args)
990
1008
  end
991
1009
  ensure
992
1010
  conn.close if conn
993
1011
  end
994
1012
  end
995
- @result == 0
1013
+ @result.success?
996
1014
  end
997
1015
  alias_method :modify_rdn, :rename
998
1016
 
@@ -1013,16 +1031,29 @@ class Net::LDAP
1013
1031
  begin
1014
1032
  conn = Connection.new(:host => @host, :port => @port,
1015
1033
  :encryption => @encryption)
1016
- if (@result = conn.bind(args[:auth] || @auth)) == 0
1034
+ if (@result = conn.bind(args[:auth] || @auth)).result_code == 0
1017
1035
  @result = conn.delete(args)
1018
1036
  end
1019
1037
  ensure
1020
1038
  conn.close
1021
1039
  end
1022
1040
  end
1023
- @result == 0
1041
+ @result.success?
1024
1042
  end
1025
1043
 
1044
+ # Delete an entry from the LDAP directory along with all subordinate entries.
1045
+ # the regular delete method will fail to delete an entry if it has subordinate
1046
+ # entries. This method sends an extra control code to tell the LDAP server
1047
+ # to do a tree delete. ('1.2.840.113556.1.4.805')
1048
+ #
1049
+ # Returns True or False to indicate whether the delete succeeded. Extended
1050
+ # status information is available by calling #get_operation_result.
1051
+ #
1052
+ # dn = "mail=deleteme@example.com, ou=people, dc=example, dc=com"
1053
+ # ldap.delete_tree :dn => dn
1054
+ def delete_tree(args)
1055
+ delete(args.merge(:control_codes => [[Net::LDAP::LDAPControls::DELETE_TREE, true]]))
1056
+ end
1026
1057
  # This method is experimental and subject to change. Return the rootDSE
1027
1058
  # record from the LDAP server as a Net::LDAP::Entry, or an empty Entry if
1028
1059
  # the server doesn't return the record.
@@ -1092,8 +1123,12 @@ class Net::LDAP
1092
1123
  # MUST refactor the root_dse call out.
1093
1124
  #++
1094
1125
  def paged_searches_supported?
1126
+ # active directory returns that it supports paged results. However
1127
+ # it returns binary data in the rfc2696_cookie which throws an
1128
+ # encoding exception breaking searching.
1129
+ return false if @force_no_page
1095
1130
  @server_caps ||= search_root_dse
1096
- @server_caps[:supportedcontrol].include?(Net::LDAP::LdapControls::PagedResults)
1131
+ @server_caps[:supportedcontrol].include?(Net::LDAP::LDAPControls::PAGED_RESULTS)
1097
1132
  end
1098
1133
  end # class LDAP
1099
1134
 
@@ -1237,7 +1272,7 @@ class Net::LDAP::Connection #:nodoc:
1237
1272
 
1238
1273
  (be = @conn.read_ber(Net::LDAP::AsnSyntax) and pdu = Net::LDAP::PDU.new(be)) or raise Net::LDAP::LdapError, "no bind result"
1239
1274
 
1240
- pdu.result_code
1275
+ pdu
1241
1276
  end
1242
1277
 
1243
1278
  #--
@@ -1275,7 +1310,7 @@ class Net::LDAP::Connection #:nodoc:
1275
1310
  @conn.write request_pkt
1276
1311
 
1277
1312
  (be = @conn.read_ber(Net::LDAP::AsnSyntax) and pdu = Net::LDAP::PDU.new(be)) or raise Net::LDAP::LdapError, "no bind result"
1278
- return pdu.result_code unless pdu.result_code == 14 # saslBindInProgress
1313
+ return pdu unless pdu.result_code == 14 # saslBindInProgress
1279
1314
  raise Net::LDAP::LdapError, "sasl-challenge overflow" if ((n += 1) > MaxSaslChallenges)
1280
1315
 
1281
1316
  cred = chall.call(pdu.result_server_sasl_creds)
@@ -1315,6 +1350,35 @@ class Net::LDAP::Connection #:nodoc:
1315
1350
  end
1316
1351
  private :bind_gss_spnego
1317
1352
 
1353
+
1354
+ #--
1355
+ # Allow the caller to specify a sort control
1356
+ #
1357
+ # The format of the sort control needs to be:
1358
+ #
1359
+ # :sort_control => ["cn"] # just a string
1360
+ # or
1361
+ # :sort_control => [["cn", "matchingRule", true]] #attribute, matchingRule, direction (true / false)
1362
+ # or
1363
+ # :sort_control => ["givenname","sn"] #multiple strings or arrays
1364
+ #
1365
+ def encode_sort_controls(sort_definitions)
1366
+ return sort_definitions unless sort_definitions
1367
+
1368
+ sort_control_values = sort_definitions.map do |control|
1369
+ control = Array(control) # if there is only an attribute name as a string then infer the orderinrule and reverseorder
1370
+ control[0] = String(control[0]).to_ber,
1371
+ control[1] = String(control[1]).to_ber,
1372
+ control[2] = (control[2] == true).to_ber
1373
+ control.to_ber_sequence
1374
+ end
1375
+ sort_control = [
1376
+ Net::LDAP::LDAPControls::SORT_REQUEST.to_ber,
1377
+ false.to_ber,
1378
+ sort_control_values.to_ber_sequence.to_s.to_ber
1379
+ ].to_ber_sequence
1380
+ end
1381
+
1318
1382
  #--
1319
1383
  # Alternate implementation, this yields each search entry to the caller as
1320
1384
  # it are received.
@@ -1340,6 +1404,12 @@ class Net::LDAP::Connection #:nodoc:
1340
1404
  scope = args[:scope] || Net::LDAP::SearchScope_WholeSubtree
1341
1405
  raise Net::LDAP::LdapError, "invalid search scope" unless Net::LDAP::SearchScopes.include?(scope)
1342
1406
 
1407
+ sort_control = encode_sort_controls(args.fetch(:sort_controls){ false })
1408
+
1409
+ deref = args[:deref] || Net::LDAP::DerefAliases_Never
1410
+ raise Net::LDAP::LdapError.new( "invalid alias dereferencing value" ) unless Net::LDAP::DerefAliasesArray.include?(deref)
1411
+
1412
+
1343
1413
  # An interesting value for the size limit would be close to A/D's
1344
1414
  # built-in page limit of 1000 records, but openLDAP newer than version
1345
1415
  # 2.2.0 chokes on anything bigger than 126. You get a silent error that
@@ -1361,7 +1431,7 @@ class Net::LDAP::Connection #:nodoc:
1361
1431
  # to do a root-DSE record search and not do a paged search if the LDAP
1362
1432
  # doesn't support it. Yuck.
1363
1433
  rfc2696_cookie = [126, ""]
1364
- result_code = 0
1434
+ result_pdu = nil
1365
1435
  n_results = 0
1366
1436
 
1367
1437
  loop {
@@ -1379,7 +1449,7 @@ class Net::LDAP::Connection #:nodoc:
1379
1449
  request = [
1380
1450
  search_base.to_ber,
1381
1451
  scope.to_ber_enumerated,
1382
- 0.to_ber_enumerated,
1452
+ deref.to_ber_enumerated,
1383
1453
  query_limit.to_ber, # size limit
1384
1454
  0.to_ber,
1385
1455
  attributes_only.to_ber,
@@ -1387,20 +1457,25 @@ class Net::LDAP::Connection #:nodoc:
1387
1457
  search_attributes.to_ber_sequence
1388
1458
  ].to_ber_appsequence(3)
1389
1459
 
1460
+ # rfc2696_cookie sometimes contains binary data from Microsoft Active Directory
1461
+ # this breaks when calling to_ber. (Can't force binary data to UTF-8)
1462
+ # we have to disable paging (even though server supports it) to get around this...
1463
+
1390
1464
  controls = []
1391
1465
  controls <<
1392
1466
  [
1393
- Net::LDAP::LdapControls::PagedResults.to_ber,
1467
+ Net::LDAP::LDAPControls::PAGED_RESULTS.to_ber,
1394
1468
  # Criticality MUST be false to interoperate with normal LDAPs.
1395
1469
  false.to_ber,
1396
1470
  rfc2696_cookie.map{ |v| v.to_ber}.to_ber_sequence.to_s.to_ber
1397
1471
  ].to_ber_sequence if paged_searches_supported
1472
+ controls << sort_control if sort_control
1398
1473
  controls = controls.empty? ? nil : controls.to_ber_contextspecific(0)
1399
1474
 
1400
1475
  pkt = [next_msgid.to_ber, request, controls].compact.to_ber_sequence
1401
1476
  @conn.write pkt
1402
1477
 
1403
- result_code = 0
1478
+ result_pdu = nil
1404
1479
  controls = []
1405
1480
 
1406
1481
  while (be = @conn.read_ber(Net::LDAP::AsnSyntax)) && (pdu = Net::LDAP::PDU.new(be))
@@ -1417,9 +1492,9 @@ class Net::LDAP::Connection #:nodoc:
1417
1492
  end
1418
1493
  end
1419
1494
  when 5 # search-result
1420
- result_code = pdu.result_code
1495
+ result_pdu = pdu
1421
1496
  controls = pdu.result_controls
1422
- if return_referrals && result_code == 10
1497
+ if return_referrals && pdu.result_code == 10
1423
1498
  if block_given?
1424
1499
  se = Net::LDAP::Entry.new
1425
1500
  se[:search_referrals] = (pdu.search_referrals || [])
@@ -1443,9 +1518,9 @@ class Net::LDAP::Connection #:nodoc:
1443
1518
  # of type OCTET STRING, covered in the default syntax supported by
1444
1519
  # read_ber, so I guess we're ok.
1445
1520
  more_pages = false
1446
- if result_code == 0 and controls
1521
+ if result_pdu.result_code == 0 and controls
1447
1522
  controls.each do |c|
1448
- if c.oid == Net::LDAP::LdapControls::PagedResults
1523
+ if c.oid == Net::LDAP::LDAPControls::PAGED_RESULTS
1449
1524
  # just in case some bogus server sends us more than 1 of these.
1450
1525
  more_pages = false
1451
1526
  if c.value and c.value.length > 0
@@ -1462,7 +1537,7 @@ class Net::LDAP::Connection #:nodoc:
1462
1537
  break unless more_pages
1463
1538
  } # loop
1464
1539
 
1465
- result_code
1540
+ result_pdu || OpenStruct.new(:status => :failure, :result_code => 1, :message => "Invalid search")
1466
1541
  end
1467
1542
 
1468
1543
  MODIFY_OPERATIONS = { #:nodoc:
@@ -1502,7 +1577,8 @@ class Net::LDAP::Connection #:nodoc:
1502
1577
  @conn.write pkt
1503
1578
 
1504
1579
  (be = @conn.read_ber(Net::LDAP::AsnSyntax)) && (pdu = Net::LDAP::PDU.new(be)) && (pdu.app_tag == 7) or raise Net::LDAP::LdapError, "response missing or invalid"
1505
- pdu.result_code
1580
+
1581
+ pdu
1506
1582
  end
1507
1583
 
1508
1584
  #--
@@ -1523,21 +1599,25 @@ class Net::LDAP::Connection #:nodoc:
1523
1599
  pkt = [next_msgid.to_ber, request].to_ber_sequence
1524
1600
  @conn.write pkt
1525
1601
 
1526
- (be = @conn.read_ber(Net::LDAP::AsnSyntax)) && (pdu = Net::LDAP::PDU.new(be)) && (pdu.app_tag == 9) or raise Net::LDAP::LdapError, "response missing or invalid"
1527
- pdu.result_code
1602
+ (be = @conn.read_ber(Net::LDAP::AsnSyntax)) &&
1603
+ (pdu = Net::LDAP::PDU.new(be)) &&
1604
+ (pdu.app_tag == 9) or
1605
+ raise Net::LDAP::LdapError, "response missing or invalid"
1606
+
1607
+ pdu
1528
1608
  end
1529
1609
 
1530
1610
  #--
1531
1611
  # TODO: need to support a time limit, in case the server fails to respond.
1532
1612
  #++
1533
- def rename args
1613
+ def rename(args)
1534
1614
  old_dn = args[:olddn] or raise "Unable to rename empty DN"
1535
1615
  new_rdn = args[:newrdn] or raise "Unable to rename to empty RDN"
1536
1616
  delete_attrs = args[:delete_attributes] ? true : false
1537
1617
  new_superior = args[:new_superior]
1538
1618
 
1539
1619
  request = [old_dn.to_ber, new_rdn.to_ber, delete_attrs.to_ber]
1540
- request << new_superior.to_ber unless new_superior == nil
1620
+ request << new_superior.to_ber_contextspecific(0) unless new_superior == nil
1541
1621
 
1542
1622
  pkt = [next_msgid.to_ber, request.to_ber_appsequence(12)].to_ber_sequence
1543
1623
  @conn.write pkt
@@ -1545,7 +1625,8 @@ class Net::LDAP::Connection #:nodoc:
1545
1625
  (be = @conn.read_ber(Net::LDAP::AsnSyntax)) &&
1546
1626
  (pdu = Net::LDAP::PDU.new( be )) && (pdu.app_tag == 13) or
1547
1627
  raise Net::LDAP::LdapError.new( "response missing or invalid" )
1548
- pdu.result_code
1628
+
1629
+ pdu
1549
1630
  end
1550
1631
 
1551
1632
  #--
@@ -1553,12 +1634,13 @@ class Net::LDAP::Connection #:nodoc:
1553
1634
  #++
1554
1635
  def delete(args)
1555
1636
  dn = args[:dn] or raise "Unable to delete empty DN"
1556
-
1637
+ controls = args.include?(:control_codes) ? args[:control_codes].to_ber_control : nil #use nil so we can compact later
1557
1638
  request = dn.to_s.to_ber_application_string(10)
1558
- pkt = [next_msgid.to_ber, request].to_ber_sequence
1639
+ pkt = [next_msgid.to_ber, request, controls].compact.to_ber_sequence
1559
1640
  @conn.write pkt
1560
1641
 
1561
1642
  (be = @conn.read_ber(Net::LDAP::AsnSyntax)) && (pdu = Net::LDAP::PDU.new(be)) && (pdu.app_tag == 11) or raise Net::LDAP::LdapError, "response missing or invalid"
1562
- pdu.result_code
1643
+
1644
+ pdu
1563
1645
  end
1564
1646
  end # class Connection