diff --git a/lib/net/ldap.rb b/lib/net/ldap.rb index bf9dcc83..7d758e96 100644 --- a/lib/net/ldap.rb +++ b/lib/net/ldap.rb @@ -325,7 +325,7 @@ class Net::LDAP universal = { constructed: { - 107 => :array, #ExtendedResponse (PasswdModifyResponseValue) + 107 => :string, # ExtendedResponse }, } @@ -341,6 +341,7 @@ class Net::LDAP StartTlsOid = '1.3.6.1.4.1.1466.20037' PasswdModifyOid = '1.3.6.1.4.1.4203.1.11.1' + WhoamiOid = '1.3.6.1.4.1.4203.1.11.3' # https://tools.ietf.org/html/rfc4511#section-4.1.9 # https://tools.ietf.org/html/rfc4511#appendix-A @@ -1200,6 +1201,23 @@ def delete_tree(args) end end + # Return the authorization identity of the client that issues the + # ldapwhoami request. The method does not support any arguments. + # + # Returns True or False to indicate whether the request was successfull. + # The result is available in the extended status information when calling + # #get_operation_result. + # + # ldap.ldapwhoami + # puts ldap.get_operation_result.extended_response + def ldapwhoami(args = {}) + instrument "ldapwhoami.net_ldap", args do |payload| + @result = use_connection(args, &:ldapwhoami) + @result.success? ? @result.extended_response : nil + end + end + alias_method :whoami, :ldapwhoami + # This method is experimental and subject to change. Return the rootDSE # record from the LDAP server as a Net::LDAP::Entry, or an empty Entry if # the server doesn't return the record. diff --git a/lib/net/ldap/connection.rb b/lib/net/ldap/connection.rb index 65fa5330..f1a70b18 100644 --- a/lib/net/ldap/connection.rb +++ b/lib/net/ldap/connection.rb @@ -703,6 +703,22 @@ def delete(args) pdu end + def ldapwhoami + ext_seq = [Net::LDAP::WhoamiOid.to_ber_contextspecific(0)] + request = ext_seq.to_ber_appsequence(Net::LDAP::PDU::ExtendedRequest) + + message_id = next_msgid + + write(request, nil, message_id) + pdu = queued_read(message_id) + + if !pdu || pdu.app_tag != Net::LDAP::PDU::ExtendedResponse + raise Net::LDAP::ResponseMissingOrInvalidError, "response missing or invalid" + end + + pdu + end + # Internal: Returns a Socket like object used internally to communicate with # LDAP server. # diff --git a/lib/net/ldap/pdu.rb b/lib/net/ldap/pdu.rb index 564a23cc..d29db032 100644 --- a/lib/net/ldap/pdu.rb +++ b/lib/net/ldap/pdu.rb @@ -194,13 +194,13 @@ def parse_ldap_result(sequence) # requestValue [1] OCTET STRING OPTIONAL } def parse_extended_response(sequence) - sequence.length >= 3 or raise Net::LDAP::PDU::Error, "Invalid LDAP result length." + sequence.length.between?(3, 5) or raise Net::LDAP::PDU::Error, "Invalid LDAP result length." @ldap_result = { :resultCode => sequence[0], :matchedDN => sequence[1], :errorMessage => sequence[2], } - @extended_response = sequence[3] + @extended_response = sequence.last end private :parse_extended_response diff --git a/test/test_ldap_connection.rb b/test/test_ldap_connection.rb index ca9bcb0b..fdfa418c 100644 --- a/test/test_ldap_connection.rb +++ b/test/test_ldap_connection.rb @@ -574,4 +574,15 @@ def test_search_with_controls # ensure no unread assert unread.empty?, "should not have any leftover unread messages" end + + def test_ldapwhoami + ber = Net::BER::BerIdentifiedArray.new([Net::LDAP::ResultCodeSuccess, '', '', 0, 'dn:uid=zerosteiner,ou=users,dc=example,dc=org']) + ber.ber_identifier = Net::LDAP::PDU::ExtendedResponse + response = [1, ber] + + @tcp_socket.should_receive(:read_ber).and_return(response) + + result = @connection.ldapwhoami + assert result.extended_response == 'dn:uid=zerosteiner,ou=users,dc=example,dc=org' + end end