Skip to content

Commit 77de98c

Browse files
Merge branch 'ruby-ldap:master' into master
2 parents ed85aff + a562790 commit 77de98c

File tree

10 files changed

+133
-43
lines changed

10 files changed

+133
-43
lines changed

Diff for: .github/workflows/test.yml

+3-5
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,13 @@ jobs:
1919
strategy:
2020
matrix:
2121
ruby:
22-
- "2.6"
23-
- "2.7"
2422
- "3.0"
2523
- "3.1"
2624
- "3.2"
27-
- "jruby-9.3"
25+
- "3.3"
2826
- "jruby-9.4"
29-
- "truffleruby-22"
27+
- "truffleruby"
3028
steps:
3129
- uses: actions/checkout@v2
3230
- name: Run tests with Ruby ${{ matrix.ruby }}
33-
run: docker-compose run ci-${{ matrix.ruby }}
31+
run: docker compose run ci-${{ matrix.ruby }}

Diff for: .rubocop_todo.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ Metrics/BlockNesting:
293293
# Offense count: 11
294294
# Configuration parameters: CountComments, CountAsOne.
295295
Metrics/ClassLength:
296-
Max: 443
296+
Max: 451
297297

298298
# Offense count: 20
299299
# Configuration parameters: AllowedMethods, AllowedPatterns.

Diff for: README.rdoc

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ the most recent LDAP RFCs (4510–4519, plus portions of 4520–4532).
2323

2424
== Synopsis
2525

26-
See {Net::LDAP on rubydoc.info}[https://www.rubydoc.info/github/ruby-ldap/ruby-net-ldap] for documentation and usage samples.
26+
See {Net::LDAP on rubydoc.info}[https://www.rubydoc.info/github/ruby-ldap/ruby-net-ldap/Net/LDAP] for documentation and usage samples.
2727

2828
== Requirements
2929

Diff for: docker-compose.yml

+10-26
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
version: "3.8"
2-
31
networks:
42
integration_test_network:
53

@@ -24,22 +22,8 @@ services:
2422
volumes:
2523
- ./test/fixtures/ldif:/ldif:ro
2624

27-
ci-2.6:
28-
image: ruby:2.7
29-
entrypoint: /code/ci-run.sh
30-
environment:
31-
INTEGRATION: openldap
32-
INTEGRATION_HOST: ldap.example.org
33-
depends_on:
34-
- openldap
35-
networks:
36-
integration_test_network:
37-
volumes:
38-
- .:/code
39-
working_dir: /code
40-
41-
ci-2.7:
42-
image: ruby:2.7
25+
ci-3.0:
26+
image: ruby:3.0
4327
entrypoint: /code/ci-run.sh
4428
environment:
4529
INTEGRATION: openldap
@@ -52,8 +36,8 @@ services:
5236
- .:/code
5337
working_dir: /code
5438

55-
ci-3.0:
56-
image: ruby:3.0
39+
ci-3.1:
40+
image: ruby:3.1
5741
entrypoint: /code/ci-run.sh
5842
environment:
5943
INTEGRATION: openldap
@@ -66,8 +50,8 @@ services:
6650
- .:/code
6751
working_dir: /code
6852

69-
ci-3.1:
70-
image: ruby:3.1
53+
ci-3.2:
54+
image: ruby:3.2
7155
entrypoint: /code/ci-run.sh
7256
environment:
7357
INTEGRATION: openldap
@@ -80,8 +64,8 @@ services:
8064
- .:/code
8165
working_dir: /code
8266

83-
ci-3.2:
84-
image: ruby:3.2
67+
ci-3.3:
68+
image: ruby:3.3
8569
entrypoint: /code/ci-run.sh
8670
environment:
8771
INTEGRATION: openldap
@@ -95,8 +79,8 @@ services:
9579
working_dir: /code
9680

9781
# https://github.com/flavorjones/truffleruby/pkgs/container/truffleruby
98-
ci-truffleruby-22:
99-
image: ghcr.io/flavorjones/truffleruby:22.3.1
82+
ci-truffleruby:
83+
image: ghcr.io/flavorjones/truffleruby:stable
10084
entrypoint: /code/ci-run.sh
10185
environment:
10286
INTEGRATION: openldap

Diff for: lib/net/ldap.rb

+20-2
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ class Net::LDAP
311311
0 => :array, # RFC-2251 Control and Filter-AND
312312
1 => :array, # SearchFilter-OR
313313
2 => :array, # SearchFilter-NOT
314-
3 => :array, # Seach referral
314+
3 => :array, # Search referral
315315
4 => :array, # unknown use in Microsoft Outlook
316316
5 => :array, # SearchFilter-GE
317317
6 => :array, # SearchFilter-LE
@@ -325,7 +325,7 @@ class Net::LDAP
325325

326326
universal = {
327327
constructed: {
328-
107 => :array, #ExtendedResponse (PasswdModifyResponseValue)
328+
107 => :string, # ExtendedResponse
329329
},
330330
}
331331

@@ -341,6 +341,7 @@ class Net::LDAP
341341

342342
StartTlsOid = '1.3.6.1.4.1.1466.20037'
343343
PasswdModifyOid = '1.3.6.1.4.1.4203.1.11.1'
344+
WhoamiOid = '1.3.6.1.4.1.4203.1.11.3'
344345

345346
# https://tools.ietf.org/html/rfc4511#section-4.1.9
346347
# https://tools.ietf.org/html/rfc4511#appendix-A
@@ -1200,6 +1201,23 @@ def delete_tree(args)
12001201
end
12011202
end
12021203

1204+
# Return the authorization identity of the client that issues the
1205+
# ldapwhoami request. The method does not support any arguments.
1206+
#
1207+
# Returns True or False to indicate whether the request was successfull.
1208+
# The result is available in the extended status information when calling
1209+
# #get_operation_result.
1210+
#
1211+
# ldap.ldapwhoami
1212+
# puts ldap.get_operation_result.extended_response
1213+
def ldapwhoami(args = {})
1214+
instrument "ldapwhoami.net_ldap", args do |payload|
1215+
@result = use_connection(args, &:ldapwhoami)
1216+
@result.success? ? @result.extended_response : nil
1217+
end
1218+
end
1219+
alias_method :whoami, :ldapwhoami
1220+
12031221
# This method is experimental and subject to change. Return the rootDSE
12041222
# record from the LDAP server as a Net::LDAP::Entry, or an empty Entry if
12051223
# the server doesn't return the record.

Diff for: lib/net/ldap/connection.rb

+28-2
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,12 @@ def modify(args)
569569
ops.to_ber_sequence,
570570
].to_ber_appsequence(Net::LDAP::PDU::ModifyRequest)
571571

572-
write(request, nil, message_id)
572+
controls = args.fetch(:controls, nil)
573+
unless controls.nil?
574+
controls = controls.to_ber_contextspecific(0)
575+
end
576+
577+
write(request, controls, message_id)
573578
pdu = queued_read(message_id)
574579

575580
if !pdu || pdu.app_tag != Net::LDAP::PDU::ModifyResponse
@@ -641,7 +646,12 @@ def add(args)
641646
message_id = next_msgid
642647
request = [add_dn.to_ber, add_attrs.to_ber_sequence].to_ber_appsequence(Net::LDAP::PDU::AddRequest)
643648

644-
write(request, nil, message_id)
649+
controls = args.fetch(:controls, nil)
650+
unless controls.nil?
651+
controls = controls.to_ber_contextspecific(0)
652+
end
653+
654+
write(request, controls, message_id)
645655
pdu = queued_read(message_id)
646656

647657
if !pdu || pdu.app_tag != Net::LDAP::PDU::AddResponse
@@ -693,6 +703,22 @@ def delete(args)
693703
pdu
694704
end
695705

706+
def ldapwhoami
707+
ext_seq = [Net::LDAP::WhoamiOid.to_ber_contextspecific(0)]
708+
request = ext_seq.to_ber_appsequence(Net::LDAP::PDU::ExtendedRequest)
709+
710+
message_id = next_msgid
711+
712+
write(request, nil, message_id)
713+
pdu = queued_read(message_id)
714+
715+
if !pdu || pdu.app_tag != Net::LDAP::PDU::ExtendedResponse
716+
raise Net::LDAP::ResponseMissingOrInvalidError, "response missing or invalid"
717+
end
718+
719+
pdu
720+
end
721+
696722
# Internal: Returns a Socket like object used internally to communicate with
697723
# LDAP server.
698724
#

Diff for: lib/net/ldap/pdu.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -194,13 +194,13 @@ def parse_ldap_result(sequence)
194194
# requestValue [1] OCTET STRING OPTIONAL }
195195

196196
def parse_extended_response(sequence)
197-
sequence.length >= 3 or raise Net::LDAP::PDU::Error, "Invalid LDAP result length."
197+
sequence.length.between?(3, 5) or raise Net::LDAP::PDU::Error, "Invalid LDAP result length."
198198
@ldap_result = {
199199
:resultCode => sequence[0],
200200
:matchedDN => sequence[1],
201201
:errorMessage => sequence[2],
202202
}
203-
@extended_response = sequence[3]
203+
@extended_response = sequence.length == 3 ? nil : sequence.last
204204
end
205205
private :parse_extended_response
206206

Diff for: net-ldap.gemspec

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@ the most recent LDAP RFCs (4510-4519, plutions of 4520-4532).}
2626
s.homepage = %q{http://github.com/ruby-ldap/ruby-net-ldap}
2727
s.rdoc_options = ["--main", "README.rdoc"]
2828
s.require_paths = ["lib"]
29-
s.required_ruby_version = ">= 2.0.0"
29+
s.required_ruby_version = ">= 3.0.0"
3030
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}
3131

32+
s.add_dependency("ostruct")
3233
s.add_development_dependency("flexmock", "~> 1.3")
3334
s.add_development_dependency("rake", "~> 12.3.3")
3435
s.add_development_dependency("rubocop", "~> 1.48")

Diff for: test/integration/test_password_modify.rb

+21-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
require_relative '../test_helper'
22

33
class TestPasswordModifyIntegration < LDAPIntegrationTestCase
4+
# see: https://www.rfc-editor.org/rfc/rfc3062#section-2
5+
PASSWORD_MODIFY_SYNTAX = Net::BER.compile_syntax(
6+
application: {},
7+
universal: {},
8+
context_specific: { primitive: { 0 => :string } },
9+
)
10+
411
def setup
512
super
613
@admin_account = { dn: 'cn=admin,dc=example,dc=org', password: 'admin', method: :simple }
@@ -49,7 +56,13 @@ def test_password_modify_generate
4956
auth: @auth,
5057
old_password: 'admin')
5158

52-
generated_password = @ldap.get_operation_result.extended_response[0][0]
59+
passwd_modify_response_value = @ldap.get_operation_result.extended_response
60+
seq = Net::BER::BerIdentifiedArray.new
61+
sio = StringIO.new(passwd_modify_response_value)
62+
until (e = sio.read_ber(PASSWORD_MODIFY_SYNTAX)).nil?
63+
seq << e
64+
end
65+
generated_password = seq[0][0]
5366

5467
assert generated_password, 'Should have generated a password'
5568

@@ -64,8 +77,13 @@ def test_password_modify_generate_no_old_password
6477
assert @ldap.password_modify(dn: @dn,
6578
auth: @auth)
6679

67-
generated_password = @ldap.get_operation_result.extended_response[0][0]
68-
80+
passwd_modify_response_value = @ldap.get_operation_result.extended_response
81+
seq = Net::BER::BerIdentifiedArray.new
82+
sio = StringIO.new(passwd_modify_response_value)
83+
until (e = sio.read_ber(PASSWORD_MODIFY_SYNTAX)).nil?
84+
seq << e
85+
end
86+
generated_password = seq[0][0]
6987
assert generated_password, 'Should have generated a password'
7088

7189
refute @ldap.bind(username: @dn, password: 'admin', method: :simple),

Diff for: test/test_ldap_connection.rb

+45
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,40 @@ def test_search_net_ldap_connection_event
502502
assert unread.empty?, "should not have any leftover unread messages"
503503
end
504504

505+
def test_add_with_controls
506+
dacl_flag = 0x4 # DACL_SECURITY_INFORMATION
507+
control_values = [dacl_flag].map(&:to_ber).to_ber_sequence.to_s.to_ber
508+
controls = []
509+
# LDAP_SERVER_SD_FLAGS constant definition, taken from https://ldapwiki.com/wiki/LDAP_SERVER_SD_FLAGS_OID
510+
ldap_server_sd_flags = '1.2.840.113556.1.4.801'.freeze
511+
controls << [ldap_server_sd_flags.to_ber, true.to_ber, control_values].to_ber_sequence
512+
513+
ber = Net::BER::BerIdentifiedArray.new([Net::LDAP::ResultCodeSuccess, "", ""])
514+
ber.ber_identifier = Net::LDAP::PDU::AddResponse
515+
@tcp_socket.should_receive(:read_ber).and_return([1, ber])
516+
517+
result = @connection.add(:dn => "uid=added-user1,ou=People,dc=rubyldap,dc=com", :controls => controls)
518+
assert result.success?, "should be success"
519+
assert_equal "", result.error_message
520+
end
521+
522+
def test_modify_with_controls
523+
dacl_flag = 0x4 # DACL_SECURITY_INFORMATION
524+
control_values = [dacl_flag].map(&:to_ber).to_ber_sequence.to_s.to_ber
525+
controls = []
526+
# LDAP_SERVER_SD_FLAGS constant definition, taken from https://ldapwiki.com/wiki/LDAP_SERVER_SD_FLAGS_OID
527+
ldap_server_sd_flags = '1.2.840.113556.1.4.801'.freeze
528+
controls << [ldap_server_sd_flags.to_ber, true.to_ber, control_values].to_ber_sequence
529+
530+
ber = Net::BER::BerIdentifiedArray.new([Net::LDAP::ResultCodeSuccess, "", ""])
531+
ber.ber_identifier = Net::LDAP::PDU::ModifyResponse
532+
@tcp_socket.should_receive(:read_ber).and_return([1, ber])
533+
534+
result = @connection.modify(:dn => "1", :operations => [[:replace, "mail", "[email protected]"]], :controls => controls)
535+
assert result.success?, "should be success"
536+
assert_equal "", result.error_message
537+
end
538+
505539
def test_search_with_controls
506540
# search data
507541
search_data_ber = Net::BER::BerIdentifiedArray.new([1, [
@@ -540,4 +574,15 @@ def test_search_with_controls
540574
# ensure no unread
541575
assert unread.empty?, "should not have any leftover unread messages"
542576
end
577+
578+
def test_ldapwhoami
579+
ber = Net::BER::BerIdentifiedArray.new([Net::LDAP::ResultCodeSuccess, '', '', 0, 'dn:uid=zerosteiner,ou=users,dc=example,dc=org'])
580+
ber.ber_identifier = Net::LDAP::PDU::ExtendedResponse
581+
response = [1, ber]
582+
583+
@tcp_socket.should_receive(:read_ber).and_return(response)
584+
585+
result = @connection.ldapwhoami
586+
assert result.extended_response == 'dn:uid=zerosteiner,ou=users,dc=example,dc=org'
587+
end
543588
end

0 commit comments

Comments
 (0)