@@ -79,6 +79,14 @@ class LDAP
7979#
8080# p ldap.get_operation_result
8181#
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
8290#
8391# == A Brief Introduction to LDAP
8492#
@@ -315,7 +323,14 @@ class Net::LDAP
315323 :constructed => constructed ,
316324 }
317325
326+ universal = {
327+ constructed : {
328+ 107 => :array #ExtendedResponse (PasswdModifyResponseValue)
329+ }
330+ }
331+
318332 AsnSyntax = Net ::BER . compile_syntax ( :application => application ,
333+ :universal => universal ,
319334 :context_specific => context_specific )
320335
321336 DefaultHost = "127.0.0.1"
@@ -324,7 +339,8 @@ class Net::LDAP
324339 DefaultTreebase = "dc=com"
325340 DefaultForceNoPage = false
326341
327- StartTlsOid = "1.3.6.1.4.1.1466.20037"
342+ StartTlsOid = '1.3.6.1.4.1.1466.20037'
343+ PasswdModifyOid = '1.3.6.1.4.1.4203.1.11.1'
328344
329345 # https://tools.ietf.org/html/rfc4511#section-4.1.9
330346 # https://tools.ietf.org/html/rfc4511#appendix-A
@@ -461,11 +477,52 @@ def self.result2string(code) #:nodoc:
461477 # call to #search, that value will override any treebase value you give
462478 # here.
463479 # * :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.
480+ # with the LDAP server. The value must be a Hash containing additional
481+ # parameters, which consists of two keys:
482+ # method: - :simple_tls or :start_tls
483+ # options: - Hash of options for that method
484+ # The :simple_tls encryption method encrypts <i>all</i> communications
485+ # with the LDAP server. It completely establishes SSL/TLS encryption with
486+ # the LDAP server before any LDAP-protocol data is exchanged. There is no
487+ # plaintext negotiation and no special encryption-request controls are
488+ # sent to the server. <i>The :simple_tls option is the simplest, easiest
489+ # way to encrypt communications between Net::LDAP and LDAP servers.</i>
490+ # It's intended for cases where you have an implicit level of trust in the
491+ # authenticity of the LDAP server. No validation of the LDAP server's SSL
492+ # certificate is performed. This means that :simple_tls will not produce
493+ # errors if the LDAP server's encryption certificate is not signed by a
494+ # well-known Certification Authority. If you get communications or
495+ # protocol errors when using this option, check with your LDAP server
496+ # administrator. Pay particular attention to the TCP port you are
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+ #
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+ # In order to verify certificates and enable other TLS options, the
508+ # :tls_options hash can be passed alongside :simple_tls or :start_tls.
509+ # This hash contains any options that can be passed to
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:
521+ #
522+ # {
523+ # :method => :start_tls,
524+ # :tls_options => { :ca_file => "/etc/cafile.pem", :ssl_version => "TLSv1_1" }
525+ # }
469526 # * :force_no_page => Set to true to prevent paged results even if your
470527 # server says it supports them. This is a fix for MS Active Directory
471528 # * :instrumentation_service => An object responsible for instrumenting
@@ -482,7 +539,8 @@ def initialize(args = {})
482539 @auth = args [ :auth ] || DefaultAuth
483540 @base = args [ :base ] || DefaultTreebase
484541 @force_no_page = args [ :force_no_page ] || DefaultForceNoPage
485- encryption args [ :encryption ] # may be nil
542+ @encryption = args [ :encryption ] # may be nil
543+ @connect_timeout = args [ :connect_timeout ]
486544
487545 if pr = @auth [ :password ] and pr . respond_to? ( :call )
488546 @auth [ :password ] = pr . call
@@ -546,52 +604,16 @@ def authenticate(username, password)
546604 # additional capabilities are added, more configuration values will be
547605 # added here.
548606 #
549- # The :simple_tls encryption method encrypts <i>all</i> communications
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:
586- #
587- # {
588- # :method => :start_tls,
589- # :tls_options => { :ca_file => "/etc/cafile.pem", :ssl_version => "TLSv1_1" }
590- # }
607+ # This method is deprecated.
608+ #
591609 def encryption ( args )
592- case args
610+ warn "Deprecation warning: please give :encryption option as a Hash to Net::LDAP.new"
611+ return if args . nil?
612+ return @encryption = args if args . is_a? Hash
613+
614+ case method = args . to_sym
593615 when :simple_tls , :start_tls
594- args = { :method => args , :tls_options => { } }
616+ args = { :method => method , :tls_options => { } }
595617 end
596618 @encryption = args
597619 end
@@ -637,8 +659,11 @@ def self.open(args)
637659 #++
638660 def get_operation_result
639661 result = @result
640- result = result . result if result . is_a? ( Net ::LDAP ::PDU )
641662 os = OpenStruct . new
663+ if result . is_a? ( Net ::LDAP ::PDU )
664+ os . extended_response = result . extended_response
665+ result = result . result
666+ end
642667 if result . is_a? ( Hash )
643668 # We might get a hash of LDAP response codes instead of a simple
644669 # numeric code.
@@ -1027,6 +1052,44 @@ def modify(args)
10271052 end
10281053 end
10291054
1055+ # Password Modify
1056+ #
1057+ # Change existing password:
1058+ #
1059+ # dn = 'uid=modify-password-user1,ou=People,dc=rubyldap,dc=com'
1060+ # auth = {
1061+ # method: :simple,
1062+ # username: dn,
1063+ # password: 'passworD1'
1064+ # }
1065+ # ldap.password_modify(dn: dn,
1066+ # auth: auth,
1067+ # old_password: 'passworD1',
1068+ # new_password: 'passworD2')
1069+ #
1070+ # Or get the LDAP server to generate a password for you:
1071+ #
1072+ # dn = 'uid=modify-password-user1,ou=People,dc=rubyldap,dc=com'
1073+ # auth = {
1074+ # method: :simple,
1075+ # username: dn,
1076+ # password: 'passworD1'
1077+ # }
1078+ # ldap.password_modify(dn: dn,
1079+ # auth: auth,
1080+ # old_password: 'passworD1')
1081+ #
1082+ # ldap.get_operation_result.extended_response[0][0] #=> 'VtcgGf/G'
1083+ #
1084+ def password_modify ( args )
1085+ instrument "modify_password.net_ldap" , args do |payload |
1086+ @result = use_connection ( args ) do |conn |
1087+ conn . password_modify ( args )
1088+ end
1089+ @result . success?
1090+ end
1091+ end
1092+
10301093 # Add a value to an attribute. Takes the full DN of the entry to modify,
10311094 # the name (Symbol or String) of the attribute, and the value (String or
10321095 # Array). If the attribute does not exist (and there are no schema
@@ -1247,12 +1310,13 @@ def new_connection
12471310 :port => @port ,
12481311 :hosts => @hosts ,
12491312 :encryption => @encryption ,
1250- :instrumentation_service => @instrumentation_service
1313+ :instrumentation_service => @instrumentation_service ,
1314+ :connect_timeout => @connect_timeout
12511315
12521316 # Force connect to see if there's a connection error
12531317 connection . socket
12541318 connection
1255- rescue Errno ::ECONNREFUSED , Net ::LDAP ::ConnectionRefusedError => e
1319+ rescue Errno ::ECONNREFUSED , Errno :: ETIMEDOUT , Net ::LDAP ::ConnectionRefusedError => e
12561320 @result = {
12571321 :resultCode => 52 ,
12581322 :errorMessage => ResultStrings [ ResultCodeUnavailable ]
0 commit comments