mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	* 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@14371 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
		
							parent
							
								
									d86caf3188
								
							
						
					
					
						commit
						c6920177f3
					
				
					 5 changed files with 139 additions and 51 deletions
				
			
		
							
								
								
									
										10
									
								
								ChangeLog
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								ChangeLog
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,3 +1,13 @@
 | 
			
		|||
Fri Dec 21 01:20:56 2007  GOTOU Yuuzou  <gotoyuzo@notwork.org>
 | 
			
		||||
 | 
			
		||||
	* 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@notwork.org>
 | 
			
		||||
 | 
			
		||||
	* io.c (select_internal): should return original value.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -575,10 +575,13 @@ module Net   #:nodoc:
 | 
			
		|||
      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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -102,70 +102,35 @@ require 'net/http'
 | 
			
		|||
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
 | 
			
		||||
 | 
			
		||||
        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
 | 
			
		||||
    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 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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										97
									
								
								test/net/http/test_https.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								test/net/http/test_https.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			@ -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 @@ module TestNetHTTPUtils
 | 
			
		|||
  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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue