ruby-net-ldap 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/ChangeLog +4 -0
  2. data/lib/net/ber.rb +17 -1
  3. data/lib/net/ldap.rb +104 -10
  4. metadata +2 -2
data/ChangeLog CHANGED
@@ -1,5 +1,9 @@
1
1
  = Net::LDAP Changelog
2
2
 
3
+ == Net::LDAP 0.0.3: July 26, 2006
4
+ * Added simple TLS encryption.
5
+ Thanks to Garett Shulman for suggestions and for helping test.
6
+
3
7
  == Net::LDAP 0.0.2: July 12, 2006
4
8
  * Fixed malformation in distro tarball and gem.
5
9
  * Improved documentation.
@@ -1,4 +1,4 @@
1
- # $Id: ber.rb 93 2006-05-01 06:40:48Z blackhedd $
1
+ # $Id: ber.rb 142 2006-07-26 12:20:33Z blackhedd $
2
2
  #
3
3
  # NET::BER
4
4
  # Mixes ASN.1/BER convenience methods into several standard classes.
@@ -139,6 +139,22 @@ class StringIO
139
139
  include Net::BER::BERParser
140
140
  end
141
141
 
142
+ begin
143
+ require 'openssl'
144
+ class OpenSSL::SSL::SSLSocket
145
+ include Net::BER::BERParser
146
+ end
147
+ rescue LoadError
148
+ # Ignore LoadError.
149
+ # DON'T ignore NameError, which means the SSLSocket class
150
+ # is somehow unavailable on this implementation of Ruby's openssl.
151
+ # This may be WRONG, however, because we don't yet know how Ruby's
152
+ # openssl behaves on machines with no OpenSSL library. I suppose
153
+ # it's possible they do not fail to require 'openssl' but do not
154
+ # create the classes. So this code is provisional.
155
+ # Also, you might think that OpenSSL::SSL::SSLSocket inherits from
156
+ # IO so we'd pick it up above. But you'd be wrong.
157
+ end
142
158
 
143
159
  class String
144
160
  def read_ber syntax=nil
@@ -1,4 +1,4 @@
1
- # $Id: ldap.rb 141 2006-07-12 10:37:37Z blackhedd $
1
+ # $Id: ldap.rb 144 2006-07-26 21:35:38Z blackhedd $
2
2
  #
3
3
  # Net::LDAP for Ruby
4
4
  #
@@ -18,6 +18,13 @@
18
18
 
19
19
  require 'socket'
20
20
  require 'ostruct'
21
+
22
+ begin
23
+ require 'openssl'
24
+ $net_ldap_openssl_available = true
25
+ rescue LoadError
26
+ end
27
+
21
28
  require 'net/ber'
22
29
  require 'net/ldap/pdu'
23
30
  require 'net/ldap/filter'
@@ -256,7 +263,7 @@ module Net
256
263
 
257
264
  class LdapError < Exception; end
258
265
 
259
- VERSION = "0.0.2"
266
+ VERSION = "0.0.3"
260
267
 
261
268
 
262
269
  SearchScope_BaseObject = 0
@@ -348,7 +355,7 @@ module Net
348
355
 
349
356
 
350
357
  # Instantiate an object of type Net::LDAP to perform directory operations.
351
- # This constructor takes a Hash containing arguments. The following arguments
358
+ # This constructor takes a Hash containing arguments, all of which are either optional or may be specified later with other methods as described below. The following arguments
352
359
  # are supported:
353
360
  # * :host => the LDAP server's IP-address (default 127.0.0.1)
354
361
  # * :port => the LDAP server's TCP port (default 389)
@@ -356,6 +363,8 @@ module Net
356
363
  # {:method => :anonymous} and
357
364
  # {:method => :simple, :username => your_user_name, :password => your_password }
358
365
  # The password parameter may be a Proc that returns a String.
366
+ # * :base => a default treebase parameter for searches performed against the LDAP server. If you don't give this value, then each call to #search must specify a treebase parameter. If you do give this value, then it will be used in subsequent calls to #search that do not specify a treebase. If you give a treebase value in any particular call to #search, that value will override any treebase value you give here.
367
+ # * :encryption => specifies the encryption to be used in communicating with the LDAP server. The value is either a Hash containing additional parameters, or the Symbol :simple_tls, which is equivalent to specifying the Hash {:method => :simple_tls}. There is a fairly large range of potential values that may be given for this parameter. See #encryption for details.
359
368
  #
360
369
  # Instantiating a Net::LDAP object does <i>not</i> result in network traffic to
361
370
  # the LDAP server. It simply stores the connection and binding parameters in the
@@ -367,6 +376,7 @@ module Net
367
376
  @verbose = false # Make this configurable with a switch on the class.
368
377
  @auth = args[:auth] || DefaultAuth
369
378
  @base = args[:base] || DefaultTreebase
379
+ encryption args[:encryption] # may be nil
370
380
 
371
381
  if pr = @auth[:password] and pr.respond_to?(:call)
372
382
  @auth[:password] = pr.call
@@ -417,6 +427,51 @@ module Net
417
427
 
418
428
  alias_method :auth, :authenticate
419
429
 
430
+ # Convenience method to specify encryption characteristics for connections
431
+ # to LDAP servers. Called implicitly by #new and #open, but may also be called
432
+ # by user code if desired.
433
+ # The single argument is generally a Hash (but see below for convenience alternatives).
434
+ # This implementation is currently a stub, supporting only a few encryption
435
+ # alternatives. As additional capabilities are added, more configuration values
436
+ # will be added here.
437
+ #
438
+ # Currently, the only supported argument is {:method => :simple_tls}.
439
+ # (Equivalently, you may pass the symbol :simple_tls all by itself, without
440
+ # enclosing it in a Hash.)
441
+ #
442
+ # The :simple_tls encryption method encrypts <i>all</i> communications with the LDAP
443
+ # server.
444
+ # It completely establishes SSL/TLS encryption with the LDAP server
445
+ # before any LDAP-protocol data is exchanged.
446
+ # There is no plaintext negotiation and no special encryption-request controls
447
+ # are sent to the server.
448
+ # <i>The :simple_tls option is the simplest, easiest way to encrypt communications
449
+ # between Net::LDAP and LDAP servers.</i>
450
+ # It's intended for cases where you have an implicit level of trust in the authenticity
451
+ # of the LDAP server. No validation of the LDAP server's SSL certificate is
452
+ # performed. This means that :simple_tls will not produce errors if the LDAP
453
+ # server's encryption certificate is not signed by a well-known Certification
454
+ # Authority.
455
+ # If you get communications or protocol errors when using this option, check
456
+ # with your LDAP server administrator. Pay particular attention to the TCP port
457
+ # you are connecting to. It's impossible for an LDAP server to support plaintext
458
+ # LDAP communications and <i>simple TLS</i> connections on the same port.
459
+ # The standard TCP port for unencrypted LDAP connections is 389, but the standard
460
+ # port for simple-TLS encrypted connections is 636. Be sure you are using the
461
+ # correct port.
462
+ #
463
+ # <i>[Note: a future version of Net::LDAP will support the STARTTLS LDAP control,
464
+ # which will enable encrypted communications on the same TCP port used for
465
+ # unencrypted connections.]</i>
466
+ #
467
+ def encryption args
468
+ if args == :simple_tls
469
+ args = {:method => :simple_tls}
470
+ end
471
+ @encryption = args
472
+ end
473
+
474
+
420
475
  # #open takes the same parameters as #new. #open makes a network connection to the
421
476
  # LDAP server and then passes a newly-created Net::LDAP object to the caller-supplied block.
422
477
  # Within the block, you can call any of the instance methods of Net::LDAP to
@@ -484,7 +539,7 @@ module Net
484
539
  # if the bind was unsuccessful.
485
540
  def open
486
541
  raise LdapError.new( "open already in progress" ) if @open_connection
487
- @open_connection = Connection.new( :host => @host, :port => @port )
542
+ @open_connection = Connection.new( :host => @host, :port => @port, :encryption => @encryption )
488
543
  @open_connection.bind @auth
489
544
  yield self
490
545
  @open_connection.close
@@ -579,7 +634,7 @@ module Net
579
634
  }
580
635
  else
581
636
  @result = 0
582
- conn = Connection.new( :host => @host, :port => @port )
637
+ conn = Connection.new( :host => @host, :port => @port, :encryption => @encryption )
583
638
  if (@result = conn.bind( args[:auth] || @auth )) == 0
584
639
  @result = conn.search( args ) {|entry|
585
640
  result_set << entry if result_set
@@ -641,7 +696,7 @@ module Net
641
696
  if @open_connection
642
697
  @result = @open_connection.bind @auth
643
698
  else
644
- conn = Connection.new( :host => @host, :port => @port )
699
+ conn = Connection.new( :host => @host, :port => @port , :encryption => @encryption)
645
700
  @result = conn.bind @auth
646
701
  conn.close
647
702
  end
@@ -692,7 +747,7 @@ module Net
692
747
  @result = @open_connection.add( args )
693
748
  else
694
749
  @result = 0
695
- conn = Connection.new( :host => @host, :port => @port )
750
+ conn = Connection.new( :host => @host, :port => @port, :encryption => @encryption)
696
751
  if (@result = conn.bind( args[:auth] || @auth )) == 0
697
752
  @result = conn.add( args )
698
753
  end
@@ -776,7 +831,7 @@ module Net
776
831
  @result = @open_connection.modify( args )
777
832
  else
778
833
  @result = 0
779
- conn = Connection.new( :host => @host, :port => @port )
834
+ conn = Connection.new( :host => @host, :port => @port, :encryption => @encryption )
780
835
  if (@result = conn.bind( args[:auth] || @auth )) == 0
781
836
  @result = conn.modify( args )
782
837
  end
@@ -848,7 +903,7 @@ module Net
848
903
  @result = @open_connection.rename( args )
849
904
  else
850
905
  @result = 0
851
- conn = Connection.new( :host => @host, :port => @port )
906
+ conn = Connection.new( :host => @host, :port => @port, :encryption => @encryption )
852
907
  if (@result = conn.bind( args[:auth] || @auth )) == 0
853
908
  @result = conn.rename( args )
854
909
  end
@@ -878,7 +933,7 @@ module Net
878
933
  @result = @open_connection.delete( args )
879
934
  else
880
935
  @result = 0
881
- conn = Connection.new( :host => @host, :port => @port )
936
+ conn = Connection.new( :host => @host, :port => @port, :encryption => @encryption )
882
937
  if (@result = conn.bind( args[:auth] || @auth )) == 0
883
938
  @result = conn.delete( args )
884
939
  end
@@ -908,10 +963,49 @@ module Net
908
963
  raise LdapError.new( "no connection to server" )
909
964
  end
910
965
 
966
+ if server[:encryption]
967
+ setup_encryption server[:encryption]
968
+ end
969
+
911
970
  yield self if block_given?
912
971
  end
913
972
 
914
973
 
974
+ #--
975
+ # Helper method called only from new, and only after we have a successfully-opened
976
+ # @conn instance variable, which is a TCP connection.
977
+ # Depending on the received arguments, we establish SSL, potentially replacing
978
+ # the value of @conn accordingly.
979
+ # Don't generate any errors here if no encryption is requested.
980
+ # DO raise LdapError objects if encryption is requested and we have trouble setting
981
+ # it up. That includes if OpenSSL is not set up on the machine. (Question:
982
+ # how does the Ruby OpenSSL wrapper react in that case?)
983
+ # DO NOT filter exceptions raised by the OpenSSL library. Let them pass back
984
+ # to the user. That should make it easier for us to debug the problem reports.
985
+ # Presumably (hopefully?) that will also produce recognizable errors if someone
986
+ # tries to use this on a machine without OpenSSL.
987
+ #
988
+ # The simple_tls method is intended as the simplest, stupidest, easiest solution
989
+ # for people who want nothing more than encrypted comms with the LDAP server.
990
+ # It doesn't do any server-cert validation and requires nothing in the way
991
+ # of key files and root-cert files, etc etc.
992
+ # OBSERVE: WE REPLACE the value of @conn, which is presumed to be a connected
993
+ # TCPsocket object.
994
+ #
995
+ def setup_encryption args
996
+ case args[:method]
997
+ when :simple_tls
998
+ raise LdapError.new("openssl unavailable") unless $net_ldap_openssl_available
999
+ ctx = OpenSSL::SSL::SSLContext.new
1000
+ @conn = OpenSSL::SSL::SSLSocket.new(@conn, ctx)
1001
+ @conn.connect
1002
+ @conn.sync_close = true
1003
+ # additional branches requiring server validation and peer certs, etc. go here.
1004
+ else
1005
+ raise LdapError.new( "unsupported encryption method #{args[:method]}" )
1006
+ end
1007
+ end
1008
+
915
1009
  #--
916
1010
  # close
917
1011
  # This is provided as a convenience method to make
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: ruby-net-ldap
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.0.2
7
- date: 2006-07-12 00:00:00 -04:00
6
+ version: 0.0.3
7
+ date: 2006-07-27 00:00:00 -04:00
8
8
  summary: A pure Ruby LDAP client library.
9
9
  require_paths:
10
10
  - lib