diff options
| -rw-r--r-- | test/rubygems/test_gem_remote_fetcher_local_server.rb | 180 | ||||
| -rw-r--r-- | test/rubygems/test_gem_remote_fetcher_local_ssl_server.rb | 373 |
2 files changed, 374 insertions, 179 deletions
diff --git a/test/rubygems/test_gem_remote_fetcher_local_server.rb b/test/rubygems/test_gem_remote_fetcher_local_server.rb index a6bc626ede..d315b520de 100644 --- a/test/rubygems/test_gem_remote_fetcher_local_server.rb +++ b/test/rubygems/test_gem_remote_fetcher_local_server.rb @@ -3,11 +3,6 @@ require_relative "helper" require "webrick" -require "webrick/https" if Gem::HAVE_OPENSSL - -unless Gem::HAVE_OPENSSL - warn "Skipping Gem::RemoteFetcher tests. openssl not found." -end require "rubygems/remote_fetcher" require "rubygems/package" @@ -72,20 +67,6 @@ gems: PROXY_DATA = SERVER_DATA.gsub(/0.4.11/, "0.4.2") - # Generated via: - # x = OpenSSL::PKey::DH.new(2048) # wait a while... - # x.to_s => pem - TEST_KEY_DH2048 = OpenSSL::PKey::DH.new <<-_END_OF_PEM_ ------BEGIN DH PARAMETERS----- -MIIBCAKCAQEA3Ze2EHSfYkZLUn557torAmjBgPsqzbodaRaGZtgK1gEU+9nNJaFV -G1JKhmGUiEDyIW7idsBpe4sX/Wqjnp48Lr8IeI/SlEzLdoGpf05iRYXC8Cm9o8aM -cfmVgoSEAo9YLBpzoji2jHkO7Q5IPt4zxbTdlmmGFLc/GO9q7LGHhC+rcMcNTGsM -49AnILNn49pq4Y72jSwdmvq4psHZwwFBbPwLdw6bLUDDCN90jfqvYt18muwUxDiN -NP0fuvVAIB158VnQ0liHSwcl6+9vE1mL0Jo/qEXQxl0+UdKDjaGfTsn6HIrwTnmJ -PeIQQkFng2VVot/WAQbv3ePqWq07g1BBcwIBAg== ------END DH PARAMETERS----- - _END_OF_PEM_ - def setup @proxies = %w[https_proxy http_proxy HTTP_PROXY http_proxy_user HTTP_PROXY_USER http_proxy_pass HTTP_PROXY_PASS no_proxy NO_PROXY] @old_proxies = @proxies.map {|k| ENV[k] } @@ -195,105 +176,6 @@ PeIQQkFng2VVot/WAQbv3ePqWq07g1BBcwIBAg== end end - def test_ssl_connection - ssl_server = start_ssl_server - temp_ca_cert = File.join(__dir__, "ca_cert.pem") - with_configured_fetcher(":ssl_ca_cert: #{temp_ca_cert}") do |fetcher| - fetcher.fetch_path("https://localhost:#{ssl_server.config[:Port]}/yaml") - end - end - - def test_ssl_client_cert_auth_connection - ssl_server = start_ssl_server( - { SSLVerifyClient: OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT } - ) - - temp_ca_cert = File.join(__dir__, "ca_cert.pem") - temp_client_cert = File.join(__dir__, "client.pem") - - with_configured_fetcher( - ":ssl_ca_cert: #{temp_ca_cert}\n" \ - ":ssl_client_cert: #{temp_client_cert}\n" - ) do |fetcher| - fetcher.fetch_path("https://localhost:#{ssl_server.config[:Port]}/yaml") - end - end - - def test_do_not_allow_invalid_client_cert_auth_connection - ssl_server = start_ssl_server( - { SSLVerifyClient: OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT } - ) - - temp_ca_cert = File.join(__dir__, "ca_cert.pem") - temp_client_cert = File.join(__dir__, "invalid_client.pem") - - with_configured_fetcher( - ":ssl_ca_cert: #{temp_ca_cert}\n" \ - ":ssl_client_cert: #{temp_client_cert}\n" - ) do |fetcher| - assert_raise Gem::RemoteFetcher::FetchError do - fetcher.fetch_path("https://localhost:#{ssl_server.config[:Port]}/yaml") - end - end - end - - def test_do_not_allow_insecure_ssl_connection_by_default - ssl_server = start_ssl_server - with_configured_fetcher do |fetcher| - assert_raise Gem::RemoteFetcher::FetchError do - fetcher.fetch_path("https://localhost:#{ssl_server.config[:Port]}/yaml") - end - end - end - - def test_ssl_connection_allow_verify_none - ssl_server = start_ssl_server - with_configured_fetcher(":ssl_verify_mode: 0") do |fetcher| - fetcher.fetch_path("https://localhost:#{ssl_server.config[:Port]}/yaml") - end - end - - def test_do_not_follow_insecure_redirect - ssl_server = start_ssl_server - temp_ca_cert = File.join(__dir__, "ca_cert.pem") - expected_error_message = - "redirecting to non-https resource: #{@server_uri} (https://localhost:#{ssl_server.config[:Port]}/insecure_redirect?to=#{@server_uri})" - - with_configured_fetcher(":ssl_ca_cert: #{temp_ca_cert}") do |fetcher| - err = assert_raise Gem::RemoteFetcher::FetchError do - fetcher.fetch_path("https://localhost:#{ssl_server.config[:Port]}/insecure_redirect?to=#{@server_uri}") - end - - assert_equal(err.message, expected_error_message) - end - end - - def test_nil_ca_cert - ssl_server = start_ssl_server - temp_ca_cert = nil - - with_configured_fetcher(":ssl_ca_cert: #{temp_ca_cert}") do |fetcher| - assert_raise Gem::RemoteFetcher::FetchError do - fetcher.fetch_path("https://localhost:#{ssl_server.config[:Port]}") - end - end - end - - def with_configured_fetcher(config_str = nil, &block) - if config_str - temp_conf = File.join @tempdir, ".gemrc" - File.open temp_conf, "w" do |fp| - fp.puts config_str - end - Gem.configuration = Gem::ConfigFile.new %W[--config-file #{temp_conf}] - end - fetcher = Gem::RemoteFetcher.new - yield fetcher - ensure - fetcher.close_all - Gem.configuration = nil - end - def assert_data_from_server(data) assert_match(/0\.4\.11/, data, "Data is not from server") end @@ -317,8 +199,6 @@ PeIQQkFng2VVot/WAQbv3ePqWq07g1BBcwIBAg== @proxy_server ||= start_server(PROXY_DATA) @enable_yaml = true @enable_zip = false - @ssl_server = nil - @ssl_server_thread = nil end def stop_servers @@ -330,14 +210,6 @@ PeIQQkFng2VVot/WAQbv3ePqWq07g1BBcwIBAg== @proxy_server.kill.join @proxy_server = nil end - if @ssl_server - @ssl_server.stop - @ssl_server = nil - end - if @ssl_server_thread - @ssl_server_thread.kill.join - @ssl_server_thread = nil - end WEBrick::Utils::TimeoutHandler.terminate end @@ -349,48 +221,6 @@ PeIQQkFng2VVot/WAQbv3ePqWq07g1BBcwIBAg== @proxy_server[:server].config[:Port] end - def start_ssl_server(config = {}) - pend "starting this test server fails randomly on jruby" if Gem.java_platform? - - null_logger = NilLog.new - server = WEBrick::HTTPServer.new({ - Port: 0, - Logger: null_logger, - AccessLog: [], - SSLEnable: true, - SSLCACertificateFile: File.join(__dir__, "ca_cert.pem"), - SSLCertificate: cert("ssl_cert.pem"), - SSLPrivateKey: key("ssl_key.pem"), - SSLVerifyClient: nil, - SSLCertName: nil, - }.merge(config)) - server.mount_proc("/yaml") do |_req, res| - res.body = "--- true\n" - end - server.mount_proc("/insecure_redirect") do |req, res| - res.set_redirect(WEBrick::HTTPStatus::MovedPermanently, req.query["to"]) - end - server.ssl_context.tmp_dh_callback = proc { TEST_KEY_DH2048 } - t = Thread.new do - server.start - rescue StandardError => ex - puts "ERROR during server thread: #{ex.message}" - raise - ensure - server.shutdown - end - while server.status != :Running - sleep 0.1 - unless t.alive? - t.join - raise - end - end - @ssl_server = server - @ssl_server_thread = t - server - end - def start_server(data) null_logger = NilLog.new s = WEBrick::HTTPServer.new( @@ -433,12 +263,4 @@ PeIQQkFng2VVot/WAQbv3ePqWq07g1BBcwIBAg== th[:server] = s th end - - def cert(filename) - OpenSSL::X509::Certificate.new(File.read(File.join(__dir__, filename))) - end - - def key(filename) - OpenSSL::PKey::RSA.new(File.read(File.join(__dir__, filename))) - end -end if Gem::HAVE_OPENSSL +end diff --git a/test/rubygems/test_gem_remote_fetcher_local_ssl_server.rb b/test/rubygems/test_gem_remote_fetcher_local_ssl_server.rb new file mode 100644 index 0000000000..e3021cebb5 --- /dev/null +++ b/test/rubygems/test_gem_remote_fetcher_local_ssl_server.rb @@ -0,0 +1,373 @@ +# frozen_string_literal: true + +require_relative "helper" + +require "webrick" +require "webrick/https" if Gem::HAVE_OPENSSL + +unless Gem::HAVE_OPENSSL + warn "Skipping Gem::RemoteFetcher tests. openssl not found." +end + +require "rubygems/remote_fetcher" +require "rubygems/package" + +# = Testing Proxy Settings +# +# These tests check the proper proxy server settings by running two +# web servers. The web server at http://localhost:#{SERVER_PORT} +# represents the normal gem server and returns a gemspec with a rake +# version of 0.4.11. The web server at http://localhost:#{PROXY_PORT} +# represents the proxy server and returns a different dataset where +# rake has version 0.4.2. This allows us to detect which server is +# returning the data. +# +# Note that the proxy server is not a *real* proxy server. But our +# software doesn't really care, as long as we hit the proxy URL when a +# proxy is configured. + +class TestGemRemoteFetcherLocalSSLServer < Gem::TestCase + include Gem::DefaultUserInteraction + + SERVER_DATA = <<-EOY +--- !ruby/object:Gem::Cache +gems: + rake-0.4.11: !ruby/object:Gem::Specification + rubygems_version: "0.7" + specification_version: 1 + name: rake + version: !ruby/object:Gem::Version + version: 0.4.11 + date: 2004-11-12 + summary: Ruby based make-like utility. + require_paths: + - lib + author: Jim Weirich + email: jim@weirichhouse.org + homepage: http://rake.rubyforge.org + description: Rake is a Make-like program implemented in Ruby. Tasks and dependencies are specified in standard Ruby syntax. + autorequire: + bindir: bin + has_rdoc: true + required_ruby_version: !ruby/object:Gem::Version::Requirement + requirements: + - + - ">" + - !ruby/object:Gem::Version + version: 0.0.0 + version: + platform: ruby + files: + - README + test_files: [] + library_stubs: + rdoc_options: + extra_rdoc_files: + executables: + - rake + extensions: [] + requirements: [] + dependencies: [] + EOY + + PROXY_DATA = SERVER_DATA.gsub(/0.4.11/, "0.4.2") + + # Generated via: + # x = OpenSSL::PKey::DH.new(2048) # wait a while... + # x.to_s => pem + TEST_KEY_DH2048 = OpenSSL::PKey::DH.new <<-_END_OF_PEM_ +-----BEGIN DH PARAMETERS----- +MIIBCAKCAQEA3Ze2EHSfYkZLUn557torAmjBgPsqzbodaRaGZtgK1gEU+9nNJaFV +G1JKhmGUiEDyIW7idsBpe4sX/Wqjnp48Lr8IeI/SlEzLdoGpf05iRYXC8Cm9o8aM +cfmVgoSEAo9YLBpzoji2jHkO7Q5IPt4zxbTdlmmGFLc/GO9q7LGHhC+rcMcNTGsM +49AnILNn49pq4Y72jSwdmvq4psHZwwFBbPwLdw6bLUDDCN90jfqvYt18muwUxDiN +NP0fuvVAIB158VnQ0liHSwcl6+9vE1mL0Jo/qEXQxl0+UdKDjaGfTsn6HIrwTnmJ +PeIQQkFng2VVot/WAQbv3ePqWq07g1BBcwIBAg== +-----END DH PARAMETERS----- + _END_OF_PEM_ + + def setup + @proxies = %w[https_proxy http_proxy HTTP_PROXY http_proxy_user HTTP_PROXY_USER http_proxy_pass HTTP_PROXY_PASS no_proxy NO_PROXY] + @old_proxies = @proxies.map {|k| ENV[k] } + @proxies.each {|k| ENV[k] = nil } + + super + start_servers + self.enable_yaml = true + self.enable_zip = false + + base_server_uri = "http://localhost:#{normal_server_port}" + @proxy_uri = "http://localhost:#{proxy_server_port}" + + @server_uri = base_server_uri + "/yaml" + @server_z_uri = base_server_uri + "/yaml.Z" + + @cache_dir = File.join @gemhome, "cache" + + # TODO: why does the remote fetcher need it written to disk? + @a1, @a1_gem = util_gem "a", "1" do |s| + s.executables << "a_bin" + end + + @a1.loaded_from = File.join(@gemhome, "specifications", @a1.full_name) + + Gem::RemoteFetcher.fetcher = nil + @stub_ui = Gem::MockGemUi.new + @fetcher = Gem::RemoteFetcher.fetcher + end + + def teardown + @fetcher.close_all + stop_servers + super + Gem.configuration[:http_proxy] = nil + @proxies.each_with_index {|k, i| ENV[k] = @old_proxies[i] } + end + + def test_ssl_connection + ssl_server = start_ssl_server + temp_ca_cert = File.join(__dir__, "ca_cert.pem") + with_configured_fetcher(":ssl_ca_cert: #{temp_ca_cert}") do |fetcher| + fetcher.fetch_path("https://localhost:#{ssl_server.config[:Port]}/yaml") + end + end + + def test_ssl_client_cert_auth_connection + ssl_server = start_ssl_server( + { SSLVerifyClient: OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT } + ) + + temp_ca_cert = File.join(__dir__, "ca_cert.pem") + temp_client_cert = File.join(__dir__, "client.pem") + + with_configured_fetcher( + ":ssl_ca_cert: #{temp_ca_cert}\n" \ + ":ssl_client_cert: #{temp_client_cert}\n" + ) do |fetcher| + fetcher.fetch_path("https://localhost:#{ssl_server.config[:Port]}/yaml") + end + end + + def test_do_not_allow_invalid_client_cert_auth_connection + ssl_server = start_ssl_server( + { SSLVerifyClient: OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT } + ) + + temp_ca_cert = File.join(__dir__, "ca_cert.pem") + temp_client_cert = File.join(__dir__, "invalid_client.pem") + + with_configured_fetcher( + ":ssl_ca_cert: #{temp_ca_cert}\n" \ + ":ssl_client_cert: #{temp_client_cert}\n" + ) do |fetcher| + assert_raise Gem::RemoteFetcher::FetchError do + fetcher.fetch_path("https://localhost:#{ssl_server.config[:Port]}/yaml") + end + end + end + + def test_do_not_allow_insecure_ssl_connection_by_default + ssl_server = start_ssl_server + with_configured_fetcher do |fetcher| + assert_raise Gem::RemoteFetcher::FetchError do + fetcher.fetch_path("https://localhost:#{ssl_server.config[:Port]}/yaml") + end + end + end + + def test_ssl_connection_allow_verify_none + ssl_server = start_ssl_server + with_configured_fetcher(":ssl_verify_mode: 0") do |fetcher| + fetcher.fetch_path("https://localhost:#{ssl_server.config[:Port]}/yaml") + end + end + + def test_do_not_follow_insecure_redirect + ssl_server = start_ssl_server + temp_ca_cert = File.join(__dir__, "ca_cert.pem") + expected_error_message = + "redirecting to non-https resource: #{@server_uri} (https://localhost:#{ssl_server.config[:Port]}/insecure_redirect?to=#{@server_uri})" + + with_configured_fetcher(":ssl_ca_cert: #{temp_ca_cert}") do |fetcher| + err = assert_raise Gem::RemoteFetcher::FetchError do + fetcher.fetch_path("https://localhost:#{ssl_server.config[:Port]}/insecure_redirect?to=#{@server_uri}") + end + + assert_equal(err.message, expected_error_message) + end + end + + def test_nil_ca_cert + ssl_server = start_ssl_server + temp_ca_cert = nil + + with_configured_fetcher(":ssl_ca_cert: #{temp_ca_cert}") do |fetcher| + assert_raise Gem::RemoteFetcher::FetchError do + fetcher.fetch_path("https://localhost:#{ssl_server.config[:Port]}") + end + end + end + + def with_configured_fetcher(config_str = nil, &block) + if config_str + temp_conf = File.join @tempdir, ".gemrc" + File.open temp_conf, "w" do |fp| + fp.puts config_str + end + Gem.configuration = Gem::ConfigFile.new %W[--config-file #{temp_conf}] + end + fetcher = Gem::RemoteFetcher.new + yield fetcher + ensure + fetcher.close_all + Gem.configuration = nil + end + + def assert_data_from_server(data) + assert_match(/0\.4\.11/, data, "Data is not from server") + end + + def assert_data_from_proxy(data) + assert_match(/0\.4\.2/, data, "Data is not from proxy") + end + + class NilLog < WEBrick::Log + def log(level, data) # Do nothing + end + end + + private + + attr_reader :normal_server, :proxy_server + attr_accessor :enable_zip, :enable_yaml + + def start_servers + @normal_server ||= start_server(SERVER_DATA) + @proxy_server ||= start_server(PROXY_DATA) + @enable_yaml = true + @enable_zip = false + @ssl_server = nil + @ssl_server_thread = nil + end + + def stop_servers + if @normal_server + @normal_server.kill.join + @normal_server = nil + end + if @proxy_server + @proxy_server.kill.join + @proxy_server = nil + end + if @ssl_server + @ssl_server.stop + @ssl_server = nil + end + if @ssl_server_thread + @ssl_server_thread.kill.join + @ssl_server_thread = nil + end + WEBrick::Utils::TimeoutHandler.terminate + end + + def normal_server_port + @normal_server[:server].config[:Port] + end + + def proxy_server_port + @proxy_server[:server].config[:Port] + end + + def start_ssl_server(config = {}) + pend "starting this test server fails randomly on jruby" if Gem.java_platform? + + null_logger = NilLog.new + server = WEBrick::HTTPServer.new({ + Port: 0, + Logger: null_logger, + AccessLog: [], + SSLEnable: true, + SSLCACertificateFile: File.join(__dir__, "ca_cert.pem"), + SSLCertificate: cert("ssl_cert.pem"), + SSLPrivateKey: key("ssl_key.pem"), + SSLVerifyClient: nil, + SSLCertName: nil, + }.merge(config)) + server.mount_proc("/yaml") do |_req, res| + res.body = "--- true\n" + end + server.mount_proc("/insecure_redirect") do |req, res| + res.set_redirect(WEBrick::HTTPStatus::MovedPermanently, req.query["to"]) + end + server.ssl_context.tmp_dh_callback = proc { TEST_KEY_DH2048 } + t = Thread.new do + server.start + rescue StandardError => ex + puts "ERROR during server thread: #{ex.message}" + raise + ensure + server.shutdown + end + while server.status != :Running + sleep 0.1 + unless t.alive? + t.join + raise + end + end + @ssl_server = server + @ssl_server_thread = t + server + end + + def start_server(data) + null_logger = NilLog.new + s = WEBrick::HTTPServer.new( + Port: 0, + DocumentRoot: nil, + Logger: null_logger, + AccessLog: null_logger + ) + s.mount_proc("/kill") {|_req, _res| s.shutdown } + s.mount_proc("/yaml") do |req, res| + if req["X-Captain"] + res.body = req["X-Captain"] + elsif @enable_yaml + res.body = data + res["Content-Type"] = "text/plain" + res["content-length"] = data.size + else + res.status = "404" + res.body = "<h1>NOT FOUND</h1>" + res["Content-Type"] = "text/html" + end + end + s.mount_proc("/yaml.Z") do |_req, res| + if @enable_zip + res.body = Zlib::Deflate.deflate(data) + res["Content-Type"] = "text/plain" + else + res.status = "404" + res.body = "<h1>NOT FOUND</h1>" + res["Content-Type"] = "text/html" + end + end + th = Thread.new do + s.start + rescue StandardError => ex + abort "ERROR during server thread: #{ex.message}" + ensure + s.shutdown + end + th[:server] = s + th + end + + def cert(filename) + OpenSSL::X509::Certificate.new(File.read(File.join(__dir__, filename))) + end + + def key(filename) + OpenSSL::PKey::RSA.new(File.read(File.join(__dir__, filename))) + end +end if Gem::HAVE_OPENSSL |
