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>
|
Fri Dec 21 01:11:37 2007 GOTOU Yuuzou <gotoyuzo@notwork.org>
|
||||||
|
|
||||||
* io.c (select_internal): should return original value.
|
* 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()) }
|
s = timeout(@open_timeout) { TCPSocket.open(conn_address(), conn_port()) }
|
||||||
D "opened"
|
D "opened"
|
||||||
if use_ssl?
|
if use_ssl?
|
||||||
unless @ssl_context.verify_mode
|
ssl_parameters = Hash.new
|
||||||
warn "warning: peer certificate won't be verified in this SSL session"
|
SSL_ATTRIBUTES.each do |name|
|
||||||
@ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
if value = instance_variable_get("@#{name}")
|
||||||
|
ssl_parameters[name] = value
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ssl_context = OpenSSL::SSL::SSLContext.build(ssl_parameters)
|
||||||
s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
|
s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
|
||||||
s.sync_close = true
|
s.sync_close = true
|
||||||
end
|
end
|
||||||
|
|
|
@ -102,70 +102,35 @@ require 'net/http'
|
||||||
require 'openssl'
|
require 'openssl'
|
||||||
|
|
||||||
module Net
|
module Net
|
||||||
|
|
||||||
class HTTP
|
class HTTP
|
||||||
remove_method :use_ssl?
|
remove_method :use_ssl?
|
||||||
def use_ssl?
|
def use_ssl?
|
||||||
@use_ssl
|
@use_ssl
|
||||||
end
|
end
|
||||||
|
|
||||||
alias use_ssl use_ssl? # for backward compatibility
|
|
||||||
|
|
||||||
# Turn on/off SSL.
|
# Turn on/off SSL.
|
||||||
# This flag must be set before starting session.
|
# This flag must be set before starting session.
|
||||||
# If you change use_ssl value after session started,
|
# If you change use_ssl value after session started,
|
||||||
# a Net::HTTP object raises IOError.
|
# a Net::HTTP object raises IOError.
|
||||||
def use_ssl=(flag)
|
def use_ssl=(flag)
|
||||||
flag = (flag ? true : false)
|
flag = (flag ? true : false)
|
||||||
raise IOError, "use_ssl value changed, but session already started" \
|
if started? and @use_ssl != flag
|
||||||
if started? and @use_ssl != flag
|
raise IOError, "use_ssl value changed, but session already started"
|
||||||
if flag and not @ssl_context
|
|
||||||
@ssl_context = OpenSSL::SSL::SSLContext.new
|
|
||||||
end
|
end
|
||||||
@use_ssl = flag
|
@use_ssl = flag
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.ssl_context_accessor(name)
|
SSL_ATTRIBUTES = %w(
|
||||||
module_eval(<<-End, __FILE__, __LINE__ + 1)
|
ssl_version key cert ca_file ca_path cert_store ciphers
|
||||||
def #{name}
|
verify_mode verify_callback verify_depth ssl_timeout
|
||||||
return nil unless @ssl_context
|
)
|
||||||
@ssl_context.#{name}
|
attr_accessor *SSL_ATTRIBUTES
|
||||||
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
|
|
||||||
|
|
||||||
def peer_cert
|
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
|
@socket.io.peer_cert
|
||||||
end
|
end
|
||||||
end
|
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'
|
require 'webrick'
|
||||||
|
begin
|
||||||
|
require "webrick/https"
|
||||||
|
rescue LoadError
|
||||||
|
# SSL features cannot be tested
|
||||||
|
end
|
||||||
require 'webrick/httpservlet/abstract'
|
require 'webrick/httpservlet/abstract'
|
||||||
|
|
||||||
module TestNetHTTPUtils
|
module TestNetHTTPUtils
|
||||||
|
@ -35,14 +40,22 @@ module TestNetHTTPUtils
|
||||||
end
|
end
|
||||||
|
|
||||||
def spawn_server
|
def spawn_server
|
||||||
@server = WEBrick::HTTPServer.new(
|
server_config = {
|
||||||
:BindAddress => config('host'),
|
:BindAddress => config('host'),
|
||||||
:Port => config('port'),
|
:Port => config('port'),
|
||||||
:Logger => WEBrick::Log.new(NullWriter.new),
|
:Logger => WEBrick::Log.new(NullWriter.new),
|
||||||
:AccessLog => [],
|
:AccessLog => [],
|
||||||
:ShutdownSocketWithoutClose => true,
|
: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.mount('/', Servlet)
|
||||||
@server.start
|
@server.start
|
||||||
n_try_max = 5
|
n_try_max = 5
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue