[前][次][番号順一覧][スレッド一覧]

ruby-changes:2880

From: ko1@a...
Date: 21 Dec 2007 01:21:38 +0900
Subject: [ruby-changes:2880] gotoyuzo - Ruby:r14371 (trunk): * lib/net/http.rb (Net::HTTP#connect): use

gotoyuzo	2007-12-21 01:21:22 +0900 (Fri, 21 Dec 2007)

  New Revision: 14371

  Added files:
    trunk/test/net/http/test_https.rb
  Modified files:
    trunk/ChangeLog
    trunk/lib/net/http.rb
    trunk/lib/net/https.rb
    trunk/test/net/http/utils.rb

  Log:
    * lib/net/http.rb (Net::HTTP#connect): use
      OpenSSL::SSL::SSLContext.build instead of SSLContext.new (default
      verify mode is now OpenSSL::SSL::VERIFY_PEER).
    
    * lib/net/https.rb: SSL parameters are defined by attr_accessor.
    
    * test/net/http/test_https.rb: add test for HTTPS features.


  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/test/net/http/utils.rb?r1=14371&r2=14370
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/net/https.rb?r1=14371&r2=14370
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/ChangeLog?r1=14371&r2=14370
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/test/net/http/test_https.rb?revision=14371&view=markup
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/net/http.rb?r1=14371&r2=14370

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 14370)
+++ ChangeLog	(revision 14371)
@@ -1,3 +1,13 @@
+Fri Dec 21 01:20:56 2007  GOTOU Yuuzou  <gotoyuzo@n...>
+
+	* lib/net/http.rb (Net::HTTP#connect): use
+	  OpenSSL::SSL::SSLContext.build instead of SSLContext.new (default
+	  verify mode is now OpenSSL::SSL::VERIFY_PEER).
+
+	* lib/net/https.rb: SSL parameters are defined by attr_accessor.
+
+	* test/net/http/test_https.rb: add test for HTTPS features.
+
 Fri Dec 21 01:11:37 2007  GOTOU Yuuzou  <gotoyuzo@n...>
 
 	* io.c (select_internal): should return original value.
Index: lib/net/http.rb
===================================================================
--- lib/net/http.rb	(revision 14370)
+++ lib/net/http.rb	(revision 14371)
@@ -575,10 +575,13 @@
       s = timeout(@open_timeout) { TCPSocket.open(conn_address(), conn_port()) }
       D "opened"
       if use_ssl?
-        unless @ssl_context.verify_mode
-          warn "warning: peer certificate won't be verified in this SSL session"
-          @ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
+        ssl_parameters = Hash.new
+        SSL_ATTRIBUTES.each do |name|
+          if value = instance_variable_get("@#{name}")
+            ssl_parameters[name] = value
+          end
         end
+        @ssl_context = OpenSSL::SSL::SSLContext.build(ssl_parameters)
         s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
         s.sync_close = true
       end
Index: lib/net/https.rb
===================================================================
--- lib/net/https.rb	(revision 14370)
+++ lib/net/https.rb	(revision 14371)
@@ -102,70 +102,35 @@
 require 'openssl'
 
 module Net
-
   class HTTP
     remove_method :use_ssl?
     def use_ssl?
       @use_ssl
     end
 
-    alias use_ssl use_ssl?   # for backward compatibility
-
     # Turn on/off SSL.
     # This flag must be set before starting session.
     # If you change use_ssl value after session started,
     # a Net::HTTP object raises IOError.
     def use_ssl=(flag)
       flag = (flag ? true : false)
-      raise IOError, "use_ssl value changed, but session already started" \
-          if started? and @use_ssl != flag
-      if flag and not @ssl_context
-        @ssl_context = OpenSSL::SSL::SSLContext.new
+      if started? and @use_ssl != flag
+        raise IOError, "use_ssl value changed, but session already started"
       end
       @use_ssl = flag
     end
 
-    def self.ssl_context_accessor(name)
-      module_eval(<<-End, __FILE__, __LINE__ + 1)
-        def #{name}
-          return nil unless @ssl_context
-          @ssl_context.#{name}
-        end
+    SSL_ATTRIBUTES = %w(
+      ssl_version key cert ca_file ca_path cert_store ciphers
+      verify_mode verify_callback verify_depth ssl_timeout
+    )
+    attr_accessor *SSL_ATTRIBUTES
 
-        def #{name}=(val)
-          @ssl_context ||= OpenSSL::SSL::SSLContext.new
-          @ssl_context.#{name} = val
-        end
-      End
-    end
-
-    ssl_context_accessor :key
-    ssl_context_accessor :cert
-    ssl_context_accessor :ca_file
-    ssl_context_accessor :ca_path
-    ssl_context_accessor :verify_mode
-    ssl_context_accessor :verify_callback
-    ssl_context_accessor :verify_depth
-    ssl_context_accessor :cert_store
-
-    def ssl_timeout
-      return nil unless @ssl_context
-      @ssl_context.timeout
-    end
-
-    def ssl_timeout=(sec)
-      raise ArgumentError, 'Net::HTTP#ssl_timeout= called but use_ssl=false' \
-          unless use_ssl?
-      @ssl_context ||= OpenSSL::SSL::SSLContext.new
-      @ssl_context.timeout = sec
-    end
-
-    alias timeout= ssl_timeout=   # for backward compatibility
-
     def peer_cert
-      return nil if not use_ssl? or not @socket
+      if not use_ssl? or not @socket
+        return nil
+      end
       @socket.io.peer_cert
     end
   end
-
 end
Index: test/net/http/utils.rb
===================================================================
--- test/net/http/utils.rb	(revision 14370)
+++ test/net/http/utils.rb	(revision 14371)
@@ -1,4 +1,9 @@
 require 'webrick'
+begin
+  require "webrick/https"
+rescue LoadError
+  # SSL features cannot be tested
+end
 require 'webrick/httpservlet/abstract'
 
 module TestNetHTTPUtils
@@ -35,14 +40,22 @@
   end
 
   def spawn_server
-    @server = WEBrick::HTTPServer.new(
+    server_config = {
       :BindAddress => config('host'),
       :Port => config('port'),
       :Logger => WEBrick::Log.new(NullWriter.new),
       :AccessLog => [],
       :ShutdownSocketWithoutClose => true,
-      :ServerType => Thread
-    )
+      :ServerType => Thread,
+    }
+    if defined?(OpenSSL) and config('ssl_enable')
+      server_config.update({
+        :SSLEnable      => true,
+        :SSLCertificate => config('ssl_certificate'),
+        :SSLPrivateKey  => config('ssl_private_key'),
+      })
+    end
+    @server = WEBrick::HTTPServer.new(server_config)
     @server.mount('/', Servlet)
     @server.start
     n_try_max = 5
Index: test/net/http/test_https.rb
===================================================================
--- test/net/http/test_https.rb	(revision 0)
+++ test/net/http/test_https.rb	(revision 14371)
@@ -0,0 +1,97 @@
+require "test/unit"
+begin
+  require 'net/https'
+rescue LoadError
+  # should skip this test
+end
+require 'stringio'
+require File.expand_path("utils", File.dirname(__FILE__))
+require File.expand_path("../../openssl/utils", File.dirname(__FILE__))
+
+class TestNetHTTPS < Test::Unit::TestCase
+  include TestNetHTTPUtils
+
+  subject = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost")
+  exts = [
+    ["keyUsage", "keyEncipherment,digitalSignature", true],
+  ]
+  key = OpenSSL::TestUtils::TEST_KEY_RSA1024
+  cert = OpenSSL::TestUtils.issue_cert(
+    subject, key, 1, Time.now, Time.now + 3600, exts,
+    nil, nil, OpenSSL::Digest::SHA1.new
+  )
+
+  CONFIG = {
+    'host' => '127.0.0.1',
+    'port' => 10081,
+    'proxy_host' => nil,
+    'proxy_port' => nil,
+    'ssl_enable' => true,
+    'ssl_certificate' => cert,
+    'ssl_private_key' => key,
+  }
+
+  def test_get
+    http = Net::HTTP.new("localhost", config("port"))
+    http.use_ssl = true
+    http.verify_callback = Proc.new do |preverify_ok, store_ctx|
+      store_ctx.current_cert.to_der == config('ssl_certificate').to_der
+    end
+    http.request_get("/") {|res|
+      assert_equal($test_net_http_data, res.body)
+    }
+  end
+
+  def test_post
+    http = Net::HTTP.new("localhost", config("port"))
+    http.use_ssl = true
+    http.verify_callback = Proc.new do |preverify_ok, store_ctx|
+      store_ctx.current_cert.to_der == config('ssl_certificate').to_der
+    end
+    data = config('ssl_private_key').to_der
+    http.request_post("/", data) {|res|
+      assert_equal(data, res.body)
+    }
+  end
+
+  if ENV["RUBY_OPENSSL_TEST_ALL"]
+    def test_verify
+      http = Net::HTTP.new("ssl.netlab.jp", 443)
+      http.use_ssl = true
+      assert(
+        http.request_head("/"){|res| },
+        "The system may not have default CA certificate store."
+      )
+    end
+  end
+
+  def test_verify_none
+    http = Net::HTTP.new("localhost", config("port"))
+    http.use_ssl = true
+    http.verify_mode = OpenSSL::SSL::VERIFY_NONE
+    http.request_get("/") {|res|
+      assert_equal($test_net_http_data, res.body)
+    }
+  end
+
+  def test_certificate_verify_failure
+    http = Net::HTTP.new("localhost", config("port"))
+    http.use_ssl = true
+    ex = assert_raise(OpenSSL::SSL::SSLError){
+      http.request_get("/") {|res| }
+    }
+    assert_match(/certificate verify failed/, ex.message)
+  end
+
+  def test_identity_verify_failure
+    http = Net::HTTP.new("127.0.0.1", config("port"))
+    http.use_ssl = true
+    http.verify_callback = Proc.new do |preverify_ok, store_ctx|
+      store_ctx.current_cert.to_der == config('ssl_certificate').to_der
+    end
+    ex = assert_raise(OpenSSL::SSL::SSLError){
+      http.request_get("/") {|res| }
+    }
+    assert_match(/hostname was not match/, ex.message)
+  end
+end if defined?(OpenSSL)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml

[前][次][番号順一覧][スレッド一覧]