Skip to content
This repository
Browse code

Merge pull request #1 from partnerpedia/add_delete_tree

added the ability to do a delete_tree
  • Loading branch information...
commit 528ef308010b25ca05e05ed66fca9e3567e25a84 2 parents 6bb9fa6 + 58bd212
Christopher Dwan authored November 17, 2011
1  .gitignore
@@ -9,3 +9,4 @@ publish/
9 9
 coverage/
10 10
 coverage.info
11 11
 .rake_tasks~
  12
+Gemfile.lock
2  Gemfile
... ...
@@ -0,0 +1,2 @@
  1
+source :rubygems
  2
+gemspec
14  lib/net/ber/core_ext/array.rb
@@ -79,4 +79,18 @@ def to_ber_oid
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
10  lib/net/ber/core_ext/string.rb
@@ -46,15 +46,19 @@ def to_ber_contextspecific(code)
46 46
   def read_ber(syntax = nil)
47 47
     StringIO.new(self).read_ber(syntax)
48 48
   end
49  
-  
  49
+
50 50
   ##
51  
-  # Destructively reads a BER object from the string. 
  51
+  # Destructively reads a BER object from the string.
52 52
   def read_ber!(syntax = nil)
53 53
     io = StringIO.new(self)
54 54
 
55 55
     result = io.read_ber(syntax)
56 56
     self.slice!(0...io.pos)
57  
-    
  57
+
58 58
     return result
59 59
   end
  60
+
  61
+  def reject_empty_ber_arrays
  62
+    self.gsub(/0\000/n,'')
  63
+  end
60 64
 end
30  lib/net/ldap.rb
@@ -334,8 +334,9 @@ class LdapError < StandardError; end
334 334
     68 => "Entry Already Exists"
335 335
   }
336 336
 
337  
-  module LdapControls
338  
-    PagedResults = "1.2.840.113556.1.4.319" # Microsoft evil from RFC 2696
  337
+  module LDAPControls
  338
+    PAGED_RESULTS = "1.2.840.113556.1.4.319" # Microsoft evil from RFC 2696
  339
+    DELETE_TREE   = "1.2.840.113556.1.4.805"
339 340
   end
340 341
 
341 342
   def self.result2string(code) #:nodoc:
@@ -552,7 +553,7 @@ def open
552 553
     # anything with the bind results. We then pass self to the caller's
553 554
     # block, where he will execute his LDAP operations. Of course they will
554 555
     # all generate auth failures if the bind was unsuccessful.
555  
-    raise Net::LDAP::LdapError, "Open already in progress" if @open_connection
  556
+    raise LdapError, "Open already in progress" if @open_connection
556 557
 
557 558
     begin
558 559
       @open_connection = Net::LDAP::Connection.new(:host => @host,
@@ -1022,6 +1023,19 @@ def delete(args)
1022 1023
     @result == 0
1023 1024
   end
1024 1025
 
  1026
+  # Delete an entry from the LDAP directory along with all subordinate entries.
  1027
+  # the regular delete method will fail to delete an entry if it has subordinate
  1028
+  # entries. This method sends an extra control code to tell the LDAP server
  1029
+  # to do a tree delete. ('1.2.840.113556.1.4.805')
  1030
+  #
  1031
+  # Returns True or False to indicate whether the delete succeeded. Extended
  1032
+  # status information is available by calling #get_operation_result.
  1033
+  #
  1034
+  #  dn = "mail=deleteme@example.com, ou=people, dc=example, dc=com"
  1035
+  #  ldap.delete_tree :dn => dn
  1036
+  def delete_tree(args)
  1037
+    delete(args.merge(:control_codes => [[LDAPControls::DELETE_TREE, true]]))
  1038
+  end
1025 1039
   # This method is experimental and subject to change. Return the rootDSE
1026 1040
   # record from the LDAP server as a Net::LDAP::Entry, or an empty Entry if
1027 1041
   # the server doesn't return the record.
@@ -1092,7 +1106,7 @@ def search_subschema_entry
1092 1106
   #++
1093 1107
   def paged_searches_supported?
1094 1108
     @server_caps ||= search_root_dse
1095  
-    @server_caps[:supportedcontrol].include?(Net::LDAP::LdapControls::PagedResults)
  1109
+    @server_caps[:supportedcontrol].include?(LDAPControls::PAGED_RESULTS)
1096 1110
   end
1097 1111
 end # class LDAP
1098 1112
 
@@ -1389,7 +1403,7 @@ def search(args = {})
1389 1403
       controls = []
1390 1404
       controls <<
1391 1405
         [
1392  
-          Net::LDAP::LdapControls::PagedResults.to_ber,
  1406
+          LDAPControls::PAGED_RESULTS.to_ber,
1393 1407
           # Criticality MUST be false to interoperate with normal LDAPs.
1394 1408
           false.to_ber,
1395 1409
           rfc2696_cookie.map{ |v| v.to_ber}.to_ber_sequence.to_s.to_ber
@@ -1437,7 +1451,7 @@ def search(args = {})
1437 1451
       more_pages = false
1438 1452
       if result_code == 0 and controls
1439 1453
         controls.each do |c|
1440  
-          if c.oid == Net::LDAP::LdapControls::PagedResults
  1454
+          if c.oid == LDAPControls::PAGED_RESULTS
1441 1455
             # just in case some bogus server sends us more than 1 of these.
1442 1456
             more_pages = false
1443 1457
             if c.value and c.value.length > 0
@@ -1545,9 +1559,9 @@ def rename args
1545 1559
   #++
1546 1560
   def delete(args)
1547 1561
     dn = args[:dn] or raise "Unable to delete empty DN"
1548  
-
  1562
+    controls = args.include?(:control_codes) ? args[:control_codes].to_ber_control : nil #use nil so we can compact later
1549 1563
     request = dn.to_s.to_ber_application_string(10)
1550  
-    pkt = [next_msgid.to_ber, request].to_ber_sequence
  1564
+    pkt = [next_msgid.to_ber, request, controls].compact.to_ber_sequence
1551 1565
     @conn.write pkt
1552 1566
 
1553 1567
     (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"
24  spec/unit/ber/core_ext/array_spec.rb
... ...
@@ -0,0 +1,24 @@
  1
+require 'spec_helper'
  2
+require 'metaid'
  3
+
  4
+describe Array, "when extended with BER core extensions" do
  5
+
  6
+  it "should correctly convert a control code array" do
  7
+    control_codes = []
  8
+    control_codes << ['1.2.3'.to_ber, true.to_ber].to_ber_sequence
  9
+    control_codes << ['1.7.9'.to_ber, false.to_ber].to_ber_sequence
  10
+    control_codes = control_codes.to_ber_sequence
  11
+    res = [['1.2.3', true],['1.7.9',false]].to_ber_control
  12
+    res.should eq(control_codes)
  13
+  end
  14
+
  15
+  it "should wrap the array in another array if a nested array is not passed" do
  16
+    result1 = ['1.2.3', true].to_ber_control
  17
+    result2 = [['1.2.3', true]].to_ber_control
  18
+    result1.should eq(result2)
  19
+  end
  20
+
  21
+  it "should return an empty string if an empty array is passed" do
  22
+    [].to_ber_control.should be_empty
  23
+  end
  24
+end

0 notes on commit 528ef30

Please sign in to comment.
Something went wrong with that request. Please try again.