From abc5e72684879003d5101d0e791bc0fb8856ae0a Mon Sep 17 00:00:00 2001 From: Daniel Colson Date: Sun, 20 Oct 2019 17:34:07 -0400 Subject: [PATCH] Add SSL support for the control app This starts to address [#2015]. I think we will need to add SSL support to the control cli as well. [#2015]: https://github.com/puma/puma/issues/2015 --- lib/puma/runner.rb | 7 +++++++ test/helpers/ssl.rb | 13 +++++++++++++ test/test_binder.rb | 15 +++------------ test/test_cli.rb | 39 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 12 deletions(-) create mode 100644 test/helpers/ssl.rb diff --git a/lib/puma/runner.rb b/lib/puma/runner.rb index 2b8e8482d0..2c9812fd92 100644 --- a/lib/puma/runner.rb +++ b/lib/puma/runner.rb @@ -2,6 +2,7 @@ require 'puma/server' require 'puma/const' +require 'puma/minissl/context_builder' module Puma # Generic class that is used by `Puma::Cluster` and `Puma::Single` to @@ -64,6 +65,12 @@ def start_control control.max_threads = 1 case uri.scheme + when "ssl" + log "* Starting control server on #{str}" + params = Util.parse_query uri.query + ctx = MiniSSL::ContextBuilder.new(params, @events).context + + control.add_ssl_listener uri.host, uri.port, ctx when "tcp" log "* Starting control server on #{str}" control.add_tcp_listener uri.host, uri.port diff --git a/test/helpers/ssl.rb b/test/helpers/ssl.rb new file mode 100644 index 0000000000..e9e7b24ea5 --- /dev/null +++ b/test/helpers/ssl.rb @@ -0,0 +1,13 @@ +module SSLHelper + def ssl_query + @ssl_query ||= if Puma.jruby? + @keystore = File.expand_path "../../../examples/puma/keystore.jks", __FILE__ + @ssl_cipher_list = "TLS_DHE_RSA_WITH_DES_CBC_SHA,TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA" + "keystore=#{@keystore}&keystore-pass=pswd&ssl_cipher_list=#{@ssl_cipher_list}" + else + @cert = File.expand_path "../../../examples/puma/cert_puma.pem", __FILE__ + @key = File.expand_path "../../../examples/puma/puma_keypair.pem", __FILE__ + "key=#{@key}&cert=#{@cert}" + end + end +end diff --git a/test/test_binder.rb b/test/test_binder.rb index 2d21414192..7bd930946c 100644 --- a/test/test_binder.rb +++ b/test/test_binder.rb @@ -1,11 +1,14 @@ # frozen_string_literal: true require_relative "helper" +require_relative "helpers/ssl" require "puma/binder" require "puma/puma_http11" class TestBinderBase < Minitest::Test + include SSLHelper + def setup @events = Puma::Events.strings @binder = Puma::Binder.new(@events) @@ -16,18 +19,6 @@ def setup def ssl_context_for_binder(binder = @binder) binder.ios[0].instance_variable_get(:@ctx) end - - def ssl_query - @ssl_query ||= if Puma.jruby? - @keystore = File.expand_path "../../examples/puma/keystore.jks", __FILE__ - @ssl_cipher_list = "TLS_DHE_RSA_WITH_DES_CBC_SHA,TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA" - "keystore=#{@keystore}&keystore-pass=pswd&ssl_cipher_list=#{@ssl_cipher_list}" - else - @cert = File.expand_path "../../examples/puma/cert_puma.pem", __FILE__ - @key = File.expand_path "../../examples/puma/puma_keypair.pem", __FILE__ - "key=#{@key}&cert=#{@cert}" - end - end end class TestBinder < TestBinderBase diff --git a/test/test_cli.rb b/test/test_cli.rb index f53ff53793..44d548051d 100644 --- a/test/test_cli.rb +++ b/test/test_cli.rb @@ -1,9 +1,12 @@ require_relative "helper" +require_relative "helpers/ssl" require "puma/cli" require "json" class TestCLI < Minitest::Test + include SSLHelper + def setup @environment = 'production' @tmp_file = Tempfile.new("puma-test") @@ -62,6 +65,42 @@ def test_control_for_tcp t.join end + def test_control_for_ssl + app_port = UniquePort.call + control_port = UniquePort.call + control_host = "127.0.0.1" + control_url = "ssl://#{control_host}:#{control_port}?#{ssl_query}" + token = "token" + + cli = Puma::CLI.new ["-b", "tcp://127.0.0.1:#{app_port}", + "--control-url", control_url, + "--control-token", token, + "test/rackup/lobster.ru"], @events + + t = Thread.new do + cli.run + end + + wait_booted + + body = "" + http = Net::HTTP.new control_host, control_port + http.use_ssl = true + http.verify_mode = OpenSSL::SSL::VERIFY_NONE + http.start do + req = Net::HTTP::Get.new "/stats?token=#{token}", {} + body = http.request(req).body + end + + expected_stats = /{ "started_at": "\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z", "backlog": 0, "running": 0, "pool_capacity": 16, "max_threads": 16 }/ + assert_match(expected_stats, body.split(/\r?\n/).last) + assert_match(expected_stats, Puma.stats) + + ensure + cli.launcher.stop + t.join + end + def test_control_clustered skip NO_FORK_MSG unless HAS_FORK skip UNIX_SKT_MSG unless UNIX_SKT_EXIST