net-ldap 0.14.0 → 0.16.3
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/.gitignore +1 -0
- data/.rubocop.yml +5 -2
- data/.rubocop_todo.yml +343 -219
- data/.travis.yml +27 -3
- data/CONTRIBUTING.md +1 -1
- data/History.rdoc +21 -0
- data/README.rdoc +10 -7
- data/Rakefile +1 -1
- data/lib/net-ldap.rb +1 -1
- data/lib/net/ber.rb +5 -6
- data/lib/net/ber/ber_parser.rb +3 -3
- data/lib/net/ber/core_ext.rb +6 -6
- data/lib/net/ldap.rb +65 -55
- data/lib/net/ldap/auth_adapter/gss_spnego.rb +2 -2
- data/lib/net/ldap/auth_adapter/sasl.rb +4 -2
- data/lib/net/ldap/auth_adapter/simple.rb +1 -1
- data/lib/net/ldap/connection.rb +58 -35
- data/lib/net/ldap/dataset.rb +2 -2
- data/lib/net/ldap/dn.rb +13 -14
- data/lib/net/ldap/entry.rb +5 -6
- data/lib/net/ldap/error.rb +1 -0
- data/lib/net/ldap/filter.rb +10 -3
- data/lib/net/ldap/instrumentation.rb +2 -2
- data/lib/net/ldap/password.rb +3 -5
- data/lib/net/ldap/pdu.rb +1 -1
- data/lib/net/ldap/version.rb +1 -1
- data/lib/net/snmp.rb +1 -1
- data/net-ldap.gemspec +4 -4
- data/script/ldap-docker +12 -0
- data/test/ber/test_ber.rb +1 -1
- data/test/fixtures/ca/docker-ca.pem +18 -0
- data/test/fixtures/{openldap/retcode.ldif → ldif/06-retcode.ldif} +7 -8
- data/test/fixtures/ldif/50-seed.ldif +374 -0
- data/test/integration/test_add.rb +1 -3
- data/test/integration/test_ber.rb +2 -2
- data/test/integration/test_bind.rb +193 -14
- data/test/integration/test_delete.rb +1 -3
- data/test/integration/test_open.rb +10 -11
- data/test/integration/test_password_modify.rb +29 -16
- data/test/integration/test_return_codes.rb +12 -4
- data/test/integration/test_search.rb +8 -8
- data/test/test_dn.rb +2 -3
- data/test/test_entry.rb +3 -2
- data/test/test_filter_parser.rb +5 -0
- data/test/test_helper.rb +12 -5
- data/test/test_ldap.rb +5 -5
- data/test/test_ldap_connection.rb +47 -35
- data/test/test_ldif.rb +13 -13
- data/test/test_password.rb +2 -2
- data/test/test_snmp.rb +4 -5
- data/test/test_ssl_ber.rb +7 -3
- data/testserver/ldapserver.rb +13 -22
- metadata +17 -26
- data/script/install-openldap +0 -115
- data/test/fixtures/cacert.pem +0 -20
- data/test/fixtures/openldap/memberof.ldif +0 -33
- data/test/fixtures/openldap/slapd.conf.ldif +0 -67
- data/test/fixtures/seed.ldif +0 -374
- data/test/support/vm/openldap/README.md +0 -32
- data/test/support/vm/openldap/Vagrantfile +0 -33
data/.travis.yml
CHANGED
@@ -3,11 +3,24 @@ rvm:
|
|
3
3
|
- 2.0.0
|
4
4
|
- 2.1
|
5
5
|
- 2.2
|
6
|
+
- 2.3
|
7
|
+
- 2.4
|
8
|
+
- 2.5
|
9
|
+
- 2.6
|
10
|
+
- 2.7
|
11
|
+
- jruby-9.2
|
6
12
|
# optional
|
7
13
|
- ruby-head
|
8
14
|
- jruby-19mode
|
15
|
+
- jruby-9.2
|
9
16
|
- jruby-head
|
10
|
-
|
17
|
+
|
18
|
+
addons:
|
19
|
+
hosts:
|
20
|
+
- ldap.example.org # needed for TLS verification
|
21
|
+
|
22
|
+
services:
|
23
|
+
- docker
|
11
24
|
|
12
25
|
env:
|
13
26
|
- INTEGRATION=openldap
|
@@ -16,7 +29,18 @@ before_install:
|
|
16
29
|
- gem update bundler
|
17
30
|
|
18
31
|
install:
|
19
|
-
-
|
32
|
+
- >
|
33
|
+
docker run \
|
34
|
+
--hostname ldap.example.org \
|
35
|
+
--env LDAP_TLS_VERIFY_CLIENT=try \
|
36
|
+
-p 389:389 \
|
37
|
+
-p 636:636 \
|
38
|
+
-v "$(pwd)"/test/fixtures/ldif:/container/service/slapd/assets/config/bootstrap/ldif/custom \
|
39
|
+
--name openldap \
|
40
|
+
--detach \
|
41
|
+
osixia/openldap:1.3.0 \
|
42
|
+
--copy-service \
|
43
|
+
--loglevel debug \
|
20
44
|
- bundle install
|
21
45
|
|
22
46
|
script: bundle exec rake ci
|
@@ -25,8 +49,8 @@ matrix:
|
|
25
49
|
allow_failures:
|
26
50
|
- rvm: ruby-head
|
27
51
|
- rvm: jruby-19mode
|
52
|
+
- rvm: jruby-9.2
|
28
53
|
- rvm: jruby-head
|
29
|
-
- rvm: rbx-2
|
30
54
|
fast_finish: true
|
31
55
|
|
32
56
|
notifications:
|
data/CONTRIBUTING.md
CHANGED
@@ -49,6 +49,6 @@ MyClass.new \
|
|
49
49
|
baz: 'garply'
|
50
50
|
```
|
51
51
|
|
52
|
-
[issues]: https://github.com/ruby-
|
52
|
+
[issues]: https://github.com/ruby-ldap/ruby-net-ldap/issues
|
53
53
|
[pr]: https://help.github.com/articles/using-pull-requests
|
54
54
|
[travis]: https://travis-ci.org/ruby-ldap/ruby-net-ldap
|
data/History.rdoc
CHANGED
@@ -1,3 +1,24 @@
|
|
1
|
+
=== Net::LDAP 0.16.2
|
2
|
+
|
3
|
+
* Net::LDAP#open does not cache bind result {#334}[https://github.com/ruby-ldap/ruby-net-ldap/pull/334]
|
4
|
+
* Fix CI build {#333}[https://github.com/ruby-ldap/ruby-net-ldap/pull/333]
|
5
|
+
* Fix to "undefined method 'result_code'" {#308}[https://github.com/ruby-ldap/ruby-net-ldap/pull/308]
|
6
|
+
* Fixed Exception: incompatible character encodings: ASCII-8BIT and UTF-8 in filter.rb {#285}[https://github.com/ruby-ldap/ruby-net-ldap/pull/285]
|
7
|
+
|
8
|
+
=== Net::LDAP 0.16.1
|
9
|
+
|
10
|
+
* Send DN and newPassword with password_modify request {#271}[https://github.com/ruby-ldap/ruby-net-ldap/pull/271]
|
11
|
+
|
12
|
+
=== Net::LDAP 0.16.0
|
13
|
+
|
14
|
+
* Sasl fix {#281}[https://github.com/ruby-ldap/ruby-net-ldap/pull/281]
|
15
|
+
* enable TLS hostname validation {#279}[https://github.com/ruby-ldap/ruby-net-ldap/pull/279]
|
16
|
+
* update rubocop to 0.42.0 {#278}[https://github.com/ruby-ldap/ruby-net-ldap/pull/278]
|
17
|
+
|
18
|
+
=== Net::LDAP 0.15.0
|
19
|
+
|
20
|
+
* Respect connect_timeout when establishing SSL connections {#273}[https://github.com/ruby-ldap/ruby-net-ldap/pull/273]
|
21
|
+
|
1
22
|
=== Net::LDAP 0.14.0
|
2
23
|
|
3
24
|
* Normalize the encryption parameter passed to the LDAP constructor {#264}[https://github.com/ruby-ldap/ruby-net-ldap/pull/264]
|
data/README.rdoc
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
= Net::LDAP for Ruby {<img src="https://travis-ci.org/ruby-ldap/ruby-net-ldap.
|
1
|
+
= Net::LDAP for Ruby {<img src="https://travis-ci.org/ruby-ldap/ruby-net-ldap.svg" />}[https://travis-ci.org/ruby-ldap/ruby-net-ldap]
|
2
2
|
|
3
3
|
== Description
|
4
4
|
|
@@ -21,7 +21,7 @@ the most recent LDAP RFCs (4510–4519, plus portions of 4520–4532).
|
|
21
21
|
|
22
22
|
== Synopsis
|
23
23
|
|
24
|
-
See Net::LDAP for documentation and usage samples.
|
24
|
+
See {Net::LDAP on rubydoc.info}[https://www.rubydoc.info/gems/net-ldap/Net/LDAP] for documentation and usage samples.
|
25
25
|
|
26
26
|
== Requirements
|
27
27
|
|
@@ -52,12 +52,15 @@ This task will run the test suite and the
|
|
52
52
|
|
53
53
|
rake rubotest
|
54
54
|
|
55
|
-
|
55
|
+
CI takes too long? If your local box supports
|
56
|
+
{Docker}[https://www.docker.com/], you can also run integration tests locally.
|
57
|
+
Simply run:
|
56
58
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
59
|
+
script/ldap-docker
|
60
|
+
INTEGRATION=openldap rake test
|
61
|
+
|
62
|
+
CAVEAT: you need to add the following line to /etc/hosts
|
63
|
+
127.0.0.1 ldap.example.org
|
61
64
|
|
62
65
|
== Release
|
63
66
|
|
data/Rakefile
CHANGED
data/lib/net-ldap.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
# -*- ruby encoding: utf-8 -*-
|
2
|
-
|
2
|
+
require_relative 'net/ldap'
|
data/lib/net/ber.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# -*- ruby encoding: utf-8 -*-
|
2
|
-
|
2
|
+
require_relative 'ldap/version'
|
3
3
|
|
4
4
|
module Net # :nodoc:
|
5
5
|
##
|
@@ -327,11 +327,10 @@ class Net::BER::BerIdentifiedString < String
|
|
327
327
|
# Check the encoding of the newly created String and set the encoding
|
328
328
|
# to 'UTF-8' (NOTE: we do NOT change the bytes, but only set the
|
329
329
|
# encoding to 'UTF-8').
|
330
|
+
return unless encoding == Encoding::BINARY
|
330
331
|
current_encoding = encoding
|
331
|
-
|
332
|
-
|
333
|
-
force_encoding(current_encoding) unless valid_encoding?
|
334
|
-
end
|
332
|
+
force_encoding('UTF-8')
|
333
|
+
force_encoding(current_encoding) unless valid_encoding?
|
335
334
|
end
|
336
335
|
end
|
337
336
|
|
@@ -350,4 +349,4 @@ module Net::BER
|
|
350
349
|
Null = Net::BER::BerIdentifiedNull.new
|
351
350
|
end
|
352
351
|
|
353
|
-
|
352
|
+
require_relative 'ber/core_ext'
|
data/lib/net/ber/ber_parser.rb
CHANGED
@@ -172,10 +172,10 @@ module Net::BER::BERParser
|
|
172
172
|
yield id, content_length if block_given?
|
173
173
|
|
174
174
|
if -1 == content_length
|
175
|
-
raise Net::BER::BerError,
|
176
|
-
|
177
|
-
data = read(content_length)
|
175
|
+
raise Net::BER::BerError,
|
176
|
+
"Indeterminite BER content length not implemented."
|
178
177
|
end
|
178
|
+
data = read(content_length)
|
179
179
|
|
180
180
|
parse_ber_object(syntax, id, data)
|
181
181
|
end
|
data/lib/net/ber/core_ext.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# -*- ruby encoding: utf-8 -*-
|
2
|
-
|
2
|
+
require_relative 'ber_parser'
|
3
3
|
# :stopdoc:
|
4
4
|
class IO
|
5
5
|
include Net::BER::BERParser
|
@@ -19,35 +19,35 @@ end
|
|
19
19
|
module Net::BER::Extensions # :nodoc:
|
20
20
|
end
|
21
21
|
|
22
|
-
|
22
|
+
require_relative 'core_ext/string'
|
23
23
|
# :stopdoc:
|
24
24
|
class String
|
25
25
|
include Net::BER::BERParser
|
26
26
|
include Net::BER::Extensions::String
|
27
27
|
end
|
28
28
|
|
29
|
-
|
29
|
+
require_relative 'core_ext/array'
|
30
30
|
# :stopdoc:
|
31
31
|
class Array
|
32
32
|
include Net::BER::Extensions::Array
|
33
33
|
end
|
34
34
|
# :startdoc:
|
35
35
|
|
36
|
-
|
36
|
+
require_relative 'core_ext/integer'
|
37
37
|
# :stopdoc:
|
38
38
|
class Integer
|
39
39
|
include Net::BER::Extensions::Integer
|
40
40
|
end
|
41
41
|
# :startdoc:
|
42
42
|
|
43
|
-
|
43
|
+
require_relative 'core_ext/true_class'
|
44
44
|
# :stopdoc:
|
45
45
|
class TrueClass
|
46
46
|
include Net::BER::Extensions::TrueClass
|
47
47
|
end
|
48
48
|
# :startdoc:
|
49
49
|
|
50
|
-
|
50
|
+
require_relative 'core_ext/false_class'
|
51
51
|
# :stopdoc:
|
52
52
|
class FalseClass
|
53
53
|
include Net::BER::Extensions::FalseClass
|
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)
|
@@ -476,61 +476,73 @@ class Net::LDAP
|
|
476
476
|
# specify a treebase. If you give a treebase value in any particular
|
477
477
|
# call to #search, that value will override any treebase value you give
|
478
478
|
# here.
|
479
|
+
# * :force_no_page => Set to true to prevent paged results even if your
|
480
|
+
# server says it supports them. This is a fix for MS Active Directory
|
481
|
+
# * :instrumentation_service => An object responsible for instrumenting
|
482
|
+
# operations, compatible with ActiveSupport::Notifications' public API.
|
479
483
|
# * :encryption => specifies the encryption to be used in communicating
|
480
484
|
# with the LDAP server. The value must be a Hash containing additional
|
481
485
|
# parameters, which consists of two keys:
|
482
486
|
# method: - :simple_tls or :start_tls
|
483
|
-
#
|
487
|
+
# tls_options: - Hash of options for that method
|
484
488
|
# The :simple_tls encryption method encrypts <i>all</i> communications
|
485
489
|
# with the LDAP server. It completely establishes SSL/TLS encryption with
|
486
490
|
# the LDAP server before any LDAP-protocol data is exchanged. There is no
|
487
491
|
# plaintext negotiation and no special encryption-request controls are
|
488
492
|
# sent to the server. <i>The :simple_tls option is the simplest, easiest
|
489
493
|
# way to encrypt communications between Net::LDAP and LDAP servers.</i>
|
490
|
-
#
|
491
|
-
#
|
492
|
-
#
|
493
|
-
#
|
494
|
-
#
|
495
|
-
#
|
496
|
-
#
|
497
|
-
# connecting to. It's impossible for an LDAP server to support plaintext
|
498
|
-
# LDAP communications and <i>simple TLS</i> connections on the same port.
|
499
|
-
# The standard TCP port for unencrypted LDAP connections is 389, but the
|
500
|
-
# standard port for simple-TLS encrypted connections is 636. Be sure you
|
501
|
-
# are using the correct port.
|
502
|
-
#
|
494
|
+
# If you get communications or protocol errors when using this option,
|
495
|
+
# check with your LDAP server administrator. Pay particular attention
|
496
|
+
# to the TCP port you are connecting to. It's impossible for an LDAP
|
497
|
+
# server to support plaintext LDAP communications and <i>simple TLS</i>
|
498
|
+
# connections on the same port. The standard TCP port for unencrypted
|
499
|
+
# LDAP connections is 389, but the standard port for simple-TLS
|
500
|
+
# encrypted connections is 636. Be sure you are using the correct port.
|
503
501
|
# The :start_tls like the :simple_tls encryption method also encrypts all
|
504
502
|
# communcations with the LDAP server. With the exception that it operates
|
505
503
|
# over the standard TCP port.
|
506
504
|
#
|
507
|
-
#
|
508
|
-
#
|
509
|
-
#
|
510
|
-
# OpenSSL::SSL::SSLContext#set_params(). The most common options passed
|
511
|
-
# should be OpenSSL::SSL::SSLContext::DEFAULT_PARAMS, or the :ca_file option,
|
512
|
-
# which contains a path to a Certificate Authority file (PEM-encoded).
|
513
|
-
#
|
514
|
-
# Example for a default setup without custom settings:
|
515
|
-
# {
|
516
|
-
# :method => :simple_tls,
|
517
|
-
# :tls_options => OpenSSL::SSL::SSLContext::DEFAULT_PARAMS
|
518
|
-
# }
|
519
|
-
#
|
520
|
-
# Example for specifying a CA-File and only allowing TLSv1.1 connections:
|
505
|
+
# To validate the LDAP server's certificate (a security must if you're
|
506
|
+
# talking over the public internet), you need to set :tls_options
|
507
|
+
# something like this...
|
521
508
|
#
|
522
|
-
#
|
523
|
-
#
|
524
|
-
#
|
509
|
+
# Net::LDAP.new(
|
510
|
+
# # ... set host, bind dn, etc ...
|
511
|
+
# encryption: {
|
512
|
+
# method: :simple_tls,
|
513
|
+
# tls_options: OpenSSL::SSL::SSLContext::DEFAULT_PARAMS,
|
525
514
|
# }
|
526
|
-
#
|
527
|
-
#
|
528
|
-
#
|
529
|
-
#
|
515
|
+
# )
|
516
|
+
#
|
517
|
+
# The above will use the operating system-provided store of CA
|
518
|
+
# certificates to validate your LDAP server's cert.
|
519
|
+
# If cert validation fails, it'll happen during the #bind
|
520
|
+
# whenever you first try to open a connection to the server.
|
521
|
+
# Those methods will throw Net::LDAP::ConnectionError with
|
522
|
+
# a message about certificate verify failing. If your
|
523
|
+
# LDAP server's certificate is signed by DigiCert, Comodo, etc.,
|
524
|
+
# you're probably good. If you've got a self-signed cert but it's
|
525
|
+
# been added to the host's OS-maintained CA store (e.g. on Debian
|
526
|
+
# add foobar.crt to /usr/local/share/ca-certificates/ and run
|
527
|
+
# `update-ca-certificates`), then the cert should pass validation.
|
528
|
+
# To ignore the OS's CA store, put your CA in a PEM-encoded file and...
|
529
|
+
#
|
530
|
+
# encryption: {
|
531
|
+
# method: :simple_tls,
|
532
|
+
# tls_options: { ca_file: '/path/to/my-little-ca.pem',
|
533
|
+
# ssl_version: 'TLSv1_1' },
|
534
|
+
# }
|
535
|
+
#
|
536
|
+
# As you might guess, the above example also fails the connection
|
537
|
+
# if the client can't negotiate TLS v1.1.
|
538
|
+
# tls_options is ultimately passed to OpenSSL::SSL::SSLContext#set_params
|
539
|
+
# For more details, see
|
540
|
+
# http://ruby-doc.org/stdlib-2.0.0/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html
|
530
541
|
#
|
531
542
|
# Instantiating a Net::LDAP object does <i>not</i> result in network
|
532
543
|
# traffic to the LDAP server. It simply stores the connection and binding
|
533
|
-
# parameters in the object.
|
544
|
+
# parameters in the object. That's why Net::LDAP.new doesn't throw
|
545
|
+
# cert validation errors itself; #bind does instead.
|
534
546
|
def initialize(args = {})
|
535
547
|
@host = args[:host] || DefaultHost
|
536
548
|
@port = args[:port] || DefaultPort
|
@@ -700,7 +712,7 @@ class Net::LDAP
|
|
700
712
|
begin
|
701
713
|
@open_connection = new_connection
|
702
714
|
payload[:connection] = @open_connection
|
703
|
-
payload[:bind] = @open_connection.bind(@auth)
|
715
|
+
payload[:bind] = @result = @open_connection.bind(@auth)
|
704
716
|
yield self
|
705
717
|
ensure
|
706
718
|
@open_connection.close if @open_connection
|
@@ -1286,11 +1298,9 @@ class Net::LDAP
|
|
1286
1298
|
else
|
1287
1299
|
begin
|
1288
1300
|
conn = new_connection
|
1289
|
-
|
1290
|
-
|
1291
|
-
|
1292
|
-
return result
|
1293
|
-
end
|
1301
|
+
result = conn.bind(args[:auth] || @auth)
|
1302
|
+
return result unless result.result_code == Net::LDAP::ResultCodeSuccess
|
1303
|
+
yield conn
|
1294
1304
|
ensure
|
1295
1305
|
conn.close if conn
|
1296
1306
|
end
|
@@ -1,9 +1,11 @@
|
|
1
|
-
|
1
|
+
require_relative '../auth_adapter'
|
2
2
|
|
3
3
|
module Net
|
4
4
|
class LDAP
|
5
5
|
class AuthAdapter
|
6
6
|
class Sasl < Net::LDAP::AuthAdapter
|
7
|
+
MAX_SASL_CHALLENGES = 10
|
8
|
+
|
7
9
|
#--
|
8
10
|
# Required parameters: :mechanism, :initial_credential and
|
9
11
|
# :challenge_response
|
@@ -47,7 +49,7 @@ module Net
|
|
47
49
|
end
|
48
50
|
|
49
51
|
return pdu unless pdu.result_code == Net::LDAP::ResultCodeSaslBindInProgress
|
50
|
-
raise Net::LDAP::SASLChallengeOverflowError, "sasl-challenge overflow" if ((n += 1) >
|
52
|
+
raise Net::LDAP::SASLChallengeOverflowError, "sasl-challenge overflow" if ((n += 1) > MAX_SASL_CHALLENGES)
|
51
53
|
|
52
54
|
cred = chall.call(pdu.result_server_sasl_creds)
|
53
55
|
end
|
data/lib/net/ldap/connection.rb
CHANGED
@@ -7,7 +7,6 @@ class Net::LDAP::Connection #:nodoc:
|
|
7
7
|
DefaultConnectTimeout = 5
|
8
8
|
|
9
9
|
LdapVersion = 3
|
10
|
-
MaxSaslChallenges = 10
|
11
10
|
|
12
11
|
# Initialize a connection to an LDAP server
|
13
12
|
#
|
@@ -31,26 +30,36 @@ class Net::LDAP::Connection #:nodoc:
|
|
31
30
|
@socket_class = socket_class
|
32
31
|
end
|
33
32
|
|
34
|
-
def prepare_socket(server)
|
33
|
+
def prepare_socket(server, timeout=nil)
|
35
34
|
socket = server[:socket]
|
36
35
|
encryption = server[:encryption]
|
37
36
|
|
38
37
|
@conn = socket
|
39
|
-
setup_encryption
|
38
|
+
setup_encryption(encryption, timeout) if encryption
|
40
39
|
end
|
41
40
|
|
42
41
|
def open_connection(server)
|
43
42
|
hosts = server[:hosts]
|
44
43
|
encryption = server[:encryption]
|
45
44
|
|
45
|
+
timeout = server[:connect_timeout] || DefaultConnectTimeout
|
46
46
|
socket_opts = {
|
47
|
-
connect_timeout:
|
47
|
+
connect_timeout: timeout,
|
48
48
|
}
|
49
49
|
|
50
50
|
errors = []
|
51
51
|
hosts.each do |host, port|
|
52
52
|
begin
|
53
|
-
prepare_socket(server.merge(socket: @socket_class.new(host, port, socket_opts)))
|
53
|
+
prepare_socket(server.merge(socket: @socket_class.new(host, port, socket_opts)), timeout)
|
54
|
+
if encryption
|
55
|
+
if encryption[:tls_options] &&
|
56
|
+
encryption[:tls_options][:verify_mode] &&
|
57
|
+
encryption[:tls_options][:verify_mode] == OpenSSL::SSL::VERIFY_NONE
|
58
|
+
warn "not verifying SSL hostname of LDAPS server '#{host}:#{port}'"
|
59
|
+
else
|
60
|
+
@conn.post_connection_check(host)
|
61
|
+
end
|
62
|
+
end
|
54
63
|
return
|
55
64
|
rescue Net::LDAP::Error, SocketError, SystemCallError,
|
56
65
|
OpenSSL::SSL::SSLError => e
|
@@ -76,7 +85,7 @@ class Net::LDAP::Connection #:nodoc:
|
|
76
85
|
end
|
77
86
|
end
|
78
87
|
|
79
|
-
def self.wrap_with_ssl(io, tls_options = {})
|
88
|
+
def self.wrap_with_ssl(io, tls_options = {}, timeout=nil)
|
80
89
|
raise Net::LDAP::NoOpenSSLError, "OpenSSL is unavailable" unless Net::LDAP::HasOpenSSL
|
81
90
|
|
82
91
|
ctx = OpenSSL::SSL::SSLContext.new
|
@@ -86,7 +95,22 @@ class Net::LDAP::Connection #:nodoc:
|
|
86
95
|
ctx.set_params(tls_options) unless tls_options.empty?
|
87
96
|
|
88
97
|
conn = OpenSSL::SSL::SSLSocket.new(io, ctx)
|
89
|
-
|
98
|
+
|
99
|
+
begin
|
100
|
+
if timeout
|
101
|
+
conn.connect_nonblock
|
102
|
+
else
|
103
|
+
conn.connect
|
104
|
+
end
|
105
|
+
rescue IO::WaitReadable
|
106
|
+
raise Errno::ETIMEDOUT, "OpenSSL connection read timeout" unless
|
107
|
+
IO.select([conn], nil, nil, timeout)
|
108
|
+
retry
|
109
|
+
rescue IO::WaitWritable
|
110
|
+
raise Errno::ETIMEDOUT, "OpenSSL connection write timeout" unless
|
111
|
+
IO.select(nil, [conn], nil, timeout)
|
112
|
+
retry
|
113
|
+
end
|
90
114
|
|
91
115
|
# Doesn't work:
|
92
116
|
# conn.sync_close = true
|
@@ -123,11 +147,11 @@ class Net::LDAP::Connection #:nodoc:
|
|
123
147
|
# communications, as with simple_tls. Thanks for Kouhei Sutou for
|
124
148
|
# generously contributing the :start_tls path.
|
125
149
|
#++
|
126
|
-
def setup_encryption(args)
|
150
|
+
def setup_encryption(args, timeout=nil)
|
127
151
|
args[:tls_options] ||= {}
|
128
152
|
case args[:method]
|
129
153
|
when :simple_tls
|
130
|
-
@conn = self.class.wrap_with_ssl(@conn, args[:tls_options])
|
154
|
+
@conn = self.class.wrap_with_ssl(@conn, args[:tls_options], timeout)
|
131
155
|
# additional branches requiring server validation and peer certs, etc.
|
132
156
|
# go here.
|
133
157
|
when :start_tls
|
@@ -143,11 +167,9 @@ class Net::LDAP::Connection #:nodoc:
|
|
143
167
|
raise Net::LDAP::NoStartTLSResultError, "no start_tls result"
|
144
168
|
end
|
145
169
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
raise Net::LDAP::StartTLSError, "start_tls failed: #{pdu.result_code}"
|
150
|
-
end
|
170
|
+
raise Net::LDAP::StartTLSError,
|
171
|
+
"start_tls failed: #{pdu.result_code}" unless pdu.result_code.zero?
|
172
|
+
@conn = self.class.wrap_with_ssl(@conn, args[:tls_options], timeout)
|
151
173
|
else
|
152
174
|
raise Net::LDAP::EncMethodUnsupportedError, "unsupported encryption method #{args[:method]}"
|
153
175
|
end
|
@@ -159,7 +181,7 @@ class Net::LDAP::Connection #:nodoc:
|
|
159
181
|
# have to call it, but perhaps it will come in handy someday.
|
160
182
|
#++
|
161
183
|
def close
|
162
|
-
return if @conn.nil?
|
184
|
+
return if !defined?(@conn) || @conn.nil?
|
163
185
|
@conn.close
|
164
186
|
@conn = nil
|
165
187
|
end
|
@@ -177,12 +199,10 @@ class Net::LDAP::Connection #:nodoc:
|
|
177
199
|
|
178
200
|
# read messages until we have a match for the given message_id
|
179
201
|
while pdu = read
|
180
|
-
if pdu.message_id == message_id
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
next
|
185
|
-
end
|
202
|
+
return pdu if pdu.message_id == message_id
|
203
|
+
|
204
|
+
message_queue[pdu.message_id].push pdu
|
205
|
+
next
|
186
206
|
end
|
187
207
|
|
188
208
|
pdu
|
@@ -280,7 +300,7 @@ class Net::LDAP::Connection #:nodoc:
|
|
280
300
|
control[2] = (control[2] == true).to_ber
|
281
301
|
control.to_ber_sequence
|
282
302
|
end
|
283
|
-
|
303
|
+
[
|
284
304
|
Net::LDAP::LDAPControls::SORT_REQUEST.to_ber,
|
285
305
|
false.to_ber,
|
286
306
|
sort_control_values.to_ber_sequence.to_s.to_ber,
|
@@ -380,12 +400,11 @@ class Net::LDAP::Connection #:nodoc:
|
|
380
400
|
# should collect this into a private helper to clarify the structure
|
381
401
|
query_limit = 0
|
382
402
|
if size > 0
|
383
|
-
if paged
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
end
|
403
|
+
query_limit = if paged
|
404
|
+
(((size - n_results) < 126) ? (size - n_results) : 0)
|
405
|
+
else
|
406
|
+
size
|
407
|
+
end
|
389
408
|
end
|
390
409
|
|
391
410
|
request = [
|
@@ -448,6 +467,10 @@ class Net::LDAP::Connection #:nodoc:
|
|
448
467
|
end
|
449
468
|
end
|
450
469
|
|
470
|
+
if result_pdu.nil?
|
471
|
+
raise Net::LDAP::ResponseMissingOrInvalidError, "response missing"
|
472
|
+
end
|
473
|
+
|
451
474
|
# count number of pages of results
|
452
475
|
payload[:page_count] ||= 0
|
453
476
|
payload[:page_count] += 1
|
@@ -573,11 +596,11 @@ class Net::LDAP::Connection #:nodoc:
|
|
573
596
|
|
574
597
|
ext_seq = [Net::LDAP::PasswdModifyOid.to_ber_contextspecific(0)]
|
575
598
|
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
599
|
+
pwd_seq = []
|
600
|
+
pwd_seq << dn.to_ber(0x80)
|
601
|
+
pwd_seq << args[:old_password].to_ber(0x81) unless args[:old_password].nil?
|
602
|
+
pwd_seq << args[:new_password].to_ber(0x82) unless args[:new_password].nil?
|
603
|
+
ext_seq << pwd_seq.to_ber_sequence.to_ber(0x81)
|
581
604
|
|
582
605
|
request = ext_seq.to_ber_appsequence(Net::LDAP::PDU::ExtendedRequest)
|
583
606
|
|
@@ -587,7 +610,7 @@ class Net::LDAP::Connection #:nodoc:
|
|
587
610
|
pdu = queued_read(message_id)
|
588
611
|
|
589
612
|
if !pdu || pdu.app_tag != Net::LDAP::PDU::ExtendedResponse
|
590
|
-
raise Net::LDAP::
|
613
|
+
raise Net::LDAP::ResponseMissingOrInvalidError, "response missing or invalid"
|
591
614
|
end
|
592
615
|
|
593
616
|
pdu
|
@@ -687,7 +710,7 @@ class Net::LDAP::Connection #:nodoc:
|
|
687
710
|
# Wrap around Socket.tcp to normalize with other Socket initializers
|
688
711
|
class DefaultSocket
|
689
712
|
def self.new(host, port, socket_opts = {})
|
690
|
-
Socket.tcp(host, port, socket_opts)
|
713
|
+
Socket.tcp(host, port, **socket_opts)
|
691
714
|
end
|
692
715
|
end
|
693
716
|
end # class Connection
|