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

ruby-changes:47236

From: normal <ko1@a...>
Date: Tue, 18 Jul 2017 10:59:34 +0900 (JST)
Subject: [ruby-changes:47236] normal:r59351 (trunk): webrick: fix SNI support

normal	2017-07-18 10:59:28 +0900 (Tue, 18 Jul 2017)

  New Revision: 59351

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=59351

  Log:
    webrick: fix SNI support
    
    * lib/webrick/https.rb: check ssl context of virtual host.
    * lib/webrick/ssl.rb: ensure to return ssl context.
    * test/webrick/test_https.rb: test returned cert is correct.
      [Feature #13729][ruby-dev:50173]
    
    Author: Tietew <tietew@g...>

  Modified files:
    trunk/lib/webrick/https.rb
    trunk/lib/webrick/ssl.rb
    trunk/test/webrick/test_https.rb
Index: lib/webrick/ssl.rb
===================================================================
--- lib/webrick/ssl.rb	(revision 59350)
+++ lib/webrick/ssl.rb	(revision 59351)
@@ -147,7 +147,13 @@ module WEBrick https://github.com/ruby/ruby/blob/trunk/lib/webrick/ssl.rb#L147
     # SSL context for the server when run in SSL mode
 
     def ssl_context # :nodoc:
-      @ssl_context ||= nil
+      @ssl_context ||= begin
+        if @config[:SSLEnable]
+          ssl_context = setup_ssl_context(@config)
+          @logger.info("\n" + @config[:SSLCertificate].to_text)
+          ssl_context
+        end
+      end
     end
 
     undef listen
@@ -158,10 +164,6 @@ module WEBrick https://github.com/ruby/ruby/blob/trunk/lib/webrick/ssl.rb#L164
     def listen(address, port) # :nodoc:
       listeners = Utils::create_listeners(address, port)
       if @config[:SSLEnable]
-        unless ssl_context
-          @ssl_context = setup_ssl_context(@config)
-          @logger.info("\n" + @config[:SSLCertificate].to_text)
-        end
         listeners.collect!{|svr|
           ssvr = ::OpenSSL::SSL::SSLServer.new(svr, ssl_context)
           ssvr.start_immediately = @config[:SSLStartImmediately]
Index: lib/webrick/https.rb
===================================================================
--- lib/webrick/https.rb	(revision 59350)
+++ lib/webrick/https.rb	(revision 59351)
@@ -131,5 +131,22 @@ module WEBrick https://github.com/ruby/ruby/blob/trunk/lib/webrick/https.rb#L131
       server = lookup_server(req)
       server ? server.ssl_context : nil
     end
+
+    # :stopdoc:
+
+    ##
+    # Check whether +server+ is also SSL server.
+    # Also +server+'s SSL context will be created.
+
+    alias orig_virtual_host virtual_host
+
+    def virtual_host(server)
+      if @config[:SSLEnable] && !server.ssl_context
+        raise ArgumentError, "virtual host must set SSLEnable to true"
+      end
+      orig_virtual_host(server)
+    end
+
+    # :startdoc:
   end
 end
Index: test/webrick/test_https.rb
===================================================================
--- test/webrick/test_https.rb	(revision 59350)
+++ test/webrick/test_https.rb	(revision 59351)
@@ -28,57 +28,85 @@ class TestWEBrickHTTPS < Test::Unit::Tes https://github.com/ruby/ruby/blob/trunk/test/webrick/test_https.rb#L28
     super
   end
 
-  def https_get(addr, port, hostname, path)
+  def https_get(addr, port, hostname, path, verifyname = nil)
+    subject = nil
     http = HTTPSNITest.new(addr, port)
     http.use_ssl = true
     http.verify_mode = OpenSSL::SSL::VERIFY_NONE
+    http.verify_callback = proc { |x, store| subject = store.chain[0].subject.to_s; x }
     http.sni_hostname = hostname
     req = Net::HTTP::Get.new(path)
     req["Host"] = "#{hostname}:#{port}"
-    http.request(req).body
+    response = http.start { http.request(req).body }
+    assert_equal("/CN=#{verifyname || hostname}", subject)
+    response
   end
 
   def test_sni
     config = {
       :ServerName => "localhost",
       :SSLEnable => true,
-      :SSLCertName => "/CN=locahost",
+      :SSLCertName => "/CN=localhost",
     }
     TestWEBrick.start_httpserver(config){|server, addr, port, log|
       server.mount_proc("/") {|req, res| res.body = "master" }
 
-      vhost_config1 = {
-        :ServerName => "vhost1",
-        :Port => port,
-        :DoNotListen => true,
-        :Logger => NoLog,
-        :AccessLog => [],
-        :SSLEnable => true,
-        :SSLCertName => "/CN=vhost1",
-      }
-      vhost1 = WEBrick::HTTPServer.new(vhost_config1)
-      vhost1.mount_proc("/") {|req, res| res.body = "vhost1" }
-      server.virtual_host(vhost1)
-
-      vhost_config2 = {
-        :ServerName => "vhost2",
-        :ServerAlias => ["vhost2alias"],
-        :Port => port,
-        :DoNotListen => true,
-        :Logger => NoLog,
-        :AccessLog => [],
-        :SSLEnable => true,
-        :SSLCertName => "/CN=vhost2",
-      }
-      vhost2 = WEBrick::HTTPServer.new(vhost_config2)
-      vhost2.mount_proc("/") {|req, res| res.body = "vhost2" }
-      server.virtual_host(vhost2)
+      # catch stderr in create_self_signed_cert
+      stderr_buffer = StringIO.new
+      old_stderr, $stderr = $stderr, stderr_buffer
 
+      begin
+        vhost_config1 = {
+          :ServerName => "vhost1",
+          :Port => port,
+          :DoNotListen => true,
+          :Logger => NoLog,
+          :AccessLog => [],
+          :SSLEnable => true,
+          :SSLCertName => "/CN=vhost1",
+        }
+        vhost1 = WEBrick::HTTPServer.new(vhost_config1)
+        vhost1.mount_proc("/") {|req, res| res.body = "vhost1" }
+        server.virtual_host(vhost1)
+
+        vhost_config2 = {
+          :ServerName => "vhost2",
+          :ServerAlias => ["vhost2alias"],
+          :Port => port,
+          :DoNotListen => true,
+          :Logger => NoLog,
+          :AccessLog => [],
+          :SSLEnable => true,
+          :SSLCertName => "/CN=vhost2",
+        }
+        vhost2 = WEBrick::HTTPServer.new(vhost_config2)
+        vhost2.mount_proc("/") {|req, res| res.body = "vhost2" }
+        server.virtual_host(vhost2)
+      ensure
+        # restore stderr
+        $stderr = old_stderr
+      end
+
+      assert_match(/\A([.+*]+\n)+\z/, stderr_buffer.string)
       assert_equal("master", https_get(addr, port, "localhost", "/localhost"))
-      assert_equal("master", https_get(addr, port, "unknown", "/unknown"))
+      assert_equal("master", https_get(addr, port, "unknown", "/unknown", "localhost"))
       assert_equal("vhost1", https_get(addr, port, "vhost1", "/vhost1"))
       assert_equal("vhost2", https_get(addr, port, "vhost2", "/vhost2"))
-      assert_equal("vhost2", https_get(addr, port, "vhost2alias", "/vhost2alias"))
+      assert_equal("vhost2", https_get(addr, port, "vhost2alias", "/vhost2alias", "vhost2"))
+    }
+  end
+
+  def test_check_ssl_virtual
+    config = {
+      :ServerName => "localhost",
+      :SSLEnable => true,
+      :SSLCertName => "/CN=localhost",
+    }
+    TestWEBrick.start_httpserver(config){|server, addr, port, log|
+      assert_raise ArgumentError do
+        vhost = WEBrick::HTTPServer.new({:DoNotListen => true, :Logger => NoLog})
+        server.virtual_host(vhost)
+      end
     }
   end
 end

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

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