net-ldap 0.11 → 0.16.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.
Potentially problematic release.
This version of net-ldap might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.rubocop.yml +15 -0
- data/.rubocop_todo.yml +471 -180
- data/.travis.yml +10 -5
- data/Contributors.rdoc +1 -0
- data/History.rdoc +60 -0
- data/README.rdoc +18 -11
- data/Rakefile +0 -1
- 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.rb +37 -5
- data/lib/net/ldap/auth_adapter/gss_spnego.rb +41 -0
- data/lib/net/ldap/auth_adapter/sasl.rb +62 -0
- data/lib/net/ldap/auth_adapter/simple.rb +34 -0
- data/lib/net/ldap/auth_adapter.rb +29 -0
- data/lib/net/ldap/connection.rb +197 -187
- data/lib/net/ldap/dataset.rb +2 -2
- data/lib/net/ldap/dn.rb +4 -5
- data/lib/net/ldap/entry.rb +4 -5
- data/lib/net/ldap/error.rb +36 -1
- data/lib/net/ldap/filter.rb +6 -6
- data/lib/net/ldap/pdu.rb +26 -2
- data/lib/net/ldap/version.rb +1 -1
- data/lib/net/ldap.rb +189 -75
- data/lib/net/snmp.rb +18 -18
- data/net-ldap.gemspec +4 -2
- data/script/changelog +47 -0
- data/script/generate-fixture-ca +48 -0
- data/script/install-openldap +67 -44
- data/test/ber/core_ext/test_array.rb +1 -1
- data/test/ber/test_ber.rb +11 -3
- data/test/fixtures/ca/ca.info +4 -0
- data/test/fixtures/ca/cacert.pem +24 -0
- data/test/fixtures/ca/cakey.pem +190 -0
- data/test/fixtures/openldap/slapd.conf.ldif +1 -1
- data/test/integration/test_add.rb +1 -1
- data/test/integration/test_ber.rb +1 -1
- data/test/integration/test_bind.rb +220 -10
- data/test/integration/test_delete.rb +1 -1
- data/test/integration/test_open.rb +1 -1
- data/test/integration/test_password_modify.rb +80 -0
- data/test/integration/test_search.rb +1 -1
- data/test/support/vm/openldap/README.md +35 -3
- data/test/support/vm/openldap/Vagrantfile +1 -0
- data/test/test_auth_adapter.rb +15 -0
- data/test/test_dn.rb +3 -3
- data/test/test_filter.rb +4 -4
- data/test/test_filter_parser.rb +4 -0
- data/test/test_helper.rb +10 -2
- data/test/test_ldap.rb +64 -10
- data/test/test_ldap_connection.rb +115 -28
- data/test/test_ldif.rb +11 -11
- data/test/test_search.rb +2 -2
- data/test/test_snmp.rb +4 -4
- data/testserver/ldapserver.rb +11 -12
- metadata +50 -8
- data/test/fixtures/cacert.pem +0 -20
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,7 +121,7 @@ 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
126
|
raise LdapPduError.new("unknown pdu-type: #{@app_tag}")
|
126
127
|
end
|
@@ -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
@@ -27,6 +27,12 @@ require 'net/ldap/instrumentation'
|
|
27
27
|
require 'net/ldap/connection'
|
28
28
|
require 'net/ldap/version'
|
29
29
|
require 'net/ldap/error'
|
30
|
+
require 'net/ldap/auth_adapter'
|
31
|
+
require 'net/ldap/auth_adapter/simple'
|
32
|
+
require 'net/ldap/auth_adapter/sasl'
|
33
|
+
|
34
|
+
Net::LDAP::AuthAdapter.register([:simple, :anon, :anonymous], Net::LDAP::AuthAdapter::Simple)
|
35
|
+
Net::LDAP::AuthAdapter.register(:sasl, Net::LDAP::AuthAdapter::Sasl)
|
30
36
|
|
31
37
|
# == Quick-start for the Impatient
|
32
38
|
# === Quick Example of a user-authentication against an LDAP directory:
|
@@ -73,6 +79,14 @@ require 'net/ldap/error'
|
|
73
79
|
#
|
74
80
|
# p ldap.get_operation_result
|
75
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
|
76
90
|
#
|
77
91
|
# == A Brief Introduction to LDAP
|
78
92
|
#
|
@@ -250,14 +264,14 @@ class Net::LDAP
|
|
250
264
|
SearchScope_BaseObject = 0
|
251
265
|
SearchScope_SingleLevel = 1
|
252
266
|
SearchScope_WholeSubtree = 2
|
253
|
-
SearchScopes = [
|
254
|
-
SearchScope_WholeSubtree
|
267
|
+
SearchScopes = [SearchScope_BaseObject, SearchScope_SingleLevel,
|
268
|
+
SearchScope_WholeSubtree]
|
255
269
|
|
256
270
|
DerefAliases_Never = 0
|
257
271
|
DerefAliases_Search = 1
|
258
272
|
DerefAliases_Find = 2
|
259
273
|
DerefAliases_Always = 3
|
260
|
-
DerefAliasesArray = [
|
274
|
+
DerefAliasesArray = [DerefAliases_Never, DerefAliases_Search, DerefAliases_Find, DerefAliases_Always]
|
261
275
|
|
262
276
|
primitive = { 2 => :null } # UnbindRequest body
|
263
277
|
constructed = {
|
@@ -309,7 +323,14 @@ class Net::LDAP
|
|
309
323
|
:constructed => constructed,
|
310
324
|
}
|
311
325
|
|
326
|
+
universal = {
|
327
|
+
constructed: {
|
328
|
+
107 => :array, #ExtendedResponse (PasswdModifyResponseValue)
|
329
|
+
},
|
330
|
+
}
|
331
|
+
|
312
332
|
AsnSyntax = Net::BER.compile_syntax(:application => application,
|
333
|
+
:universal => universal,
|
313
334
|
:context_specific => context_specific)
|
314
335
|
|
315
336
|
DefaultHost = "127.0.0.1"
|
@@ -318,7 +339,8 @@ class Net::LDAP
|
|
318
339
|
DefaultTreebase = "dc=com"
|
319
340
|
DefaultForceNoPage = false
|
320
341
|
|
321
|
-
StartTlsOid =
|
342
|
+
StartTlsOid = '1.3.6.1.4.1.1466.20037'
|
343
|
+
PasswdModifyOid = '1.3.6.1.4.1.4203.1.11.1'
|
322
344
|
|
323
345
|
# https://tools.ietf.org/html/rfc4511#section-4.1.9
|
324
346
|
# https://tools.ietf.org/html/rfc4511#appendix-A
|
@@ -367,14 +389,14 @@ class Net::LDAP
|
|
367
389
|
ResultCodeCompareFalse,
|
368
390
|
ResultCodeCompareTrue,
|
369
391
|
ResultCodeReferral,
|
370
|
-
ResultCodeSaslBindInProgress
|
392
|
+
ResultCodeSaslBindInProgress,
|
371
393
|
]
|
372
394
|
|
373
395
|
# nonstandard list of "successful" result codes for searches
|
374
396
|
ResultCodesSearchSuccess = [
|
375
397
|
ResultCodeSuccess,
|
376
398
|
ResultCodeTimeLimitExceeded,
|
377
|
-
ResultCodeSizeLimitExceeded
|
399
|
+
ResultCodeSizeLimitExceeded,
|
378
400
|
]
|
379
401
|
|
380
402
|
# map of result code to human message
|
@@ -416,7 +438,7 @@ class Net::LDAP
|
|
416
438
|
ResultCodeEntryAlreadyExists => "Entry Already Exists",
|
417
439
|
ResultCodeObjectClassModsProhibited => "ObjectClass Modifications Prohibited",
|
418
440
|
ResultCodeAffectsMultipleDSAs => "Affects Multiple DSAs",
|
419
|
-
ResultCodeOther => "Other"
|
441
|
+
ResultCodeOther => "Other",
|
420
442
|
}
|
421
443
|
|
422
444
|
module LDAPControls
|
@@ -432,6 +454,7 @@ class Net::LDAP
|
|
432
454
|
|
433
455
|
attr_accessor :host
|
434
456
|
attr_accessor :port
|
457
|
+
attr_accessor :hosts
|
435
458
|
attr_accessor :base
|
436
459
|
|
437
460
|
# Instantiate an object of type Net::LDAP to perform directory operations.
|
@@ -440,6 +463,8 @@ class Net::LDAP
|
|
440
463
|
# described below. The following arguments are supported:
|
441
464
|
# * :host => the LDAP server's IP-address (default 127.0.0.1)
|
442
465
|
# * :port => the LDAP server's TCP port (default 389)
|
466
|
+
# * :hosts => an enumerable of pairs of hosts and corresponding ports with
|
467
|
+
# which to attempt opening connections (default [[host, port]])
|
443
468
|
# * :auth => a Hash containing authorization parameters. Currently
|
444
469
|
# supported values include: {:method => :anonymous} and {:method =>
|
445
470
|
# :simple, :username => your_user_name, :password => your_password }
|
@@ -451,28 +476,83 @@ class Net::LDAP
|
|
451
476
|
# specify a treebase. If you give a treebase value in any particular
|
452
477
|
# call to #search, that value will override any treebase value you give
|
453
478
|
# here.
|
454
|
-
# * :encryption => specifies the encryption to be used in communicating
|
455
|
-
# with the LDAP server. The value is either a Hash containing additional
|
456
|
-
# parameters, or the Symbol :simple_tls, which is equivalent to
|
457
|
-
# specifying the Hash {:method => :simple_tls}. There is a fairly large
|
458
|
-
# range of potential values that may be given for this parameter. See
|
459
|
-
# #encryption for details.
|
460
479
|
# * :force_no_page => Set to true to prevent paged results even if your
|
461
480
|
# server says it supports them. This is a fix for MS Active Directory
|
462
481
|
# * :instrumentation_service => An object responsible for instrumenting
|
463
482
|
# operations, compatible with ActiveSupport::Notifications' public API.
|
483
|
+
# * :encryption => specifies the encryption to be used in communicating
|
484
|
+
# with the LDAP server. The value must be a Hash containing additional
|
485
|
+
# parameters, which consists of two keys:
|
486
|
+
# method: - :simple_tls or :start_tls
|
487
|
+
# tls_options: - Hash of options for that method
|
488
|
+
# The :simple_tls encryption method encrypts <i>all</i> communications
|
489
|
+
# with the LDAP server. It completely establishes SSL/TLS encryption with
|
490
|
+
# the LDAP server before any LDAP-protocol data is exchanged. There is no
|
491
|
+
# plaintext negotiation and no special encryption-request controls are
|
492
|
+
# sent to the server. <i>The :simple_tls option is the simplest, easiest
|
493
|
+
# way to encrypt communications between Net::LDAP and LDAP servers.</i>
|
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.
|
501
|
+
# The :start_tls like the :simple_tls encryption method also encrypts all
|
502
|
+
# communcations with the LDAP server. With the exception that it operates
|
503
|
+
# over the standard TCP port.
|
504
|
+
#
|
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...
|
508
|
+
#
|
509
|
+
# Net::LDAP.new(
|
510
|
+
# # ... set host, bind dn, etc ...
|
511
|
+
# encryption: {
|
512
|
+
# method: :simple_tls,
|
513
|
+
# tls_options: OpenSSL::SSL::SSLContext::DEFAULT_PARAMS,
|
514
|
+
# }
|
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
|
464
541
|
#
|
465
542
|
# Instantiating a Net::LDAP object does <i>not</i> result in network
|
466
543
|
# traffic to the LDAP server. It simply stores the connection and binding
|
467
|
-
# 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.
|
468
546
|
def initialize(args = {})
|
469
547
|
@host = args[:host] || DefaultHost
|
470
548
|
@port = args[:port] || DefaultPort
|
549
|
+
@hosts = args[:hosts]
|
471
550
|
@verbose = false # Make this configurable with a switch on the class.
|
472
551
|
@auth = args[:auth] || DefaultAuth
|
473
552
|
@base = args[:base] || DefaultTreebase
|
474
553
|
@force_no_page = args[:force_no_page] || DefaultForceNoPage
|
475
|
-
encryption args[:encryption] # may be nil
|
554
|
+
@encryption = normalize_encryption(args[:encryption]) # may be nil
|
555
|
+
@connect_timeout = args[:connect_timeout]
|
476
556
|
|
477
557
|
if pr = @auth[:password] and pr.respond_to?(:call)
|
478
558
|
@auth[:password] = pr.call
|
@@ -523,7 +603,7 @@ class Net::LDAP
|
|
523
603
|
@auth = {
|
524
604
|
:method => :simple,
|
525
605
|
:username => username,
|
526
|
-
:password => password
|
606
|
+
:password => password,
|
527
607
|
}
|
528
608
|
end
|
529
609
|
alias_method :auth, :authenticate
|
@@ -536,54 +616,12 @@ class Net::LDAP
|
|
536
616
|
# additional capabilities are added, more configuration values will be
|
537
617
|
# added here.
|
538
618
|
#
|
539
|
-
#
|
540
|
-
# with the LDAP server. It completely establishes SSL/TLS encryption with
|
541
|
-
# the LDAP server before any LDAP-protocol data is exchanged. There is no
|
542
|
-
# plaintext negotiation and no special encryption-request controls are
|
543
|
-
# sent to the server. <i>The :simple_tls option is the simplest, easiest
|
544
|
-
# way to encrypt communications between Net::LDAP and LDAP servers.</i>
|
545
|
-
# It's intended for cases where you have an implicit level of trust in the
|
546
|
-
# authenticity of the LDAP server. No validation of the LDAP server's SSL
|
547
|
-
# certificate is performed. This means that :simple_tls will not produce
|
548
|
-
# errors if the LDAP server's encryption certificate is not signed by a
|
549
|
-
# well-known Certification Authority. If you get communications or
|
550
|
-
# protocol errors when using this option, check with your LDAP server
|
551
|
-
# administrator. Pay particular attention to the TCP port you are
|
552
|
-
# connecting to. It's impossible for an LDAP server to support plaintext
|
553
|
-
# LDAP communications and <i>simple TLS</i> connections on the same port.
|
554
|
-
# The standard TCP port for unencrypted LDAP connections is 389, but the
|
555
|
-
# standard port for simple-TLS encrypted connections is 636. Be sure you
|
556
|
-
# are using the correct port.
|
557
|
-
#
|
558
|
-
# The :start_tls like the :simple_tls encryption method also encrypts all
|
559
|
-
# communcations with the LDAP server. With the exception that it operates
|
560
|
-
# over the standard TCP port.
|
561
|
-
#
|
562
|
-
# In order to verify certificates and enable other TLS options, the
|
563
|
-
# :tls_options hash can be passed alongside :simple_tls or :start_tls.
|
564
|
-
# This hash contains any options that can be passed to
|
565
|
-
# OpenSSL::SSL::SSLContext#set_params(). The most common options passed
|
566
|
-
# should be OpenSSL::SSL::SSLContext::DEFAULT_PARAMS, or the :ca_file option,
|
567
|
-
# which contains a path to a Certificate Authority file (PEM-encoded).
|
568
|
-
#
|
569
|
-
# Example for a default setup without custom settings:
|
570
|
-
# {
|
571
|
-
# :method => :simple_tls,
|
572
|
-
# :tls_options => OpenSSL::SSL::SSLContext::DEFAULT_PARAMS
|
573
|
-
# }
|
574
|
-
#
|
575
|
-
# Example for specifying a CA-File and only allowing TLSv1.1 connections:
|
619
|
+
# This method is deprecated.
|
576
620
|
#
|
577
|
-
# {
|
578
|
-
# :method => :start_tls,
|
579
|
-
# :tls_options => { :ca_file => "/etc/cafile.pem", :ssl_version => "TLSv1_1" }
|
580
|
-
# }
|
581
621
|
def encryption(args)
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
end
|
586
|
-
@encryption = args
|
622
|
+
warn "Deprecation warning: please give :encryption option as a Hash to Net::LDAP.new"
|
623
|
+
return if args.nil?
|
624
|
+
@encryption = normalize_encryption(args)
|
587
625
|
end
|
588
626
|
|
589
627
|
# #open takes the same parameters as #new. #open makes a network
|
@@ -627,8 +665,11 @@ class Net::LDAP
|
|
627
665
|
#++
|
628
666
|
def get_operation_result
|
629
667
|
result = @result
|
630
|
-
result = result.result if result.is_a?(Net::LDAP::PDU)
|
631
668
|
os = OpenStruct.new
|
669
|
+
if result.is_a?(Net::LDAP::PDU)
|
670
|
+
os.extended_response = result.extended_response
|
671
|
+
result = result.result
|
672
|
+
end
|
632
673
|
if result.is_a?(Hash)
|
633
674
|
# We might get a hash of LDAP response codes instead of a simple
|
634
675
|
# numeric code.
|
@@ -740,10 +781,10 @@ class Net::LDAP
|
|
740
781
|
|
741
782
|
instrument "search.net_ldap", args do |payload|
|
742
783
|
@result = use_connection(args) do |conn|
|
743
|
-
conn.search(args)
|
784
|
+
conn.search(args) do |entry|
|
744
785
|
result_set << entry if result_set
|
745
786
|
yield entry if block_given?
|
746
|
-
|
787
|
+
end
|
747
788
|
end
|
748
789
|
|
749
790
|
if return_result_set
|
@@ -882,7 +923,7 @@ class Net::LDAP
|
|
882
923
|
# end
|
883
924
|
def bind_as(args = {})
|
884
925
|
result = false
|
885
|
-
open
|
926
|
+
open do |me|
|
886
927
|
rs = search args
|
887
928
|
if rs and rs.first and dn = rs.first.dn
|
888
929
|
password = args[:password]
|
@@ -890,7 +931,7 @@ class Net::LDAP
|
|
890
931
|
result = rs if bind(:method => :simple, :username => dn,
|
891
932
|
:password => password)
|
892
933
|
end
|
893
|
-
|
934
|
+
end
|
894
935
|
result
|
895
936
|
end
|
896
937
|
|
@@ -1017,6 +1058,44 @@ class Net::LDAP
|
|
1017
1058
|
end
|
1018
1059
|
end
|
1019
1060
|
|
1061
|
+
# Password Modify
|
1062
|
+
#
|
1063
|
+
# Change existing password:
|
1064
|
+
#
|
1065
|
+
# dn = 'uid=modify-password-user1,ou=People,dc=rubyldap,dc=com'
|
1066
|
+
# auth = {
|
1067
|
+
# method: :simple,
|
1068
|
+
# username: dn,
|
1069
|
+
# password: 'passworD1'
|
1070
|
+
# }
|
1071
|
+
# ldap.password_modify(dn: dn,
|
1072
|
+
# auth: auth,
|
1073
|
+
# old_password: 'passworD1',
|
1074
|
+
# new_password: 'passworD2')
|
1075
|
+
#
|
1076
|
+
# Or get the LDAP server to generate a password for you:
|
1077
|
+
#
|
1078
|
+
# dn = 'uid=modify-password-user1,ou=People,dc=rubyldap,dc=com'
|
1079
|
+
# auth = {
|
1080
|
+
# method: :simple,
|
1081
|
+
# username: dn,
|
1082
|
+
# password: 'passworD1'
|
1083
|
+
# }
|
1084
|
+
# ldap.password_modify(dn: dn,
|
1085
|
+
# auth: auth,
|
1086
|
+
# old_password: 'passworD1')
|
1087
|
+
#
|
1088
|
+
# ldap.get_operation_result.extended_response[0][0] #=> 'VtcgGf/G'
|
1089
|
+
#
|
1090
|
+
def password_modify(args)
|
1091
|
+
instrument "modify_password.net_ldap", args do |payload|
|
1092
|
+
@result = use_connection(args) do |conn|
|
1093
|
+
conn.password_modify(args)
|
1094
|
+
end
|
1095
|
+
@result.success?
|
1096
|
+
end
|
1097
|
+
end
|
1098
|
+
|
1020
1099
|
# Add a value to an attribute. Takes the full DN of the entry to modify,
|
1021
1100
|
# the name (Symbol or String) of the attribute, and the value (String or
|
1022
1101
|
# Array). If the attribute does not exist (and there are no schema
|
@@ -1135,7 +1214,7 @@ class Net::LDAP
|
|
1135
1214
|
:supportedExtension,
|
1136
1215
|
:supportedFeatures,
|
1137
1216
|
:supportedLdapVersion,
|
1138
|
-
:supportedSASLMechanisms
|
1217
|
+
:supportedSASLMechanisms,
|
1139
1218
|
])
|
1140
1219
|
(rs and rs.first) or Net::LDAP::Entry.new
|
1141
1220
|
end
|
@@ -1195,6 +1274,18 @@ class Net::LDAP
|
|
1195
1274
|
@server_caps[:supportedcontrol].include?(Net::LDAP::LDAPControls::PAGED_RESULTS)
|
1196
1275
|
end
|
1197
1276
|
|
1277
|
+
# Mask auth password
|
1278
|
+
def inspect
|
1279
|
+
inspected = super
|
1280
|
+
inspected.gsub! @auth[:password], "*******" if @auth[:password]
|
1281
|
+
inspected
|
1282
|
+
end
|
1283
|
+
|
1284
|
+
# Internal: Set @open_connection for testing
|
1285
|
+
def connection=(connection)
|
1286
|
+
@open_connection = connection
|
1287
|
+
end
|
1288
|
+
|
1198
1289
|
private
|
1199
1290
|
|
1200
1291
|
# Yields an open connection if there is one, otherwise establishes a new
|
@@ -1207,11 +1298,9 @@ class Net::LDAP
|
|
1207
1298
|
else
|
1208
1299
|
begin
|
1209
1300
|
conn = new_connection
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
1213
|
-
return result
|
1214
|
-
end
|
1301
|
+
result = conn.bind(args[:auth] || @auth)
|
1302
|
+
return result unless result.result_code == Net::LDAP::ResultCodeSuccess
|
1303
|
+
yield conn
|
1215
1304
|
ensure
|
1216
1305
|
conn.close if conn
|
1217
1306
|
end
|
@@ -1220,10 +1309,35 @@ class Net::LDAP
|
|
1220
1309
|
|
1221
1310
|
# Establish a new connection to the LDAP server
|
1222
1311
|
def new_connection
|
1223
|
-
Net::LDAP::Connection.new \
|
1312
|
+
connection = Net::LDAP::Connection.new \
|
1224
1313
|
:host => @host,
|
1225
1314
|
:port => @port,
|
1315
|
+
:hosts => @hosts,
|
1226
1316
|
:encryption => @encryption,
|
1227
|
-
:instrumentation_service => @instrumentation_service
|
1317
|
+
:instrumentation_service => @instrumentation_service,
|
1318
|
+
:connect_timeout => @connect_timeout
|
1319
|
+
|
1320
|
+
# Force connect to see if there's a connection error
|
1321
|
+
connection.socket
|
1322
|
+
connection
|
1323
|
+
rescue Errno::ECONNREFUSED, Errno::ETIMEDOUT, Net::LDAP::ConnectionRefusedError => e
|
1324
|
+
@result = {
|
1325
|
+
:resultCode => 52,
|
1326
|
+
:errorMessage => ResultStrings[ResultCodeUnavailable],
|
1327
|
+
}
|
1328
|
+
raise e
|
1329
|
+
end
|
1330
|
+
|
1331
|
+
# Normalize encryption parameter the constructor accepts, expands a few
|
1332
|
+
# convenience symbols into recognizable hashes
|
1333
|
+
def normalize_encryption(args)
|
1334
|
+
return if args.nil?
|
1335
|
+
return args if args.is_a? Hash
|
1336
|
+
|
1337
|
+
case method = args.to_sym
|
1338
|
+
when :simple_tls, :start_tls
|
1339
|
+
{ :method => method, :tls_options => {} }
|
1340
|
+
end
|
1228
1341
|
end
|
1342
|
+
|
1229
1343
|
end # class LDAP
|
data/lib/net/snmp.rb
CHANGED
@@ -12,7 +12,7 @@ module Net
|
|
12
12
|
2 => :integer, # Gauge32 or Unsigned32, (RFC2578 sec 2)
|
13
13
|
3 => :integer # TimeTicks32, (RFC2578 sec 2)
|
14
14
|
},
|
15
|
-
:constructed => {}
|
15
|
+
:constructed => {},
|
16
16
|
},
|
17
17
|
:context_specific => {
|
18
18
|
:primitive => {},
|
@@ -20,8 +20,8 @@ module Net
|
|
20
20
|
0 => :array, # GetRequest PDU (RFC1157 pgh 4.1.2)
|
21
21
|
1 => :array, # GetNextRequest PDU (RFC1157 pgh 4.1.3)
|
22
22
|
2 => :array # GetResponse PDU (RFC1157 pgh 4.1.4)
|
23
|
-
}
|
24
|
-
}
|
23
|
+
},
|
24
|
+
},
|
25
25
|
})
|
26
26
|
|
27
27
|
# SNMP 32-bit counter.
|
@@ -70,7 +70,7 @@ module Net
|
|
70
70
|
:get_next_request,
|
71
71
|
:get_response,
|
72
72
|
:set_request,
|
73
|
-
:trap
|
73
|
+
:trap,
|
74
74
|
]
|
75
75
|
ErrorStatusCodes = { # Per RFC1157, pgh 4.1.1
|
76
76
|
0 => "noError",
|
@@ -78,7 +78,7 @@ module Net
|
|
78
78
|
2 => "noSuchName",
|
79
79
|
3 => "badValue",
|
80
80
|
4 => "readOnly",
|
81
|
-
5 => "genErr"
|
81
|
+
5 => "genErr",
|
82
82
|
}
|
83
83
|
|
84
84
|
class << self
|
@@ -148,7 +148,7 @@ module Net
|
|
148
148
|
# data[2] is error_index, always zero.
|
149
149
|
send :error_status=, 0
|
150
150
|
send :error_index=, 0
|
151
|
-
data[3].each do |n,v|
|
151
|
+
data[3].each do |n, v|
|
152
152
|
# A variable-binding, of which there may be several,
|
153
153
|
# consists of an OID and a BER null.
|
154
154
|
# We're ignoring the null, we might want to verify it instead.
|
@@ -166,7 +166,7 @@ module Net
|
|
166
166
|
send :request_id=, data[0].to_i
|
167
167
|
send :error_status=, data[1].to_i
|
168
168
|
send :error_index=, data[2].to_i
|
169
|
-
data[3].each do |n,v|
|
169
|
+
data[3].each do |n, v|
|
170
170
|
# A variable-binding, of which there may be several,
|
171
171
|
# consists of an OID and a BER null.
|
172
172
|
# We're ignoring the null, we might want to verify it instead.
|
@@ -177,7 +177,7 @@ module Net
|
|
177
177
|
|
178
178
|
|
179
179
|
def version= ver
|
180
|
-
unless [0,2].include?(ver)
|
180
|
+
unless [0, 2].include?(ver)
|
181
181
|
raise Error.new("unknown snmp-version: #{ver}")
|
182
182
|
end
|
183
183
|
@version = ver
|
@@ -191,7 +191,7 @@ module Net
|
|
191
191
|
end
|
192
192
|
|
193
193
|
def error_status= es
|
194
|
-
unless ErrorStatusCodes.
|
194
|
+
unless ErrorStatusCodes.key?(es)
|
195
195
|
raise Error.new("unknown error-status: #{es}")
|
196
196
|
end
|
197
197
|
@error_status = es
|
@@ -227,10 +227,10 @@ module Net
|
|
227
227
|
error_status.to_ber,
|
228
228
|
error_index.to_ber,
|
229
229
|
[
|
230
|
-
@variables.map
|
230
|
+
@variables.map do|n, v|
|
231
231
|
[n.to_ber_oid, Net::BER::BerIdentifiedNull.new.to_ber].to_ber_sequence
|
232
|
-
|
233
|
-
].to_ber_sequence
|
232
|
+
end,
|
233
|
+
].to_ber_sequence,
|
234
234
|
].to_ber_contextspecific(0)
|
235
235
|
when :get_next_request
|
236
236
|
[
|
@@ -238,10 +238,10 @@ module Net
|
|
238
238
|
error_status.to_ber,
|
239
239
|
error_index.to_ber,
|
240
240
|
[
|
241
|
-
@variables.map
|
241
|
+
@variables.map do|n, v|
|
242
242
|
[n.to_ber_oid, Net::BER::BerIdentifiedNull.new.to_ber].to_ber_sequence
|
243
|
-
|
244
|
-
].to_ber_sequence
|
243
|
+
end,
|
244
|
+
].to_ber_sequence,
|
245
245
|
].to_ber_contextspecific(1)
|
246
246
|
when :get_response
|
247
247
|
[
|
@@ -249,10 +249,10 @@ module Net
|
|
249
249
|
error_status.to_ber,
|
250
250
|
error_index.to_ber,
|
251
251
|
[
|
252
|
-
@variables.map
|
252
|
+
@variables.map do|n, v|
|
253
253
|
[n.to_ber_oid, v.to_ber].to_ber_sequence
|
254
|
-
|
255
|
-
].to_ber_sequence
|
254
|
+
end,
|
255
|
+
].to_ber_sequence,
|
256
256
|
].to_ber_contextspecific(2)
|
257
257
|
else
|
258
258
|
raise Error.new( "unknown pdu-type: #{pdu_type}" )
|
data/net-ldap.gemspec
CHANGED
@@ -26,10 +26,12 @@ the most recent LDAP RFCs (4510-4519, plutions of 4520-4532).}
|
|
26
26
|
s.homepage = %q{http://github.com/ruby-ldap/ruby-net-ldap}
|
27
27
|
s.rdoc_options = ["--main", "README.rdoc"]
|
28
28
|
s.require_paths = ["lib"]
|
29
|
-
s.required_ruby_version = ">=
|
29
|
+
s.required_ruby_version = ">= 2.0.0"
|
30
30
|
s.summary = %q{Net::LDAP for Ruby (also called net-ldap) implements client access for the Lightweight Directory Access Protocol (LDAP), an IETF standard protocol for accessing distributed directory services}
|
31
31
|
|
32
32
|
s.add_development_dependency("flexmock", "~> 1.3")
|
33
33
|
s.add_development_dependency("rake", "~> 10.0")
|
34
|
-
s.add_development_dependency("rubocop", "~> 0.
|
34
|
+
s.add_development_dependency("rubocop", "~> 0.42.0")
|
35
|
+
s.add_development_dependency("test-unit")
|
36
|
+
s.add_development_dependency("byebug")
|
35
37
|
end
|
data/script/changelog
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
# Usage: script/changelog [-r <repo>] [-b <base>] [-h <head>]
|
3
|
+
#
|
4
|
+
# repo: BASE string of GitHub REPOsitory url. e.g. "user_or_org/REPOsitory". Defaults to git remote url.
|
5
|
+
# base: git ref to compare from. e.g. "v1.3.1". Defaults to latest git tag.
|
6
|
+
# head: git ref to compare to. Defaults to "HEAD".
|
7
|
+
#
|
8
|
+
# Generate a changelog preview from pull requests merged between `base` and
|
9
|
+
# `head`.
|
10
|
+
#
|
11
|
+
# https://github.com/jch/release-scripts/blob/master/changelog
|
12
|
+
set -e
|
13
|
+
|
14
|
+
[ $# -eq 0 ] && set -- --help
|
15
|
+
while [[ $# > 1 ]]
|
16
|
+
do
|
17
|
+
key="$1"
|
18
|
+
case $key in
|
19
|
+
-r|--repo)
|
20
|
+
repo="$2"
|
21
|
+
shift
|
22
|
+
;;
|
23
|
+
-b|--base)
|
24
|
+
base="$2"
|
25
|
+
shift
|
26
|
+
;;
|
27
|
+
-h|--head)
|
28
|
+
head="$2"
|
29
|
+
shift
|
30
|
+
;;
|
31
|
+
*)
|
32
|
+
;;
|
33
|
+
esac
|
34
|
+
shift
|
35
|
+
done
|
36
|
+
|
37
|
+
repo="${repo:-$(git remote -v | grep push | awk '{print $2}' | cut -d'/' -f4- | sed 's/\.git//')}"
|
38
|
+
base="${base:-$(git tag -l | sort -t. -k 1,1n -k 2,2n -k 3,3n | tail -n 1)}"
|
39
|
+
head="${head:-HEAD}"
|
40
|
+
api_url="https://api.github.com"
|
41
|
+
|
42
|
+
# get merged PR's. Better way is to query the API for these, but this is easier
|
43
|
+
for pr in $(git log --oneline $base..$head | grep "Merge pull request" | awk '{gsub("#",""); print $5}')
|
44
|
+
do
|
45
|
+
# frustrated with trying to pull out the right values, fell back to ruby
|
46
|
+
curl -s "$api_url/repos/$repo/pulls/$pr" | ruby -rjson -e 'pr=JSON.parse(STDIN.read); puts "* #{pr[%q(title)]} {##{pr[%q(number)]}}[#{pr[%q(html_url)]}]"'
|
47
|
+
done
|