Class: Net::LDAP::Connection

Inherits:
Object
  • Object
show all
Defined in:
lib/net/ldap.rb

Overview

This is a private class used internally by the library. It should not be called by user code.

Constant Summary collapse

LdapVersion =

:nodoc:

3

Instance Method Summary collapse

Constructor Details

#initialize(server) {|_self| ... } ⇒ Connection

– initialize

Yields:

  • (_self)

Yield Parameters:



804
805
806
807
808
809
810
811
812
# File 'lib/net/ldap.rb', line 804

def initialize server
  begin
    @conn = TCPsocket.new( server[:host], server[:port] )
  rescue
    raise LdapError.new( "no connection to server" )
  end

  yield self if block_given?
end

Instance Method Details

#add(args) ⇒ Object

– add TODO, need to support a time limit, in case the server fails to respond.



985
986
987
988
989
990
991
992
993
994
995
996
997
998
# File 'lib/net/ldap.rb', line 985

def add args
  add_dn = args[:dn] or raise LdapError.new("Unable to add empty DN")
  add_attrs = []
  a = args[:attributes] and a.each {|k,v|
    add_attrs << [ k.to_s.to_ber, v.to_a.map {|m| m.to_ber}.to_ber_set ].to_ber_sequence
  }

  request = [add_dn.to_ber, add_attrs.to_ber_sequence].to_ber_appsequence(8)
  pkt = [next_msgid.to_ber, request].to_ber_sequence
  @conn.write pkt

  (be = @conn.read_ber(AsnSyntax)) && (pdu = LdapPdu.new( be )) && (pdu.app_tag == 9) or raise LdapError.new( "response missing or invalid" )
  pdu.result_code
end

#bind(auth) ⇒ Object

– bind

Raises:



838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
# File 'lib/net/ldap.rb', line 838

def bind auth
  user,psw = case auth[:method]
  when :anonymous
    ["",""]
  when :simple
    [auth[:username] || auth[:dn], auth[:password]]
  end
  raise LdapError.new( "invalid binding information" ) unless (user && psw)

  msgid = next_msgid.to_ber
  request = [LdapVersion.to_ber, user.to_ber, psw.to_ber_contextspecific(0)].to_ber_appsequence(0)
  request_pkt = [msgid, request].to_ber_sequence
  @conn.write request_pkt

  (be = @conn.read_ber(AsnSyntax) and pdu = Net::LdapPdu.new( be )) or raise LdapError.new( "no bind result" )
  pdu.result_code
end

#closeObject

– close This is provided as a convenience method to make sure a connection object gets closed without waiting for a GC to happen. Clients shouldn’t have to call it, but perhaps it will come in handy someday.



821
822
823
824
# File 'lib/net/ldap.rb', line 821

def close
  @conn.close
  @conn = nil
end

#delete(args) ⇒ Object

– delete TODO, need to support a time limit, in case the server fails to respond.



1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
# File 'lib/net/ldap.rb', line 1023

def delete args
  dn = args[:dn] or raise "Unable to delete empty DN"

  request = dn.to_s.to_ber_application_string(10)
  pkt = [next_msgid.to_ber, request].to_ber_sequence
  @conn.write pkt

  (be = @conn.read_ber(AsnSyntax)) && (pdu = LdapPdu.new( be )) && (pdu.app_tag == 11) or raise LdapError.new( "response missing or invalid" )
  pdu.result_code
end

#modify(args) ⇒ Object

– modify TODO, need to support a time limit, in case the server fails to respond. TODO!!! We’re throwing an exception here on empty DN. Should return a proper error instead, probaby from farther up the chain. TODO!!! If the user specifies a bogus opcode, we’ll throw a confusing error here (“to_ber_enumerated is not defined on nil”).



962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
# File 'lib/net/ldap.rb', line 962

def modify args
  modify_dn = args[:dn] or raise "Unable to modify empty DN"
  modify_ops = []
  a = args[:operations] and a.each {|op, attr, values|
    # TODO, fix the following line, which gives a bogus error
    # if the opcode is invalid.
    op_1 = {:add => 0, :delete => 1, :replace => 2} [op.to_sym].to_ber_enumerated
    modify_ops << [op_1, [attr.to_s.to_ber, values.to_a.map {|v| v.to_ber}.to_ber_set].to_ber_sequence].to_ber_sequence
  }

  request = [modify_dn.to_ber, modify_ops.to_ber_sequence].to_ber_appsequence(6)
  pkt = [next_msgid.to_ber, request].to_ber_sequence
  @conn.write pkt

  (be = @conn.read_ber(AsnSyntax)) && (pdu = LdapPdu.new( be )) && (pdu.app_tag == 7) or raise LdapError.new( "response missing or invalid" )
  pdu.result_code
end

#next_msgidObject

– next_msgid



829
830
831
832
# File 'lib/net/ldap.rb', line 829

def next_msgid
  @msgid ||= 0
  @msgid += 1
end

#rename(args) ⇒ Object

– rename TODO, need to support a time limit, in case the server fails to respond.



1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
# File 'lib/net/ldap.rb', line 1005

def rename args
  old_dn = args[:olddn] or raise "Unable to rename empty DN"
  new_rdn = args[:newrdn] or raise "Unable to rename to empty RDN"
  delete_attrs = args[:delete_attributes] ? true : false

  request = [old_dn.to_ber, new_rdn.to_ber, delete_attrs.to_ber].to_ber_appsequence(12)
  pkt = [next_msgid.to_ber, request].to_ber_sequence
  @conn.write pkt

  (be = @conn.read_ber(AsnSyntax)) && (pdu = LdapPdu.new( be )) && (pdu.app_tag == 13) or raise LdapError.new( "response missing or invalid" )
  pdu.result_code
end

#search(args = {}) ⇒ Object

– search Alternate implementation, this yields each search entry to the caller as it are received. TODO, certain search parameters are hardcoded. TODO, if we mis-parse the server results or the results are wrong, we can block forever. That’s because we keep reading results until we get a type-5 packet, which might never come. We need to support the time-limit in the protocol. – WARNING: this code substantially recapitulates the searchx method.

Raises:



867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
# File 'lib/net/ldap.rb', line 867

def search args = {}
  search_filter = (args && args[:filter]) || Filter.eq( "objectclass", "*" )
  search_base = (args && args[:base]) || "dc=example,dc=com"
  search_attributes = ((args && args[:attributes]) || []).map {|attr| attr.to_s.to_ber}

  attributes_only = (args and args[:attributes_only] == true)
  scope = args[:scope] || Net::LDAP::SearchScope_WholeSubtree
  raise LdapError.new( "invalid search scope" ) unless SearchScopes.include?(scope)

  request = [
    search_base.to_ber,
    scope.to_ber_enumerated,
    0.to_ber_enumerated,
    0.to_ber,
    0.to_ber,
    attributes_only.to_ber,
    search_filter.to_ber,
    search_attributes.to_ber_sequence
  ].to_ber_appsequence(3)
  pkt = [next_msgid.to_ber, request].to_ber_sequence
  @conn.write pkt

  result_code = 0

  while (be = @conn.read_ber(AsnSyntax)) && (pdu = LdapPdu.new( be ))
    case pdu.app_tag
    when 4 # search-data
      yield( pdu.search_entry ) if block_given?
    when 5 # search-result
      result_code = pdu.result_code
      break
    else
      raise LdapError.new( "invalid response-type in search: #{pdu.app_tag}" )
    end
  end

  result_code
end

#searchx(args) ⇒ Object

– searchx Original implementation, this doesn’t return until all data have been received from the server. TODO, certain search parameters are hardcoded. TODO, if we mis-parse the server results or the results are wrong, we can block forever. That’s because we keep reading results until we get a type-5 packet, which might never come. We need to support the time-limit in the protocol. – WARNING: this code substantially recapitulates the search method.



918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
# File 'lib/net/ldap.rb', line 918

def searchx args
  search_filter = (args && args[:filter]) || Filter.eq( "objectclass", "*" )
  search_base = (args && args[:base]) || "dc=example,dc=com"
  search_attributes = ((args && args[:attributes]) || []).map {|attr| attr.to_s.to_ber}
  request = [
    search_base.to_ber,
    2.to_ber_enumerated,
    0.to_ber_enumerated,
    0.to_ber,
    0.to_ber,
    false.to_ber,
    search_filter.to_ber,
    search_attributes.to_ber_sequence
  ].to_ber_appsequence(3)
  pkt = [next_msgid.to_ber, request].to_ber_sequence
  @conn.write pkt

  search_results = {}
  result_code = 0

  while (be = @conn.read_ber(AsnSyntax)) && (pdu = LdapPdu.new( be ))
    case pdu.app_tag
    when 4 # search-data
      search_results [pdu.search_dn] = pdu.search_attributes
    when 5 # search-result
      result_code = pdu.result_code
      block_given? and yield( search_results )
      break
    else
      raise LdapError.new( "invalid response-type in search: #{pdu.app_tag}" )
    end
  end

  result_code
end