From 463ac436a8ad0463c394feb48e40acea75d6a036 Mon Sep 17 00:00:00 2001 From: Chris Dwan Date: Wed, 16 Nov 2011 16:36:39 -0800 Subject: [PATCH 1/3] added the ability to do a delete_tree --- Gemfile | 2 ++ Gemfile.lock | 38 ++++++++++++++++++++++++++++ lib/net/ber/core_ext/array.rb | 12 +++++++++ lib/net/ldap.rb | 17 +++++++++++-- spec/unit/ber/core_ext/array_spec.rb | 14 ++++++++++ 5 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 Gemfile create mode 100644 Gemfile.lock create mode 100644 spec/unit/ber/core_ext/array_spec.rb diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..e45e65f --- /dev/null +++ b/Gemfile @@ -0,0 +1,2 @@ +source :rubygems +gemspec diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..f2c7ae4 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,38 @@ +PATH + remote: . + specs: + net-ldap (0.2.20110317223538) + +GEM + remote: http://rubygems.org/ + specs: + diff-lcs (1.1.3) + flexmock (0.9.0) + hoe (2.12.3) + rake (~> 0.8) + hoe-gemspec (1.0.0) + hoe (>= 2.2.0) + hoe-git (1.4.1) + hoe (>= 2.2.0) + metaid (1.0) + rake (0.9.2.2) + rspec (2.7.0) + rspec-core (~> 2.7.0) + rspec-expectations (~> 2.7.0) + rspec-mocks (~> 2.7.0) + rspec-core (2.7.1) + rspec-expectations (2.7.0) + diff-lcs (~> 1.1.2) + rspec-mocks (2.7.0) + +PLATFORMS + ruby + +DEPENDENCIES + flexmock (~> 0.9.0) + hoe (>= 2.9.1) + hoe-gemspec (~> 1) + hoe-git (~> 1) + metaid (~> 1) + net-ldap! + rspec (~> 2.0) diff --git a/lib/net/ber/core_ext/array.rb b/lib/net/ber/core_ext/array.rb index 8fa12c1..71b1a5e 100644 --- a/lib/net/ber/core_ext/array.rb +++ b/lib/net/ber/core_ext/array.rb @@ -79,4 +79,16 @@ module Net::BER::Extensions::Array oid = ary.pack("w*") [6, oid.length].pack("CC") + oid end + + ## + # Converts an array into a set of ber control codes + # The expected format is [[control_oid, criticality, control_value(optional)]] + # [['1.2.840.113556.1.4.805',true]] + # + def to_ber_control + ary = self.collect do |control_sequence| + control_sequence.collect{|element| element.to_ber}.to_ber_sequence + end + ary.to_ber_sequence #putting this on a new line to make it more readable. + end end diff --git a/lib/net/ldap.rb b/lib/net/ldap.rb index b92a13f..e687da2 100644 --- a/lib/net/ldap.rb +++ b/lib/net/ldap.rb @@ -1022,6 +1022,19 @@ class Net::LDAP @result == 0 end + # Delete an entry from the LDAP directory along with all subordinate entries. + # the regular delete method will fail to delete an entry if it has subordinate + # entries. This method sends an extra control code to tell the LDAP server + # to do a tree delete. ('1.2.840.113556.1.4.805') + # + # Returns True or False to indicate whether the delete succeeded. Extended + # status information is available by calling #get_operation_result. + # + # dn = "mail=deleteme@example.com, ou=people, dc=example, dc=com" + # ldap.delete_tree :dn => dn + def delete_tree(args) + delete(args.merge(:control_codes => [['1.2.840.113556.1.4.805',true]])) + end # This method is experimental and subject to change. Return the rootDSE # record from the LDAP server as a Net::LDAP::Entry, or an empty Entry if # the server doesn't return the record. @@ -1545,9 +1558,9 @@ class Net::LDAP::Connection #:nodoc: #++ def delete(args) dn = args[:dn] or raise "Unable to delete empty DN" - + controls = args.include?(:control_codes) ? args[:control_codes].to_ber_control : nil #use nil so we can compact later request = dn.to_s.to_ber_application_string(10) - pkt = [next_msgid.to_ber, request].to_ber_sequence + pkt = [next_msgid.to_ber, request, controls].compact.to_ber_sequence @conn.write pkt (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" diff --git a/spec/unit/ber/core_ext/array_spec.rb b/spec/unit/ber/core_ext/array_spec.rb new file mode 100644 index 0000000..44e2bd9 --- /dev/null +++ b/spec/unit/ber/core_ext/array_spec.rb @@ -0,0 +1,14 @@ +require 'spec_helper' +require 'metaid' + +describe Array, "when extended with BER core extensions" do + + it "should correctly convert a control code array" do + control_codes = [] + control_codes << ['1.2.3'.to_ber, true.to_ber].to_ber_sequence + control_codes << ['1.7.9'.to_ber, false.to_ber].to_ber_sequence + control_codes = control_codes.to_ber_sequence + res = [['1.2.3', true],['1.7.9',false]].to_ber_control + res.should eq(control_codes) + end +end From b6b7985d6e42744367aafc8bb29f392ee4edf220 Mon Sep 17 00:00:00 2001 From: Chris Dwan Date: Thu, 17 Nov 2011 14:23:41 -0800 Subject: [PATCH 2/3] fixes based on comments for pull request --- lib/net/ber/core_ext/array.rb | 8 +++++--- lib/net/ber/core_ext/string.rb | 10 +++++++--- lib/net/ldap.rb | 15 ++++++++------- spec/unit/ber/core_ext/array_spec.rb | 10 ++++++++++ 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/lib/net/ber/core_ext/array.rb b/lib/net/ber/core_ext/array.rb index 71b1a5e..250fa24 100644 --- a/lib/net/ber/core_ext/array.rb +++ b/lib/net/ber/core_ext/array.rb @@ -86,9 +86,11 @@ module Net::BER::Extensions::Array # [['1.2.840.113556.1.4.805',true]] # def to_ber_control - ary = self.collect do |control_sequence| - control_sequence.collect{|element| element.to_ber}.to_ber_sequence + #if our array does not contain at least one array then wrap it in an array before going forward + ary = self[0].kind_of?(Array) ? self : [self] + ary = ary.collect do |control_sequence| + control_sequence.collect{|element| element.to_ber}.to_ber_sequence.reject_empty_ber_arrays end - ary.to_ber_sequence #putting this on a new line to make it more readable. + ary.to_ber_sequence.reject_empty_ber_arrays end end diff --git a/lib/net/ber/core_ext/string.rb b/lib/net/ber/core_ext/string.rb index 28aeedd..d52d787 100644 --- a/lib/net/ber/core_ext/string.rb +++ b/lib/net/ber/core_ext/string.rb @@ -46,15 +46,19 @@ module Net::BER::Extensions::String def read_ber(syntax = nil) StringIO.new(self).read_ber(syntax) end - + ## - # Destructively reads a BER object from the string. + # Destructively reads a BER object from the string. def read_ber!(syntax = nil) io = StringIO.new(self) result = io.read_ber(syntax) self.slice!(0...io.pos) - + return result end + + def reject_empty_ber_arrays + self.gsub(/0\000/n,'') + end end diff --git a/lib/net/ldap.rb b/lib/net/ldap.rb index e687da2..b81a9d8 100644 --- a/lib/net/ldap.rb +++ b/lib/net/ldap.rb @@ -334,8 +334,9 @@ class Net::LDAP 68 => "Entry Already Exists" } - module LdapControls - PagedResults = "1.2.840.113556.1.4.319" # Microsoft evil from RFC 2696 + module LDAPControls + PAGED_RESULTS = "1.2.840.113556.1.4.319" # Microsoft evil from RFC 2696 + DELETE_TREE = "1.2.840.113556.1.4.805" end def self.result2string(code) #:nodoc: @@ -552,7 +553,7 @@ class Net::LDAP # anything with the bind results. We then pass self to the caller's # block, where he will execute his LDAP operations. Of course they will # all generate auth failures if the bind was unsuccessful. - raise Net::LDAP::LdapError, "Open already in progress" if @open_connection + raise LdapError, "Open already in progress" if @open_connection begin @open_connection = Net::LDAP::Connection.new(:host => @host, @@ -1033,7 +1034,7 @@ class Net::LDAP # dn = "mail=deleteme@example.com, ou=people, dc=example, dc=com" # ldap.delete_tree :dn => dn def delete_tree(args) - delete(args.merge(:control_codes => [['1.2.840.113556.1.4.805',true]])) + delete(args.merge(:control_codes => [[LDAPControls::DELETE_TREE, true]])) end # This method is experimental and subject to change. Return the rootDSE # record from the LDAP server as a Net::LDAP::Entry, or an empty Entry if @@ -1105,7 +1106,7 @@ class Net::LDAP #++ def paged_searches_supported? @server_caps ||= search_root_dse - @server_caps[:supportedcontrol].include?(Net::LDAP::LdapControls::PagedResults) + @server_caps[:supportedcontrol].include?(LDAPControls::PAGED_RESULTS) end end # class LDAP @@ -1402,7 +1403,7 @@ class Net::LDAP::Connection #:nodoc: controls = [] controls << [ - Net::LDAP::LdapControls::PagedResults.to_ber, + LDAPControls::PAGED_RESULTS.to_ber, # Criticality MUST be false to interoperate with normal LDAPs. false.to_ber, rfc2696_cookie.map{ |v| v.to_ber}.to_ber_sequence.to_s.to_ber @@ -1450,7 +1451,7 @@ class Net::LDAP::Connection #:nodoc: more_pages = false if result_code == 0 and controls controls.each do |c| - if c.oid == Net::LDAP::LdapControls::PagedResults + if c.oid == LDAPControls::PAGED_RESULTS # just in case some bogus server sends us more than 1 of these. more_pages = false if c.value and c.value.length > 0 diff --git a/spec/unit/ber/core_ext/array_spec.rb b/spec/unit/ber/core_ext/array_spec.rb index 44e2bd9..c8a6b4e 100644 --- a/spec/unit/ber/core_ext/array_spec.rb +++ b/spec/unit/ber/core_ext/array_spec.rb @@ -11,4 +11,14 @@ describe Array, "when extended with BER core extensions" do res = [['1.2.3', true],['1.7.9',false]].to_ber_control res.should eq(control_codes) end + + it "should wrap the array in another array if a nested array is not passed" do + result1 = ['1.2.3', true].to_ber_control + result2 = [['1.2.3', true]].to_ber_control + result1.should eq(result2) + end + + it "should return an empty string if an empty array is passed" do + [].to_ber_control.should be_empty + end end From 58bd212918dce30030fe68897a7774e8f92aa57e Mon Sep 17 00:00:00 2001 From: Chris Dwan Date: Thu, 17 Nov 2011 14:25:00 -0800 Subject: [PATCH 3/3] remove Gemfile.lock --- .gitignore | 1 + Gemfile.lock | 38 -------------------------------------- 2 files changed, 1 insertion(+), 38 deletions(-) delete mode 100644 Gemfile.lock diff --git a/.gitignore b/.gitignore index a323762..1959fc0 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ publish/ coverage/ coverage.info .rake_tasks~ +Gemfile.lock diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index f2c7ae4..0000000 --- a/Gemfile.lock +++ /dev/null @@ -1,38 +0,0 @@ -PATH - remote: . - specs: - net-ldap (0.2.20110317223538) - -GEM - remote: http://rubygems.org/ - specs: - diff-lcs (1.1.3) - flexmock (0.9.0) - hoe (2.12.3) - rake (~> 0.8) - hoe-gemspec (1.0.0) - hoe (>= 2.2.0) - hoe-git (1.4.1) - hoe (>= 2.2.0) - metaid (1.0) - rake (0.9.2.2) - rspec (2.7.0) - rspec-core (~> 2.7.0) - rspec-expectations (~> 2.7.0) - rspec-mocks (~> 2.7.0) - rspec-core (2.7.1) - rspec-expectations (2.7.0) - diff-lcs (~> 1.1.2) - rspec-mocks (2.7.0) - -PLATFORMS - ruby - -DEPENDENCIES - flexmock (~> 0.9.0) - hoe (>= 2.9.1) - hoe-gemspec (~> 1) - hoe-git (~> 1) - metaid (~> 1) - net-ldap! - rspec (~> 2.0)