net-ldap 0.12.0 → 0.19.0
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.
- checksums.yaml +5 -5
 - data/Contributors.rdoc +1 -0
 - data/History.rdoc +112 -0
 - data/README.rdoc +19 -9
 - data/lib/net/ber/ber_parser.rb +4 -4
 - data/lib/net/ber/core_ext/array.rb +1 -1
 - data/lib/net/ber/core_ext/integer.rb +1 -1
 - data/lib/net/ber/core_ext/string.rb +1 -1
 - data/lib/net/ber/core_ext.rb +6 -6
 - data/lib/net/ber.rb +39 -9
 - data/lib/net/ldap/auth_adapter/gss_spnego.rb +9 -8
 - data/lib/net/ldap/auth_adapter/sasl.rb +6 -4
 - data/lib/net/ldap/auth_adapter/simple.rb +1 -1
 - data/lib/net/ldap/connection.rb +173 -52
 - data/lib/net/ldap/dataset.rb +3 -5
 - data/lib/net/ldap/dn.rb +21 -30
 - data/lib/net/ldap/entry.rb +15 -7
 - data/lib/net/ldap/error.rb +2 -25
 - data/lib/net/ldap/filter.rb +15 -8
 - data/lib/net/ldap/instrumentation.rb +2 -2
 - data/lib/net/ldap/password.rb +7 -5
 - data/lib/net/ldap/pdu.rb +27 -3
 - data/lib/net/ldap/version.rb +1 -1
 - data/lib/net/ldap.rb +212 -91
 - data/lib/net/snmp.rb +19 -19
 - data/lib/net-ldap.rb +1 -1
 - metadata +27 -96
 - data/.gitignore +0 -9
 - data/.rubocop.yml +0 -5
 - data/.rubocop_todo.yml +0 -462
 - data/.travis.yml +0 -31
 - data/CONTRIBUTING.md +0 -54
 - data/Gemfile +0 -2
 - data/Rakefile +0 -23
 - data/net-ldap.gemspec +0 -36
 - data/script/changelog +0 -47
 - data/script/install-openldap +0 -112
 - data/script/package +0 -7
 - data/script/release +0 -16
 - data/test/ber/core_ext/test_array.rb +0 -22
 - data/test/ber/core_ext/test_string.rb +0 -25
 - data/test/ber/test_ber.rb +0 -145
 - data/test/fixtures/cacert.pem +0 -20
 - data/test/fixtures/openldap/memberof.ldif +0 -33
 - data/test/fixtures/openldap/retcode.ldif +0 -76
 - data/test/fixtures/openldap/slapd.conf.ldif +0 -67
 - data/test/fixtures/seed.ldif +0 -374
 - data/test/integration/test_add.rb +0 -28
 - data/test/integration/test_ber.rb +0 -30
 - data/test/integration/test_bind.rb +0 -34
 - data/test/integration/test_delete.rb +0 -31
 - data/test/integration/test_open.rb +0 -88
 - data/test/integration/test_return_codes.rb +0 -38
 - data/test/integration/test_search.rb +0 -77
 - data/test/support/vm/openldap/.gitignore +0 -1
 - data/test/support/vm/openldap/README.md +0 -32
 - data/test/support/vm/openldap/Vagrantfile +0 -33
 - data/test/test_auth_adapter.rb +0 -11
 - data/test/test_dn.rb +0 -44
 - data/test/test_entry.rb +0 -65
 - data/test/test_filter.rb +0 -223
 - data/test/test_filter_parser.rb +0 -24
 - data/test/test_helper.rb +0 -66
 - data/test/test_ldap.rb +0 -67
 - data/test/test_ldap_connection.rb +0 -460
 - data/test/test_ldif.rb +0 -104
 - data/test/test_password.rb +0 -10
 - data/test/test_rename.rb +0 -77
 - data/test/test_search.rb +0 -39
 - data/test/test_snmp.rb +0 -119
 - data/test/test_ssl_ber.rb +0 -40
 - data/test/testdata.ldif +0 -101
 - data/testserver/ldapserver.rb +0 -210
 - data/testserver/testdata.ldif +0 -101
 
    
        data/lib/net/ldap/filter.rb
    CHANGED
    
    | 
         @@ -23,7 +23,7 @@ 
     | 
|
| 
       23 
23 
     | 
    
         
             
            class Net::LDAP::Filter
         
     | 
| 
       24 
24 
     | 
    
         
             
              ##
         
     | 
| 
       25 
25 
     | 
    
         
             
              # Known filter types.
         
     | 
| 
       26 
     | 
    
         
            -
              FilterTypes = [ 
     | 
| 
      
 26 
     | 
    
         
            +
              FilterTypes = [:ne, :eq, :ge, :le, :and, :or, :not, :ex, :bineq]
         
     | 
| 
       27 
27 
     | 
    
         | 
| 
       28 
28 
     | 
    
         
             
              def initialize(op, left, right) #:nodoc:
         
     | 
| 
       29 
29 
     | 
    
         
             
                unless FilterTypes.include?(op)
         
     | 
| 
         @@ -287,7 +287,7 @@ class Net::LDAP::Filter 
     | 
|
| 
       287 
287 
     | 
    
         
             
                  when 0xa4 # context-specific constructed 4, "substring"
         
     | 
| 
       288 
288 
     | 
    
         
             
                    str = ""
         
     | 
| 
       289 
289 
     | 
    
         
             
                    final = false
         
     | 
| 
       290 
     | 
    
         
            -
                    ber.last.each  
     | 
| 
      
 290 
     | 
    
         
            +
                    ber.last.each do |b|
         
     | 
| 
       291 
291 
     | 
    
         
             
                      case b.ber_identifier
         
     | 
| 
       292 
292 
     | 
    
         
             
                      when 0x80 # context-specific primitive 0, SubstringFilter "initial"
         
     | 
| 
       293 
293 
     | 
    
         
             
                        raise Net::LDAP::SubstringFilterError, "Unrecognized substring filter; bad initial value." if str.length > 0
         
     | 
| 
         @@ -298,7 +298,7 @@ class Net::LDAP::Filter 
     | 
|
| 
       298 
298 
     | 
    
         
             
                        str += "*#{escape(b)}"
         
     | 
| 
       299 
299 
     | 
    
         
             
                        final = true
         
     | 
| 
       300 
300 
     | 
    
         
             
                      end
         
     | 
| 
       301 
     | 
    
         
            -
                     
     | 
| 
      
 301 
     | 
    
         
            +
                    end
         
     | 
| 
       302 
302 
     | 
    
         
             
                    str += "*" unless final
         
     | 
| 
       303 
303 
     | 
    
         
             
                    eq(ber.first.to_s, str)
         
     | 
| 
       304 
304 
     | 
    
         
             
                  when 0xa5 # context-specific constructed 5, "greaterOrEqual"
         
     | 
| 
         @@ -490,7 +490,7 @@ class Net::LDAP::Filter 
     | 
|
| 
       490 
490 
     | 
    
         
             
                when :eq
         
     | 
| 
       491 
491 
     | 
    
         
             
                  if @right == "*" # presence test
         
     | 
| 
       492 
492 
     | 
    
         
             
                    @left.to_s.to_ber_contextspecific(7)
         
     | 
| 
       493 
     | 
    
         
            -
                  elsif @right =~ /[*]/ # substring
         
     | 
| 
      
 493 
     | 
    
         
            +
                  elsif @right.to_s =~ /[*]/ # substring
         
     | 
| 
       494 
494 
     | 
    
         
             
                    # Parsing substrings is a little tricky. We use String#split to
         
     | 
| 
       495 
495 
     | 
    
         
             
                    # break a string into substrings delimited by the * (star)
         
     | 
| 
       496 
496 
     | 
    
         
             
                    # character. But we also need to know whether there is a star at the
         
     | 
| 
         @@ -550,10 +550,10 @@ class Net::LDAP::Filter 
     | 
|
| 
       550 
550 
     | 
    
         
             
                  [self.class.eq(@left, @right).to_ber].to_ber_contextspecific(2)
         
     | 
| 
       551 
551 
     | 
    
         
             
                when :and
         
     | 
| 
       552 
552 
     | 
    
         
             
                  ary = [@left.coalesce(:and), @right.coalesce(:and)].flatten
         
     | 
| 
       553 
     | 
    
         
            -
                  ary.map 
     | 
| 
      
 553 
     | 
    
         
            +
                  ary.map(&:to_ber).to_ber_contextspecific(0)
         
     | 
| 
       554 
554 
     | 
    
         
             
                when :or
         
     | 
| 
       555 
555 
     | 
    
         
             
                  ary = [@left.coalesce(:or), @right.coalesce(:or)].flatten
         
     | 
| 
       556 
     | 
    
         
            -
                  ary.map 
     | 
| 
      
 556 
     | 
    
         
            +
                  ary.map(&:to_ber).to_ber_contextspecific(1)
         
     | 
| 
       557 
557 
     | 
    
         
             
                when :not
         
     | 
| 
       558 
558 
     | 
    
         
             
                  [@left.to_ber].to_ber_contextspecific(2)
         
     | 
| 
       559 
559 
     | 
    
         
             
                end
         
     | 
| 
         @@ -645,8 +645,15 @@ class Net::LDAP::Filter 
     | 
|
| 
       645 
645 
     | 
    
         | 
| 
       646 
646 
     | 
    
         
             
              ##
         
     | 
| 
       647 
647 
     | 
    
         
             
              # Converts escaped characters (e.g., "\\28") to unescaped characters
         
     | 
| 
      
 648 
     | 
    
         
            +
              # @note slawson20170317: Don't attempt to unescape 16 byte binary data which we assume are objectGUIDs
         
     | 
| 
      
 649 
     | 
    
         
            +
              # The binary form of 5936AE79-664F-44EA-BCCB-5C39399514C6 triggers a BINARY -> UTF-8 conversion error
         
     | 
| 
       648 
650 
     | 
    
         
             
              def unescape(right)
         
     | 
| 
       649 
     | 
    
         
            -
                right 
     | 
| 
      
 651 
     | 
    
         
            +
                right = right.to_s
         
     | 
| 
      
 652 
     | 
    
         
            +
                if right.length == 16 && right.encoding == Encoding::BINARY
         
     | 
| 
      
 653 
     | 
    
         
            +
                  right
         
     | 
| 
      
 654 
     | 
    
         
            +
                else
         
     | 
| 
      
 655 
     | 
    
         
            +
                  right.to_s.gsub(/\\([a-fA-F\d]{2})/) { [$1.hex].pack("U") }
         
     | 
| 
      
 656 
     | 
    
         
            +
                end
         
     | 
| 
       650 
657 
     | 
    
         
             
              end
         
     | 
| 
       651 
658 
     | 
    
         
             
              private :unescape
         
     | 
| 
       652 
659 
     | 
    
         | 
| 
         @@ -748,7 +755,7 @@ class Net::LDAP::Filter 
     | 
|
| 
       748 
755 
     | 
    
         
             
                # This parses a given expression inside of parentheses.
         
     | 
| 
       749 
756 
     | 
    
         
             
                def parse_filter_branch(scanner)
         
     | 
| 
       750 
757 
     | 
    
         
             
                  scanner.scan(/\s*/)
         
     | 
| 
       751 
     | 
    
         
            -
                  if token = scanner.scan(/[-\w 
     | 
| 
      
 758 
     | 
    
         
            +
                  if token = scanner.scan(/[-\w:.;]*[\w]/)
         
     | 
| 
       752 
759 
     | 
    
         
             
                    scanner.scan(/\s*/)
         
     | 
| 
       753 
760 
     | 
    
         
             
                    if op = scanner.scan(/<=|>=|!=|:=|=/)
         
     | 
| 
       754 
761 
     | 
    
         
             
                      scanner.scan(/\s*/)
         
     | 
| 
         @@ -12,8 +12,8 @@ module Net::LDAP::Instrumentation 
     | 
|
| 
       12 
12 
     | 
    
         
             
              def instrument(event, payload = {})
         
     | 
| 
       13 
13 
     | 
    
         
             
                payload = (payload || {}).dup
         
     | 
| 
       14 
14 
     | 
    
         
             
                if instrumentation_service
         
     | 
| 
       15 
     | 
    
         
            -
                  instrumentation_service.instrument(event, payload) do | 
     | 
| 
       16 
     | 
    
         
            -
                     
     | 
| 
      
 15 
     | 
    
         
            +
                  instrumentation_service.instrument(event, payload) do |instr_payload|
         
     | 
| 
      
 16 
     | 
    
         
            +
                    instr_payload[:result] = yield(instr_payload) if block_given?
         
     | 
| 
       17 
17 
     | 
    
         
             
                  end
         
     | 
| 
       18 
18 
     | 
    
         
             
                else
         
     | 
| 
       19 
19 
     | 
    
         
             
                  yield(payload) if block_given?
         
     | 
    
        data/lib/net/ldap/password.rb
    CHANGED
    
    | 
         @@ -1,5 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # -*- ruby encoding: utf-8 -*-
         
     | 
| 
       2 
2 
     | 
    
         
             
            require 'digest/sha1'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'digest/sha2'
         
     | 
| 
       3 
4 
     | 
    
         
             
            require 'digest/md5'
         
     | 
| 
       4 
5 
     | 
    
         
             
            require 'base64'
         
     | 
| 
       5 
6 
     | 
    
         
             
            require 'securerandom'
         
     | 
| 
         @@ -19,20 +20,21 @@ class Net::LDAP::Password 
     | 
|
| 
       19 
20 
     | 
    
         
             
                # * Should we provide sha1 as a synonym for sha1? I vote no because then
         
     | 
| 
       20 
21 
     | 
    
         
             
                #   should you also provide ssha1 for symmetry?
         
     | 
| 
       21 
22 
     | 
    
         
             
                #
         
     | 
| 
       22 
     | 
    
         
            -
                attribute_value = ""
         
     | 
| 
       23 
23 
     | 
    
         
             
                def generate(type, str)
         
     | 
| 
       24 
24 
     | 
    
         
             
                  case type
         
     | 
| 
       25 
25 
     | 
    
         
             
                  when :md5
         
     | 
| 
       26 
     | 
    
         
            -
                      
     | 
| 
      
 26 
     | 
    
         
            +
                     '{MD5}' + Base64.strict_encode64(Digest::MD5.digest(str))
         
     | 
| 
       27 
27 
     | 
    
         
             
                  when :sha
         
     | 
| 
       28 
     | 
    
         
            -
                      
     | 
| 
      
 28 
     | 
    
         
            +
                     '{SHA}' + Base64.strict_encode64(Digest::SHA1.digest(str))
         
     | 
| 
       29 
29 
     | 
    
         
             
                  when :ssha
         
     | 
| 
       30 
30 
     | 
    
         
             
                     salt = SecureRandom.random_bytes(16)
         
     | 
| 
       31 
     | 
    
         
            -
                      
     | 
| 
      
 31 
     | 
    
         
            +
                     '{SSHA}' + Base64.strict_encode64(Digest::SHA1.digest(str + salt) + salt)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  when :ssha256
         
     | 
| 
      
 33 
     | 
    
         
            +
                    salt = SecureRandom.random_bytes(16)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    '{SSHA256}' + Base64.strict_encode64(Digest::SHA256.digest(str + salt) + salt)
         
     | 
| 
       32 
35 
     | 
    
         
             
                  else
         
     | 
| 
       33 
36 
     | 
    
         
             
                     raise Net::LDAP::HashTypeUnsupportedError, "Unsupported password-hash type (#{type})"
         
     | 
| 
       34 
37 
     | 
    
         
             
                  end
         
     | 
| 
       35 
     | 
    
         
            -
                  return attribute_value
         
     | 
| 
       36 
38 
     | 
    
         
             
                end
         
     | 
| 
       37 
39 
     | 
    
         
             
              end
         
     | 
| 
       38 
40 
     | 
    
         
             
            end
         
     | 
    
        data/lib/net/ldap/pdu.rb
    CHANGED
    
    | 
         @@ -74,6 +74,7 @@ class Net::LDAP::PDU 
     | 
|
| 
       74 
74 
     | 
    
         
             
              attr_reader :search_referrals
         
     | 
| 
       75 
75 
     | 
    
         
             
              attr_reader :search_parameters
         
     | 
| 
       76 
76 
     | 
    
         
             
              attr_reader :bind_parameters
         
     | 
| 
      
 77 
     | 
    
         
            +
              attr_reader :extended_response
         
     | 
| 
       77 
78 
     | 
    
         | 
| 
       78 
79 
     | 
    
         
             
              ##
         
     | 
| 
       79 
80 
     | 
    
         
             
              # Returns RFC-2251 Controls if any.
         
     | 
| 
         @@ -120,9 +121,9 @@ class Net::LDAP::PDU 
     | 
|
| 
       120 
121 
     | 
    
         
             
                when UnbindRequest
         
     | 
| 
       121 
122 
     | 
    
         
             
                  parse_unbind_request(ber_object[1])
         
     | 
| 
       122 
123 
     | 
    
         
             
                when ExtendedResponse
         
     | 
| 
       123 
     | 
    
         
            -
                   
     | 
| 
      
 124 
     | 
    
         
            +
                  parse_extended_response(ber_object[1])
         
     | 
| 
       124 
125 
     | 
    
         
             
                else
         
     | 
| 
       125 
     | 
    
         
            -
                  raise  
     | 
| 
      
 126 
     | 
    
         
            +
                  raise Error.new("unknown pdu-type: #{@app_tag}")
         
     | 
| 
       126 
127 
     | 
    
         
             
                end
         
     | 
| 
       127 
128 
     | 
    
         | 
| 
       128 
129 
     | 
    
         
             
                parse_controls(ber_object[2]) if ber_object[2]
         
     | 
| 
         @@ -174,12 +175,35 @@ class Net::LDAP::PDU 
     | 
|
| 
       174 
175 
     | 
    
         
             
                @ldap_result = {
         
     | 
| 
       175 
176 
     | 
    
         
             
                  :resultCode => sequence[0],
         
     | 
| 
       176 
177 
     | 
    
         
             
                  :matchedDN => sequence[1],
         
     | 
| 
       177 
     | 
    
         
            -
                  :errorMessage => sequence[2]
         
     | 
| 
      
 178 
     | 
    
         
            +
                  :errorMessage => sequence[2],
         
     | 
| 
       178 
179 
     | 
    
         
             
                }
         
     | 
| 
       179 
180 
     | 
    
         
             
                parse_search_referral(sequence[3]) if @ldap_result[:resultCode] == Net::LDAP::ResultCodeReferral
         
     | 
| 
       180 
181 
     | 
    
         
             
              end
         
     | 
| 
       181 
182 
     | 
    
         
             
              private :parse_ldap_result
         
     | 
| 
       182 
183 
     | 
    
         | 
| 
      
 184 
     | 
    
         
            +
              ##
         
     | 
| 
      
 185 
     | 
    
         
            +
              # Parse an extended response
         
     | 
| 
      
 186 
     | 
    
         
            +
              #
         
     | 
| 
      
 187 
     | 
    
         
            +
              # http://www.ietf.org/rfc/rfc2251.txt
         
     | 
| 
      
 188 
     | 
    
         
            +
              #
         
     | 
| 
      
 189 
     | 
    
         
            +
              # Each Extended operation consists of an Extended request and an
         
     | 
| 
      
 190 
     | 
    
         
            +
              # Extended response.
         
     | 
| 
      
 191 
     | 
    
         
            +
              #
         
     | 
| 
      
 192 
     | 
    
         
            +
              #      ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
         
     | 
| 
      
 193 
     | 
    
         
            +
              #           requestName      [0] LDAPOID,
         
     | 
| 
      
 194 
     | 
    
         
            +
              #           requestValue     [1] OCTET STRING OPTIONAL }
         
     | 
| 
      
 195 
     | 
    
         
            +
             
     | 
| 
      
 196 
     | 
    
         
            +
              def parse_extended_response(sequence)
         
     | 
| 
      
 197 
     | 
    
         
            +
                sequence.length >= 3 or raise Net::LDAP::PDU::Error, "Invalid LDAP result length."
         
     | 
| 
      
 198 
     | 
    
         
            +
                @ldap_result = {
         
     | 
| 
      
 199 
     | 
    
         
            +
                  :resultCode => sequence[0],
         
     | 
| 
      
 200 
     | 
    
         
            +
                  :matchedDN => sequence[1],
         
     | 
| 
      
 201 
     | 
    
         
            +
                  :errorMessage => sequence[2],
         
     | 
| 
      
 202 
     | 
    
         
            +
                }
         
     | 
| 
      
 203 
     | 
    
         
            +
                @extended_response = sequence[3]
         
     | 
| 
      
 204 
     | 
    
         
            +
              end
         
     | 
| 
      
 205 
     | 
    
         
            +
              private :parse_extended_response
         
     | 
| 
      
 206 
     | 
    
         
            +
             
     | 
| 
       183 
207 
     | 
    
         
             
              ##
         
     | 
| 
       184 
208 
     | 
    
         
             
              # A Bind Response may have an additional field, ID [7], serverSaslCreds,
         
     | 
| 
       185 
209 
     | 
    
         
             
              # per RFC 2251 pgh 4.2.3.
         
     | 
    
        data/lib/net/ldap/version.rb
    CHANGED
    
    
    
        data/lib/net/ldap.rb
    CHANGED
    
    | 
         @@ -17,19 +17,19 @@ module Net # :nodoc: 
     | 
|
| 
       17 
17 
     | 
    
         
             
            end
         
     | 
| 
       18 
18 
     | 
    
         
             
            require 'socket'
         
     | 
| 
       19 
19 
     | 
    
         | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
      
 20 
     | 
    
         
            +
            require_relative 'ber'
         
     | 
| 
      
 21 
     | 
    
         
            +
            require_relative 'ldap/pdu'
         
     | 
| 
      
 22 
     | 
    
         
            +
            require_relative 'ldap/filter'
         
     | 
| 
      
 23 
     | 
    
         
            +
            require_relative 'ldap/dataset'
         
     | 
| 
      
 24 
     | 
    
         
            +
            require_relative 'ldap/password'
         
     | 
| 
      
 25 
     | 
    
         
            +
            require_relative 'ldap/entry'
         
     | 
| 
      
 26 
     | 
    
         
            +
            require_relative 'ldap/instrumentation'
         
     | 
| 
      
 27 
     | 
    
         
            +
            require_relative 'ldap/connection'
         
     | 
| 
      
 28 
     | 
    
         
            +
            require_relative 'ldap/version'
         
     | 
| 
      
 29 
     | 
    
         
            +
            require_relative 'ldap/error'
         
     | 
| 
      
 30 
     | 
    
         
            +
            require_relative 'ldap/auth_adapter'
         
     | 
| 
      
 31 
     | 
    
         
            +
            require_relative 'ldap/auth_adapter/simple'
         
     | 
| 
      
 32 
     | 
    
         
            +
            require_relative 'ldap/auth_adapter/sasl'
         
     | 
| 
       33 
33 
     | 
    
         | 
| 
       34 
34 
     | 
    
         
             
            Net::LDAP::AuthAdapter.register([:simple, :anon, :anonymous], Net::LDAP::AuthAdapter::Simple)
         
     | 
| 
       35 
35 
     | 
    
         
             
            Net::LDAP::AuthAdapter.register(:sasl, Net::LDAP::AuthAdapter::Sasl)
         
     | 
| 
         @@ -79,6 +79,14 @@ Net::LDAP::AuthAdapter.register(:sasl, Net::LDAP::AuthAdapter::Sasl) 
     | 
|
| 
       79 
79 
     | 
    
         
             
            #
         
     | 
| 
       80 
80 
     | 
    
         
             
            #  p ldap.get_operation_result
         
     | 
| 
       81 
81 
     | 
    
         
             
            #
         
     | 
| 
      
 82 
     | 
    
         
            +
            # === Setting connect timeout
         
     | 
| 
      
 83 
     | 
    
         
            +
            #
         
     | 
| 
      
 84 
     | 
    
         
            +
            # By default, Net::LDAP uses TCP sockets with a connection timeout of 5 seconds.
         
     | 
| 
      
 85 
     | 
    
         
            +
            #
         
     | 
| 
      
 86 
     | 
    
         
            +
            # This value can be tweaked passing the :connect_timeout parameter.
         
     | 
| 
      
 87 
     | 
    
         
            +
            # i.e.
         
     | 
| 
      
 88 
     | 
    
         
            +
            #  ldap = Net::LDAP.new ...,
         
     | 
| 
      
 89 
     | 
    
         
            +
            #                       :connect_timeout => 3
         
     | 
| 
       82 
90 
     | 
    
         
             
            #
         
     | 
| 
       83 
91 
     | 
    
         
             
            # == A Brief Introduction to LDAP
         
     | 
| 
       84 
92 
     | 
    
         
             
            #
         
     | 
| 
         @@ -256,14 +264,14 @@ class Net::LDAP 
     | 
|
| 
       256 
264 
     | 
    
         
             
              SearchScope_BaseObject = 0
         
     | 
| 
       257 
265 
     | 
    
         
             
              SearchScope_SingleLevel = 1
         
     | 
| 
       258 
266 
     | 
    
         
             
              SearchScope_WholeSubtree = 2
         
     | 
| 
       259 
     | 
    
         
            -
              SearchScopes = [ 
     | 
| 
       260 
     | 
    
         
            -
                SearchScope_WholeSubtree 
     | 
| 
      
 267 
     | 
    
         
            +
              SearchScopes = [SearchScope_BaseObject, SearchScope_SingleLevel,
         
     | 
| 
      
 268 
     | 
    
         
            +
                SearchScope_WholeSubtree]
         
     | 
| 
       261 
269 
     | 
    
         | 
| 
       262 
270 
     | 
    
         
             
              DerefAliases_Never = 0
         
     | 
| 
       263 
271 
     | 
    
         
             
              DerefAliases_Search = 1
         
     | 
| 
       264 
272 
     | 
    
         
             
              DerefAliases_Find = 2
         
     | 
| 
       265 
273 
     | 
    
         
             
              DerefAliases_Always = 3
         
     | 
| 
       266 
     | 
    
         
            -
              DerefAliasesArray = [ 
     | 
| 
      
 274 
     | 
    
         
            +
              DerefAliasesArray = [DerefAliases_Never, DerefAliases_Search, DerefAliases_Find, DerefAliases_Always]
         
     | 
| 
       267 
275 
     | 
    
         | 
| 
       268 
276 
     | 
    
         
             
              primitive = { 2 => :null } # UnbindRequest body
         
     | 
| 
       269 
277 
     | 
    
         
             
              constructed = {
         
     | 
| 
         @@ -315,7 +323,14 @@ class Net::LDAP 
     | 
|
| 
       315 
323 
     | 
    
         
             
                :constructed => constructed,
         
     | 
| 
       316 
324 
     | 
    
         
             
              }
         
     | 
| 
       317 
325 
     | 
    
         | 
| 
      
 326 
     | 
    
         
            +
              universal = {
         
     | 
| 
      
 327 
     | 
    
         
            +
                constructed: {
         
     | 
| 
      
 328 
     | 
    
         
            +
                  107 => :array, #ExtendedResponse (PasswdModifyResponseValue)
         
     | 
| 
      
 329 
     | 
    
         
            +
                },
         
     | 
| 
      
 330 
     | 
    
         
            +
              }
         
     | 
| 
      
 331 
     | 
    
         
            +
             
     | 
| 
       318 
332 
     | 
    
         
             
              AsnSyntax = Net::BER.compile_syntax(:application => application,
         
     | 
| 
      
 333 
     | 
    
         
            +
                                                  :universal => universal,
         
     | 
| 
       319 
334 
     | 
    
         
             
                                                  :context_specific => context_specific)
         
     | 
| 
       320 
335 
     | 
    
         | 
| 
       321 
336 
     | 
    
         
             
              DefaultHost = "127.0.0.1"
         
     | 
| 
         @@ -324,7 +339,8 @@ class Net::LDAP 
     | 
|
| 
       324 
339 
     | 
    
         
             
              DefaultTreebase = "dc=com"
         
     | 
| 
       325 
340 
     | 
    
         
             
              DefaultForceNoPage = false
         
     | 
| 
       326 
341 
     | 
    
         | 
| 
       327 
     | 
    
         
            -
              StartTlsOid =  
     | 
| 
      
 342 
     | 
    
         
            +
              StartTlsOid = '1.3.6.1.4.1.1466.20037'
         
     | 
| 
      
 343 
     | 
    
         
            +
              PasswdModifyOid = '1.3.6.1.4.1.4203.1.11.1'
         
     | 
| 
       328 
344 
     | 
    
         | 
| 
       329 
345 
     | 
    
         
             
              # https://tools.ietf.org/html/rfc4511#section-4.1.9
         
     | 
| 
       330 
346 
     | 
    
         
             
              # https://tools.ietf.org/html/rfc4511#appendix-A
         
     | 
| 
         @@ -373,14 +389,14 @@ class Net::LDAP 
     | 
|
| 
       373 
389 
     | 
    
         
             
                ResultCodeCompareFalse,
         
     | 
| 
       374 
390 
     | 
    
         
             
                ResultCodeCompareTrue,
         
     | 
| 
       375 
391 
     | 
    
         
             
                ResultCodeReferral,
         
     | 
| 
       376 
     | 
    
         
            -
                ResultCodeSaslBindInProgress
         
     | 
| 
      
 392 
     | 
    
         
            +
                ResultCodeSaslBindInProgress,
         
     | 
| 
       377 
393 
     | 
    
         
             
              ]
         
     | 
| 
       378 
394 
     | 
    
         | 
| 
       379 
395 
     | 
    
         
             
              # nonstandard list of "successful" result codes for searches
         
     | 
| 
       380 
396 
     | 
    
         
             
              ResultCodesSearchSuccess = [
         
     | 
| 
       381 
397 
     | 
    
         
             
                ResultCodeSuccess,
         
     | 
| 
       382 
398 
     | 
    
         
             
                ResultCodeTimeLimitExceeded,
         
     | 
| 
       383 
     | 
    
         
            -
                ResultCodeSizeLimitExceeded
         
     | 
| 
      
 399 
     | 
    
         
            +
                ResultCodeSizeLimitExceeded,
         
     | 
| 
       384 
400 
     | 
    
         
             
              ]
         
     | 
| 
       385 
401 
     | 
    
         | 
| 
       386 
402 
     | 
    
         
             
              # map of result code to human message
         
     | 
| 
         @@ -396,7 +412,7 @@ class Net::LDAP 
     | 
|
| 
       396 
412 
     | 
    
         
             
                ResultCodeStrongerAuthRequired         => "Stronger Auth Needed",
         
     | 
| 
       397 
413 
     | 
    
         
             
                ResultCodeReferral                     => "Referral",
         
     | 
| 
       398 
414 
     | 
    
         
             
                ResultCodeAdminLimitExceeded           => "Admin Limit Exceeded",
         
     | 
| 
       399 
     | 
    
         
            -
                ResultCodeUnavailableCriticalExtension => "Unavailable  
     | 
| 
      
 415 
     | 
    
         
            +
                ResultCodeUnavailableCriticalExtension => "Unavailable critical extension",
         
     | 
| 
       400 
416 
     | 
    
         
             
                ResultCodeConfidentialityRequired      => "Confidentiality Required",
         
     | 
| 
       401 
417 
     | 
    
         
             
                ResultCodeSaslBindInProgress           => "saslBindInProgress",
         
     | 
| 
       402 
418 
     | 
    
         
             
                ResultCodeNoSuchAttribute              => "No Such Attribute",
         
     | 
| 
         @@ -422,7 +438,7 @@ class Net::LDAP 
     | 
|
| 
       422 
438 
     | 
    
         
             
                ResultCodeEntryAlreadyExists           => "Entry Already Exists",
         
     | 
| 
       423 
439 
     | 
    
         
             
                ResultCodeObjectClassModsProhibited    => "ObjectClass Modifications Prohibited",
         
     | 
| 
       424 
440 
     | 
    
         
             
                ResultCodeAffectsMultipleDSAs          => "Affects Multiple DSAs",
         
     | 
| 
       425 
     | 
    
         
            -
                ResultCodeOther                        => "Other"
         
     | 
| 
      
 441 
     | 
    
         
            +
                ResultCodeOther                        => "Other",
         
     | 
| 
       426 
442 
     | 
    
         
             
              }
         
     | 
| 
       427 
443 
     | 
    
         | 
| 
       428 
444 
     | 
    
         
             
              module LDAPControls
         
     | 
| 
         @@ -460,20 +476,75 @@ class Net::LDAP 
     | 
|
| 
       460 
476 
     | 
    
         
             
              #   specify a treebase. If you give a treebase value in any particular
         
     | 
| 
       461 
477 
     | 
    
         
             
              #   call to #search, that value will override any treebase value you give
         
     | 
| 
       462 
478 
     | 
    
         
             
              #   here.
         
     | 
| 
       463 
     | 
    
         
            -
              # * :encryption => specifies the encryption to be used in communicating
         
     | 
| 
       464 
     | 
    
         
            -
              #   with the LDAP server. The value is either a Hash containing additional
         
     | 
| 
       465 
     | 
    
         
            -
              #   parameters, or the Symbol :simple_tls, which is equivalent to
         
     | 
| 
       466 
     | 
    
         
            -
              #   specifying the Hash {:method => :simple_tls}. There is a fairly large
         
     | 
| 
       467 
     | 
    
         
            -
              #   range of potential values that may be given for this parameter. See
         
     | 
| 
       468 
     | 
    
         
            -
              #   #encryption for details.
         
     | 
| 
       469 
479 
     | 
    
         
             
              # * :force_no_page => Set to true to prevent paged results even if your
         
     | 
| 
       470 
480 
     | 
    
         
             
              #   server says it supports them. This is a fix for MS Active Directory
         
     | 
| 
       471 
481 
     | 
    
         
             
              # * :instrumentation_service => An object responsible for instrumenting
         
     | 
| 
       472 
482 
     | 
    
         
             
              #   operations, compatible with ActiveSupport::Notifications' public API.
         
     | 
| 
      
 483 
     | 
    
         
            +
              # * :connect_timeout => The TCP socket timeout (in seconds) to use when
         
     | 
| 
      
 484 
     | 
    
         
            +
              #   connecting to the LDAP server (default 5 seconds).
         
     | 
| 
      
 485 
     | 
    
         
            +
              # * :encryption => specifies the encryption to be used in communicating
         
     | 
| 
      
 486 
     | 
    
         
            +
              #   with the LDAP server. The value must be a Hash containing additional
         
     | 
| 
      
 487 
     | 
    
         
            +
              #   parameters, which consists of two keys:
         
     | 
| 
      
 488 
     | 
    
         
            +
              #     method: - :simple_tls or :start_tls
         
     | 
| 
      
 489 
     | 
    
         
            +
              #     tls_options: - Hash of options for that method
         
     | 
| 
      
 490 
     | 
    
         
            +
              #   The :simple_tls encryption method encrypts <i>all</i> communications
         
     | 
| 
      
 491 
     | 
    
         
            +
              #   with the LDAP server. It completely establishes SSL/TLS encryption with
         
     | 
| 
      
 492 
     | 
    
         
            +
              #   the LDAP server before any LDAP-protocol data is exchanged. There is no
         
     | 
| 
      
 493 
     | 
    
         
            +
              #   plaintext negotiation and no special encryption-request controls are
         
     | 
| 
      
 494 
     | 
    
         
            +
              #   sent to the server. <i>The :simple_tls option is the simplest, easiest
         
     | 
| 
      
 495 
     | 
    
         
            +
              #   way to encrypt communications between Net::LDAP and LDAP servers.</i>
         
     | 
| 
      
 496 
     | 
    
         
            +
              #   If you get communications or protocol errors when using this option,
         
     | 
| 
      
 497 
     | 
    
         
            +
              #   check with your LDAP server administrator. Pay particular attention
         
     | 
| 
      
 498 
     | 
    
         
            +
              #   to the TCP port you are connecting to. It's impossible for an LDAP
         
     | 
| 
      
 499 
     | 
    
         
            +
              #   server to support plaintext LDAP communications and <i>simple TLS</i>
         
     | 
| 
      
 500 
     | 
    
         
            +
              #   connections on the same port. The standard TCP port for unencrypted
         
     | 
| 
      
 501 
     | 
    
         
            +
              #   LDAP connections is 389, but the standard port for simple-TLS
         
     | 
| 
      
 502 
     | 
    
         
            +
              #   encrypted connections is 636. Be sure you are using the correct port.
         
     | 
| 
      
 503 
     | 
    
         
            +
              #   The :start_tls like the :simple_tls encryption method also encrypts all
         
     | 
| 
      
 504 
     | 
    
         
            +
              #   communcations with the LDAP server. With the exception that it operates
         
     | 
| 
      
 505 
     | 
    
         
            +
              #   over the standard TCP port.
         
     | 
| 
      
 506 
     | 
    
         
            +
              #
         
     | 
| 
      
 507 
     | 
    
         
            +
              #   To validate the LDAP server's certificate (a security must if you're
         
     | 
| 
      
 508 
     | 
    
         
            +
              #   talking over the public internet), you need to set :tls_options
         
     | 
| 
      
 509 
     | 
    
         
            +
              #   something like this...
         
     | 
| 
      
 510 
     | 
    
         
            +
              #
         
     | 
| 
      
 511 
     | 
    
         
            +
              #   Net::LDAP.new(
         
     | 
| 
      
 512 
     | 
    
         
            +
              #     # ... set host, bind dn, etc ...
         
     | 
| 
      
 513 
     | 
    
         
            +
              #     encryption: {
         
     | 
| 
      
 514 
     | 
    
         
            +
              #       method: :simple_tls,
         
     | 
| 
      
 515 
     | 
    
         
            +
              #       tls_options: OpenSSL::SSL::SSLContext::DEFAULT_PARAMS,
         
     | 
| 
      
 516 
     | 
    
         
            +
              #     }
         
     | 
| 
      
 517 
     | 
    
         
            +
              #   )
         
     | 
| 
      
 518 
     | 
    
         
            +
              #
         
     | 
| 
      
 519 
     | 
    
         
            +
              #   The above will use the operating system-provided store of CA
         
     | 
| 
      
 520 
     | 
    
         
            +
              #   certificates to validate your LDAP server's cert.
         
     | 
| 
      
 521 
     | 
    
         
            +
              #   If cert validation fails, it'll happen during the #bind
         
     | 
| 
      
 522 
     | 
    
         
            +
              #   whenever you first try to open a connection to the server.
         
     | 
| 
      
 523 
     | 
    
         
            +
              #   Those methods will throw Net::LDAP::ConnectionError with
         
     | 
| 
      
 524 
     | 
    
         
            +
              #   a message about certificate verify failing. If your
         
     | 
| 
      
 525 
     | 
    
         
            +
              #   LDAP server's certificate is signed by DigiCert, Comodo, etc.,
         
     | 
| 
      
 526 
     | 
    
         
            +
              #   you're probably good. If you've got a self-signed cert but it's
         
     | 
| 
      
 527 
     | 
    
         
            +
              #   been added to the host's OS-maintained CA store (e.g. on Debian
         
     | 
| 
      
 528 
     | 
    
         
            +
              #   add foobar.crt to /usr/local/share/ca-certificates/ and run
         
     | 
| 
      
 529 
     | 
    
         
            +
              #   `update-ca-certificates`), then the cert should pass validation.
         
     | 
| 
      
 530 
     | 
    
         
            +
              #   To ignore the OS's CA store, put your CA in a PEM-encoded file and...
         
     | 
| 
      
 531 
     | 
    
         
            +
              #
         
     | 
| 
      
 532 
     | 
    
         
            +
              #   encryption: {
         
     | 
| 
      
 533 
     | 
    
         
            +
              #     method:      :simple_tls,
         
     | 
| 
      
 534 
     | 
    
         
            +
              #     tls_options: { ca_file:     '/path/to/my-little-ca.pem',
         
     | 
| 
      
 535 
     | 
    
         
            +
              #                    ssl_version: 'TLSv1_1' },
         
     | 
| 
      
 536 
     | 
    
         
            +
              #   }
         
     | 
| 
      
 537 
     | 
    
         
            +
              #
         
     | 
| 
      
 538 
     | 
    
         
            +
              #   As you might guess, the above example also fails the connection
         
     | 
| 
      
 539 
     | 
    
         
            +
              #   if the client can't negotiate TLS v1.1.
         
     | 
| 
      
 540 
     | 
    
         
            +
              #   tls_options is ultimately passed to OpenSSL::SSL::SSLContext#set_params
         
     | 
| 
      
 541 
     | 
    
         
            +
              #   For more details, see
         
     | 
| 
      
 542 
     | 
    
         
            +
              #    http://ruby-doc.org/stdlib-2.0.0/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html
         
     | 
| 
       473 
543 
     | 
    
         
             
              #
         
     | 
| 
       474 
544 
     | 
    
         
             
              # Instantiating a Net::LDAP object does <i>not</i> result in network
         
     | 
| 
       475 
545 
     | 
    
         
             
              # traffic to the LDAP server. It simply stores the connection and binding
         
     | 
| 
       476 
     | 
    
         
            -
              # parameters in the object.
         
     | 
| 
      
 546 
     | 
    
         
            +
              # parameters in the object. That's why Net::LDAP.new doesn't throw
         
     | 
| 
      
 547 
     | 
    
         
            +
              # cert validation errors itself; #bind does instead.
         
     | 
| 
       477 
548 
     | 
    
         
             
              def initialize(args = {})
         
     | 
| 
       478 
549 
     | 
    
         
             
                @host = args[:host] || DefaultHost
         
     | 
| 
       479 
550 
     | 
    
         
             
                @port = args[:port] || DefaultPort
         
     | 
| 
         @@ -482,7 +553,8 @@ class Net::LDAP 
     | 
|
| 
       482 
553 
     | 
    
         
             
                @auth = args[:auth] || DefaultAuth
         
     | 
| 
       483 
554 
     | 
    
         
             
                @base = args[:base] || DefaultTreebase
         
     | 
| 
       484 
555 
     | 
    
         
             
                @force_no_page = args[:force_no_page] || DefaultForceNoPage
         
     | 
| 
       485 
     | 
    
         
            -
                encryption args[:encryption] # may be nil
         
     | 
| 
      
 556 
     | 
    
         
            +
                @encryption = normalize_encryption(args[:encryption]) # may be nil
         
     | 
| 
      
 557 
     | 
    
         
            +
                @connect_timeout = args[:connect_timeout]
         
     | 
| 
       486 
558 
     | 
    
         | 
| 
       487 
559 
     | 
    
         
             
                if pr = @auth[:password] and pr.respond_to?(:call)
         
     | 
| 
       488 
560 
     | 
    
         
             
                  @auth[:password] = pr.call
         
     | 
| 
         @@ -533,7 +605,7 @@ class Net::LDAP 
     | 
|
| 
       533 
605 
     | 
    
         
             
                @auth = {
         
     | 
| 
       534 
606 
     | 
    
         
             
                  :method => :simple,
         
     | 
| 
       535 
607 
     | 
    
         
             
                  :username => username,
         
     | 
| 
       536 
     | 
    
         
            -
                  :password => password
         
     | 
| 
      
 608 
     | 
    
         
            +
                  :password => password,
         
     | 
| 
       537 
609 
     | 
    
         
             
                }
         
     | 
| 
       538 
610 
     | 
    
         
             
              end
         
     | 
| 
       539 
611 
     | 
    
         
             
              alias_method :auth, :authenticate
         
     | 
| 
         @@ -546,54 +618,12 @@ class Net::LDAP 
     | 
|
| 
       546 
618 
     | 
    
         
             
              # additional capabilities are added, more configuration values will be
         
     | 
| 
       547 
619 
     | 
    
         
             
              # added here.
         
     | 
| 
       548 
620 
     | 
    
         
             
              #
         
     | 
| 
       549 
     | 
    
         
            -
              #  
     | 
| 
       550 
     | 
    
         
            -
              # with the LDAP server. It completely establishes SSL/TLS encryption with
         
     | 
| 
       551 
     | 
    
         
            -
              # the LDAP server before any LDAP-protocol data is exchanged. There is no
         
     | 
| 
       552 
     | 
    
         
            -
              # plaintext negotiation and no special encryption-request controls are
         
     | 
| 
       553 
     | 
    
         
            -
              # sent to the server. <i>The :simple_tls option is the simplest, easiest
         
     | 
| 
       554 
     | 
    
         
            -
              # way to encrypt communications between Net::LDAP and LDAP servers.</i>
         
     | 
| 
       555 
     | 
    
         
            -
              # It's intended for cases where you have an implicit level of trust in the
         
     | 
| 
       556 
     | 
    
         
            -
              # authenticity of the LDAP server. No validation of the LDAP server's SSL
         
     | 
| 
       557 
     | 
    
         
            -
              # certificate is performed. This means that :simple_tls will not produce
         
     | 
| 
       558 
     | 
    
         
            -
              # errors if the LDAP server's encryption certificate is not signed by a
         
     | 
| 
       559 
     | 
    
         
            -
              # well-known Certification Authority. If you get communications or
         
     | 
| 
       560 
     | 
    
         
            -
              # protocol errors when using this option, check with your LDAP server
         
     | 
| 
       561 
     | 
    
         
            -
              # administrator. Pay particular attention to the TCP port you are
         
     | 
| 
       562 
     | 
    
         
            -
              # connecting to. It's impossible for an LDAP server to support plaintext
         
     | 
| 
       563 
     | 
    
         
            -
              # LDAP communications and <i>simple TLS</i> connections on the same port.
         
     | 
| 
       564 
     | 
    
         
            -
              # The standard TCP port for unencrypted LDAP connections is 389, but the
         
     | 
| 
       565 
     | 
    
         
            -
              # standard port for simple-TLS encrypted connections is 636. Be sure you
         
     | 
| 
       566 
     | 
    
         
            -
              # are using the correct port.
         
     | 
| 
       567 
     | 
    
         
            -
              #
         
     | 
| 
       568 
     | 
    
         
            -
              # The :start_tls like the :simple_tls encryption method also encrypts all
         
     | 
| 
       569 
     | 
    
         
            -
              # communcations with the LDAP server. With the exception that it operates
         
     | 
| 
       570 
     | 
    
         
            -
              # over the standard TCP port.
         
     | 
| 
       571 
     | 
    
         
            -
              #
         
     | 
| 
       572 
     | 
    
         
            -
              # In order to verify certificates and enable other TLS options, the
         
     | 
| 
       573 
     | 
    
         
            -
              # :tls_options hash can be passed alongside :simple_tls or :start_tls.
         
     | 
| 
       574 
     | 
    
         
            -
              # This hash contains any options that can be passed to
         
     | 
| 
       575 
     | 
    
         
            -
              # OpenSSL::SSL::SSLContext#set_params(). The most common options passed
         
     | 
| 
       576 
     | 
    
         
            -
              # should be OpenSSL::SSL::SSLContext::DEFAULT_PARAMS, or the :ca_file option,
         
     | 
| 
       577 
     | 
    
         
            -
              # which contains a path to a Certificate Authority file (PEM-encoded).
         
     | 
| 
       578 
     | 
    
         
            -
              #
         
     | 
| 
       579 
     | 
    
         
            -
              # Example for a default setup without custom settings:
         
     | 
| 
       580 
     | 
    
         
            -
              #   {
         
     | 
| 
       581 
     | 
    
         
            -
              #     :method => :simple_tls,
         
     | 
| 
       582 
     | 
    
         
            -
              #     :tls_options => OpenSSL::SSL::SSLContext::DEFAULT_PARAMS
         
     | 
| 
       583 
     | 
    
         
            -
              #   }
         
     | 
| 
       584 
     | 
    
         
            -
              #
         
     | 
| 
       585 
     | 
    
         
            -
              # Example for specifying a CA-File and only allowing TLSv1.1 connections:
         
     | 
| 
      
 621 
     | 
    
         
            +
              # This method is deprecated.
         
     | 
| 
       586 
622 
     | 
    
         
             
              #
         
     | 
| 
       587 
     | 
    
         
            -
              #   {
         
     | 
| 
       588 
     | 
    
         
            -
              #     :method => :start_tls,
         
     | 
| 
       589 
     | 
    
         
            -
              #     :tls_options => { :ca_file => "/etc/cafile.pem", :ssl_version => "TLSv1_1" }
         
     | 
| 
       590 
     | 
    
         
            -
              #   }
         
     | 
| 
       591 
623 
     | 
    
         
             
              def encryption(args)
         
     | 
| 
       592 
     | 
    
         
            -
                 
     | 
| 
       593 
     | 
    
         
            -
                 
     | 
| 
       594 
     | 
    
         
            -
             
     | 
| 
       595 
     | 
    
         
            -
                end
         
     | 
| 
       596 
     | 
    
         
            -
                @encryption = args
         
     | 
| 
      
 624 
     | 
    
         
            +
                warn "Deprecation warning: please give :encryption option as a Hash to Net::LDAP.new"
         
     | 
| 
      
 625 
     | 
    
         
            +
                return if args.nil?
         
     | 
| 
      
 626 
     | 
    
         
            +
                @encryption = normalize_encryption(args)
         
     | 
| 
       597 
627 
     | 
    
         
             
              end
         
     | 
| 
       598 
628 
     | 
    
         | 
| 
       599 
629 
     | 
    
         
             
              # #open takes the same parameters as #new. #open makes a network
         
     | 
| 
         @@ -637,8 +667,11 @@ class Net::LDAP 
     | 
|
| 
       637 
667 
     | 
    
         
             
              #++
         
     | 
| 
       638 
668 
     | 
    
         
             
              def get_operation_result
         
     | 
| 
       639 
669 
     | 
    
         
             
                result = @result
         
     | 
| 
       640 
     | 
    
         
            -
                result = result.result if result.is_a?(Net::LDAP::PDU)
         
     | 
| 
       641 
670 
     | 
    
         
             
                os = OpenStruct.new
         
     | 
| 
      
 671 
     | 
    
         
            +
                if result.is_a?(Net::LDAP::PDU)
         
     | 
| 
      
 672 
     | 
    
         
            +
                  os.extended_response = result.extended_response
         
     | 
| 
      
 673 
     | 
    
         
            +
                  result = result.result
         
     | 
| 
      
 674 
     | 
    
         
            +
                end
         
     | 
| 
       642 
675 
     | 
    
         
             
                if result.is_a?(Hash)
         
     | 
| 
       643 
676 
     | 
    
         
             
                  # We might get a hash of LDAP response codes instead of a simple
         
     | 
| 
       644 
677 
     | 
    
         
             
                  # numeric code.
         
     | 
| 
         @@ -681,7 +714,7 @@ class Net::LDAP 
     | 
|
| 
       681 
714 
     | 
    
         
             
                  begin
         
     | 
| 
       682 
715 
     | 
    
         
             
                    @open_connection = new_connection
         
     | 
| 
       683 
716 
     | 
    
         
             
                    payload[:connection] = @open_connection
         
     | 
| 
       684 
     | 
    
         
            -
                    payload[:bind]       = @open_connection.bind(@auth)
         
     | 
| 
      
 717 
     | 
    
         
            +
                    payload[:bind]       = @result = @open_connection.bind(@auth)
         
     | 
| 
       685 
718 
     | 
    
         
             
                    yield self
         
     | 
| 
       686 
719 
     | 
    
         
             
                  ensure
         
     | 
| 
       687 
720 
     | 
    
         
             
                    @open_connection.close if @open_connection
         
     | 
| 
         @@ -750,10 +783,10 @@ class Net::LDAP 
     | 
|
| 
       750 
783 
     | 
    
         | 
| 
       751 
784 
     | 
    
         
             
                instrument "search.net_ldap", args do |payload|
         
     | 
| 
       752 
785 
     | 
    
         
             
                  @result = use_connection(args) do |conn|
         
     | 
| 
       753 
     | 
    
         
            -
                    conn.search(args)  
     | 
| 
      
 786 
     | 
    
         
            +
                    conn.search(args) do |entry|
         
     | 
| 
       754 
787 
     | 
    
         
             
                      result_set << entry if result_set
         
     | 
| 
       755 
788 
     | 
    
         
             
                      yield entry if block_given?
         
     | 
| 
       756 
     | 
    
         
            -
                     
     | 
| 
      
 789 
     | 
    
         
            +
                    end
         
     | 
| 
       757 
790 
     | 
    
         
             
                  end
         
     | 
| 
       758 
791 
     | 
    
         | 
| 
       759 
792 
     | 
    
         
             
                  if return_result_set
         
     | 
| 
         @@ -892,7 +925,7 @@ class Net::LDAP 
     | 
|
| 
       892 
925 
     | 
    
         
             
              #  end
         
     | 
| 
       893 
926 
     | 
    
         
             
              def bind_as(args = {})
         
     | 
| 
       894 
927 
     | 
    
         
             
                result = false
         
     | 
| 
       895 
     | 
    
         
            -
                open  
     | 
| 
      
 928 
     | 
    
         
            +
                open do |me|
         
     | 
| 
       896 
929 
     | 
    
         
             
                  rs = search args
         
     | 
| 
       897 
930 
     | 
    
         
             
                  if rs and rs.first and dn = rs.first.dn
         
     | 
| 
       898 
931 
     | 
    
         
             
                    password = args[:password]
         
     | 
| 
         @@ -900,7 +933,7 @@ class Net::LDAP 
     | 
|
| 
       900 
933 
     | 
    
         
             
                    result = rs if bind(:method => :simple, :username => dn,
         
     | 
| 
       901 
934 
     | 
    
         
             
                                        :password => password)
         
     | 
| 
       902 
935 
     | 
    
         
             
                  end
         
     | 
| 
       903 
     | 
    
         
            -
                 
     | 
| 
      
 936 
     | 
    
         
            +
                end
         
     | 
| 
       904 
937 
     | 
    
         
             
                result
         
     | 
| 
       905 
938 
     | 
    
         
             
              end
         
     | 
| 
       906 
939 
     | 
    
         | 
| 
         @@ -1027,6 +1060,44 @@ class Net::LDAP 
     | 
|
| 
       1027 
1060 
     | 
    
         
             
                end
         
     | 
| 
       1028 
1061 
     | 
    
         
             
              end
         
     | 
| 
       1029 
1062 
     | 
    
         | 
| 
      
 1063 
     | 
    
         
            +
              # Password Modify
         
     | 
| 
      
 1064 
     | 
    
         
            +
              #
         
     | 
| 
      
 1065 
     | 
    
         
            +
              # Change existing password:
         
     | 
| 
      
 1066 
     | 
    
         
            +
              #
         
     | 
| 
      
 1067 
     | 
    
         
            +
              #  dn = 'uid=modify-password-user1,ou=People,dc=rubyldap,dc=com'
         
     | 
| 
      
 1068 
     | 
    
         
            +
              #  auth = {
         
     | 
| 
      
 1069 
     | 
    
         
            +
              #    method: :simple,
         
     | 
| 
      
 1070 
     | 
    
         
            +
              #    username: dn,
         
     | 
| 
      
 1071 
     | 
    
         
            +
              #    password: 'passworD1'
         
     | 
| 
      
 1072 
     | 
    
         
            +
              #  }
         
     | 
| 
      
 1073 
     | 
    
         
            +
              #  ldap.password_modify(dn: dn,
         
     | 
| 
      
 1074 
     | 
    
         
            +
              #                       auth: auth,
         
     | 
| 
      
 1075 
     | 
    
         
            +
              #                       old_password: 'passworD1',
         
     | 
| 
      
 1076 
     | 
    
         
            +
              #                       new_password: 'passworD2')
         
     | 
| 
      
 1077 
     | 
    
         
            +
              #
         
     | 
| 
      
 1078 
     | 
    
         
            +
              # Or get the LDAP server to generate a password for you:
         
     | 
| 
      
 1079 
     | 
    
         
            +
              #
         
     | 
| 
      
 1080 
     | 
    
         
            +
              #  dn = 'uid=modify-password-user1,ou=People,dc=rubyldap,dc=com'
         
     | 
| 
      
 1081 
     | 
    
         
            +
              #  auth = {
         
     | 
| 
      
 1082 
     | 
    
         
            +
              #    method: :simple,
         
     | 
| 
      
 1083 
     | 
    
         
            +
              #    username: dn,
         
     | 
| 
      
 1084 
     | 
    
         
            +
              #    password: 'passworD1'
         
     | 
| 
      
 1085 
     | 
    
         
            +
              #  }
         
     | 
| 
      
 1086 
     | 
    
         
            +
              #  ldap.password_modify(dn: dn,
         
     | 
| 
      
 1087 
     | 
    
         
            +
              #                       auth: auth,
         
     | 
| 
      
 1088 
     | 
    
         
            +
              #                       old_password: 'passworD1')
         
     | 
| 
      
 1089 
     | 
    
         
            +
              #
         
     | 
| 
      
 1090 
     | 
    
         
            +
              #  ldap.get_operation_result.extended_response[0][0] #=> 'VtcgGf/G'
         
     | 
| 
      
 1091 
     | 
    
         
            +
              #
         
     | 
| 
      
 1092 
     | 
    
         
            +
              def password_modify(args)
         
     | 
| 
      
 1093 
     | 
    
         
            +
                instrument "modify_password.net_ldap", args do |payload|
         
     | 
| 
      
 1094 
     | 
    
         
            +
                  @result = use_connection(args) do |conn|
         
     | 
| 
      
 1095 
     | 
    
         
            +
                    conn.password_modify(args)
         
     | 
| 
      
 1096 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1097 
     | 
    
         
            +
                  @result.success?
         
     | 
| 
      
 1098 
     | 
    
         
            +
                end
         
     | 
| 
      
 1099 
     | 
    
         
            +
              end
         
     | 
| 
      
 1100 
     | 
    
         
            +
             
     | 
| 
       1030 
1101 
     | 
    
         
             
              # Add a value to an attribute. Takes the full DN of the entry to modify,
         
     | 
| 
       1031 
1102 
     | 
    
         
             
              # the name (Symbol or String) of the attribute, and the value (String or
         
     | 
| 
       1032 
1103 
     | 
    
         
             
              # Array). If the attribute does not exist (and there are no schema
         
     | 
| 
         @@ -1113,14 +1184,22 @@ class Net::LDAP 
     | 
|
| 
       1113 
1184 
     | 
    
         
             
              # entries. This method sends an extra control code to tell the LDAP server
         
     | 
| 
       1114 
1185 
     | 
    
         
             
              # to do a tree delete. ('1.2.840.113556.1.4.805')
         
     | 
| 
       1115 
1186 
     | 
    
         
             
              #
         
     | 
| 
      
 1187 
     | 
    
         
            +
              # If the LDAP server does not support the DELETE_TREE control code, subordinate
         
     | 
| 
      
 1188 
     | 
    
         
            +
              # entries are deleted recursively instead.
         
     | 
| 
      
 1189 
     | 
    
         
            +
              #
         
     | 
| 
       1116 
1190 
     | 
    
         
             
              # Returns True or False to indicate whether the delete succeeded. Extended
         
     | 
| 
       1117 
1191 
     | 
    
         
             
              # status information is available by calling #get_operation_result.
         
     | 
| 
       1118 
1192 
     | 
    
         
             
              #
         
     | 
| 
       1119 
1193 
     | 
    
         
             
              #  dn = "mail=deleteme@example.com, ou=people, dc=example, dc=com"
         
     | 
| 
       1120 
1194 
     | 
    
         
             
              #  ldap.delete_tree :dn => dn
         
     | 
| 
       1121 
1195 
     | 
    
         
             
              def delete_tree(args)
         
     | 
| 
       1122 
     | 
    
         
            -
                 
     | 
| 
      
 1196 
     | 
    
         
            +
                if search_root_dse[:supportedcontrol].include? Net::LDAP::LDAPControls::DELETE_TREE
         
     | 
| 
      
 1197 
     | 
    
         
            +
                  delete(args.merge(:control_codes => [[Net::LDAP::LDAPControls::DELETE_TREE, true]]))
         
     | 
| 
      
 1198 
     | 
    
         
            +
                else
         
     | 
| 
      
 1199 
     | 
    
         
            +
                  recursive_delete(args)
         
     | 
| 
      
 1200 
     | 
    
         
            +
                end
         
     | 
| 
       1123 
1201 
     | 
    
         
             
              end
         
     | 
| 
      
 1202 
     | 
    
         
            +
             
     | 
| 
       1124 
1203 
     | 
    
         
             
              # This method is experimental and subject to change. Return the rootDSE
         
     | 
| 
       1125 
1204 
     | 
    
         
             
              # record from the LDAP server as a Net::LDAP::Entry, or an empty Entry if
         
     | 
| 
       1126 
1205 
     | 
    
         
             
              # the server doesn't return the record.
         
     | 
| 
         @@ -1145,7 +1224,7 @@ class Net::LDAP 
     | 
|
| 
       1145 
1224 
     | 
    
         
             
                              :supportedExtension,
         
     | 
| 
       1146 
1225 
     | 
    
         
             
                              :supportedFeatures,
         
     | 
| 
       1147 
1226 
     | 
    
         
             
                              :supportedLdapVersion,
         
     | 
| 
       1148 
     | 
    
         
            -
                              :supportedSASLMechanisms
         
     | 
| 
      
 1227 
     | 
    
         
            +
                              :supportedSASLMechanisms,
         
     | 
| 
       1149 
1228 
     | 
    
         
             
                            ])
         
     | 
| 
       1150 
1229 
     | 
    
         
             
                (rs and rs.first) or Net::LDAP::Entry.new
         
     | 
| 
       1151 
1230 
     | 
    
         
             
              end
         
     | 
| 
         @@ -1212,6 +1291,11 @@ class Net::LDAP 
     | 
|
| 
       1212 
1291 
     | 
    
         
             
                inspected
         
     | 
| 
       1213 
1292 
     | 
    
         
             
              end
         
     | 
| 
       1214 
1293 
     | 
    
         | 
| 
      
 1294 
     | 
    
         
            +
              # Internal: Set @open_connection for testing
         
     | 
| 
      
 1295 
     | 
    
         
            +
              def connection=(connection)
         
     | 
| 
      
 1296 
     | 
    
         
            +
                @open_connection = connection
         
     | 
| 
      
 1297 
     | 
    
         
            +
              end
         
     | 
| 
      
 1298 
     | 
    
         
            +
             
     | 
| 
       1215 
1299 
     | 
    
         
             
              private
         
     | 
| 
       1216 
1300 
     | 
    
         | 
| 
       1217 
1301 
     | 
    
         
             
              # Yields an open connection if there is one, otherwise establishes a new
         
     | 
| 
         @@ -1224,11 +1308,9 @@ class Net::LDAP 
     | 
|
| 
       1224 
1308 
     | 
    
         
             
                else
         
     | 
| 
       1225 
1309 
     | 
    
         
             
                  begin
         
     | 
| 
       1226 
1310 
     | 
    
         
             
                    conn = new_connection
         
     | 
| 
       1227 
     | 
    
         
            -
                     
     | 
| 
       1228 
     | 
    
         
            -
             
     | 
| 
       1229 
     | 
    
         
            -
                     
     | 
| 
       1230 
     | 
    
         
            -
                      return result
         
     | 
| 
       1231 
     | 
    
         
            -
                    end
         
     | 
| 
      
 1311 
     | 
    
         
            +
                    result = conn.bind(args[:auth] || @auth)
         
     | 
| 
      
 1312 
     | 
    
         
            +
                    return result unless result.result_code == Net::LDAP::ResultCodeSuccess
         
     | 
| 
      
 1313 
     | 
    
         
            +
                    yield conn
         
     | 
| 
       1232 
1314 
     | 
    
         
             
                  ensure
         
     | 
| 
       1233 
1315 
     | 
    
         
             
                    conn.close if conn
         
     | 
| 
       1234 
1316 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -1237,11 +1319,50 @@ class Net::LDAP 
     | 
|
| 
       1237 
1319 
     | 
    
         | 
| 
       1238 
1320 
     | 
    
         
             
              # Establish a new connection to the LDAP server
         
     | 
| 
       1239 
1321 
     | 
    
         
             
              def new_connection
         
     | 
| 
       1240 
     | 
    
         
            -
                Net::LDAP::Connection.new \
         
     | 
| 
      
 1322 
     | 
    
         
            +
                connection = Net::LDAP::Connection.new \
         
     | 
| 
       1241 
1323 
     | 
    
         
             
                  :host                    => @host,
         
     | 
| 
       1242 
1324 
     | 
    
         
             
                  :port                    => @port,
         
     | 
| 
       1243 
1325 
     | 
    
         
             
                  :hosts                   => @hosts,
         
     | 
| 
       1244 
1326 
     | 
    
         
             
                  :encryption              => @encryption,
         
     | 
| 
       1245 
     | 
    
         
            -
                  :instrumentation_service => @instrumentation_service
         
     | 
| 
      
 1327 
     | 
    
         
            +
                  :instrumentation_service => @instrumentation_service,
         
     | 
| 
      
 1328 
     | 
    
         
            +
                  :connect_timeout         => @connect_timeout
         
     | 
| 
      
 1329 
     | 
    
         
            +
             
     | 
| 
      
 1330 
     | 
    
         
            +
                # Force connect to see if there's a connection error
         
     | 
| 
      
 1331 
     | 
    
         
            +
                connection.socket
         
     | 
| 
      
 1332 
     | 
    
         
            +
                connection
         
     | 
| 
      
 1333 
     | 
    
         
            +
              rescue Errno::ECONNREFUSED, Errno::ETIMEDOUT => e
         
     | 
| 
      
 1334 
     | 
    
         
            +
                @result = {
         
     | 
| 
      
 1335 
     | 
    
         
            +
                  :resultCode   => 52,
         
     | 
| 
      
 1336 
     | 
    
         
            +
                  :errorMessage => ResultStrings[ResultCodeUnavailable],
         
     | 
| 
      
 1337 
     | 
    
         
            +
                }
         
     | 
| 
      
 1338 
     | 
    
         
            +
                raise e
         
     | 
| 
      
 1339 
     | 
    
         
            +
              end
         
     | 
| 
      
 1340 
     | 
    
         
            +
             
     | 
| 
      
 1341 
     | 
    
         
            +
              # Normalize encryption parameter the constructor accepts, expands a few
         
     | 
| 
      
 1342 
     | 
    
         
            +
              # convenience symbols into recognizable hashes
         
     | 
| 
      
 1343 
     | 
    
         
            +
              def normalize_encryption(args)
         
     | 
| 
      
 1344 
     | 
    
         
            +
                return if args.nil?
         
     | 
| 
      
 1345 
     | 
    
         
            +
                return args if args.is_a? Hash
         
     | 
| 
      
 1346 
     | 
    
         
            +
             
     | 
| 
      
 1347 
     | 
    
         
            +
                case method = args.to_sym
         
     | 
| 
      
 1348 
     | 
    
         
            +
                when :simple_tls, :start_tls
         
     | 
| 
      
 1349 
     | 
    
         
            +
                  { :method => method, :tls_options => {} }
         
     | 
| 
      
 1350 
     | 
    
         
            +
                end
         
     | 
| 
      
 1351 
     | 
    
         
            +
              end
         
     | 
| 
      
 1352 
     | 
    
         
            +
             
     | 
| 
      
 1353 
     | 
    
         
            +
              # Recursively delete a dn and it's subordinate children.
         
     | 
| 
      
 1354 
     | 
    
         
            +
              # This is useful when a server does not support the DELETE_TREE control code.
         
     | 
| 
      
 1355 
     | 
    
         
            +
              def recursive_delete(args)
         
     | 
| 
      
 1356 
     | 
    
         
            +
                raise EmptyDNError unless args.is_a?(Hash) && args.key?(:dn)
         
     | 
| 
      
 1357 
     | 
    
         
            +
                # Delete Children
         
     | 
| 
      
 1358 
     | 
    
         
            +
                search(base: args[:dn], scope: Net::LDAP::SearchScope_SingleLevel) do |entry|
         
     | 
| 
      
 1359 
     | 
    
         
            +
                  recursive_delete(dn: entry.dn)
         
     | 
| 
      
 1360 
     | 
    
         
            +
                end
         
     | 
| 
      
 1361 
     | 
    
         
            +
                # Delete Self
         
     | 
| 
      
 1362 
     | 
    
         
            +
                unless delete(dn: args[:dn])
         
     | 
| 
      
 1363 
     | 
    
         
            +
                  raise Net::LDAP::Error, get_operation_result[:error_message].to_s
         
     | 
| 
      
 1364 
     | 
    
         
            +
                end
         
     | 
| 
      
 1365 
     | 
    
         
            +
                true
         
     | 
| 
       1246 
1366 
     | 
    
         
             
              end
         
     | 
| 
      
 1367 
     | 
    
         
            +
             
     | 
| 
       1247 
1368 
     | 
    
         
             
            end # class LDAP
         
     |