Skip to content

Commit

Permalink
Support localhost integration in ssl_bind (puma#2764)
Browse files Browse the repository at this point in the history
Close puma#2708
Close puma#2711

Co-authored-by: Marcin Olichwirowicz <marcin.olichwirowicz@nedap.com>

Co-authored-by: Marcin Olichwirowicz <marcin.olichwirowicz@nedap.com>
  • Loading branch information
2 people authored and JuanitoFatas committed Sep 9, 2022
1 parent 8427098 commit 1a8bd06
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 8 deletions.
4 changes: 3 additions & 1 deletion lib/puma/binder.rb
Expand Up @@ -233,7 +233,9 @@ def parse(binds, logger, log_msg = 'Listening')
# If key and certs are not defined and localhost gem is required.
# localhost gem will be used for self signed
# Load localhost authority if not loaded.
ctx = localhost_authority && localhost_authority_context if params.empty?
if params.values_at('cert', 'key').all? { |v| v.to_s.empty? }
ctx = localhost_authority && localhost_authority_context
end

ctx ||=
begin
Expand Down
23 changes: 16 additions & 7 deletions lib/puma/dsl.rb
Expand Up @@ -193,7 +193,7 @@ def load(file)
end

# Bind the server to +url+. "tcp://", "unix://" and "ssl://" are the only
# accepted protocols. Multiple urls can be bound to, calling `bind` does
# accepted protocols. Multiple urls can be bound to, calling +bind+ does
# not overwrite previous bindings.
#
# The default is "tcp://0.0.0.0:9292".
Expand Down Expand Up @@ -438,8 +438,15 @@ def threads(min, max)
@options[:max_threads] = max
end

# Instead of `bind 'ssl://127.0.0.1:9292?key=key_path&cert=cert_path'` you
# can also use the this method.
# Instead of using +bind+ and manually constructing a URI like:
#
# bind 'ssl://127.0.0.1:9292?key=key_path&cert=cert_path'
#
# you can use the this method.
#
# When binding on localhost you don't need to specify +cert+ and +key+,
# Puma will assume you are using the +localhost+ gem and try to load the
# appropriate files.
#
# @example
# ssl_bind '127.0.0.1', '9292', {
Expand All @@ -450,21 +457,23 @@ def threads(min, max)
# verification_flags: flags, # optional, not supported by JRuby
# }
#
# Alternatively, you can provide the cert_pem and key_pem:
# @example
# @example Using self-signed certificate with the +localhost+ gem:
# ssl_bind '127.0.0.1', '9292'
#
# @example Alternatively, you can provide +cert_pem+ and +key_pem+:
# ssl_bind '127.0.0.1', '9292', {
# cert_pem: File.read(path_to_cert),
# key_pem: File.read(path_to_key),
# }
#
# @example For JRuby, two keys are required: keystore & keystore_pass.
# @example For JRuby, two keys are required: +keystore+ & +keystore_pass+
# ssl_bind '127.0.0.1', '9292', {
# keystore: path_to_keystore,
# keystore_pass: password,
# ssl_cipher_list: cipher_list, # optional
# verify_mode: verify_mode # default 'none'
# }
def ssl_bind(host, port, opts)
def ssl_bind(host, port, opts = {})
add_pem_values_to_options_store(opts)
bind self.class.ssl_bind_str(host, port, opts)
end
Expand Down
7 changes: 7 additions & 0 deletions test/config/ssl_self_signed_config.rb
@@ -0,0 +1,7 @@
require "localhost"

ssl_bind "0.0.0.0", 9292

app do |env|
[200, {}, ["self-signed certificate app"]]
end
16 changes: 16 additions & 0 deletions test/test_config.rb
Expand Up @@ -58,6 +58,22 @@ def test_ssl_configuration_from_DSL
assert_equal [200, {}, ["embedded app"]], app.call({})
end

def test_ssl_self_signed_configuration_from_DSL
skip_if :jruby
skip_unless :ssl
conf = Puma::Configuration.new do |config|
config.load "test/config/ssl_self_signed_config.rb"
end

conf.load

bind_configuration = conf.options.file_options[:binds].first
app = conf.app

ssl_binding = "ssl://0.0.0.0:9292?cert=&key=&verify_mode=none"
assert_equal [ssl_binding], conf.options[:binds]
end

def test_ssl_bind
skip_if :jruby
skip_unless :ssl
Expand Down
24 changes: 24 additions & 0 deletions test/test_integration_ssl.rb
Expand Up @@ -108,6 +108,30 @@ def test_ssl_run_with_pem
activate_control_app 'tcp://#{HOST}:#{control_tcp_port}', { auth_token: '#{TOKEN}' }
app do |env|
[200, {}, [env['rack.url_scheme']]]
end
RUBY

with_server(config) do |http|
body = nil
http.start do
req = Net::HTTP::Get.new '/', {}
http.request(req) { |resp| body = resp.body }
end
assert_equal 'https', body
end
end

def test_ssl_run_with_localhost_authority
skip_if :jruby

config = <<RUBY
require 'localhost'
ssl_bind '#{HOST}', '#{bind_port}'
activate_control_app 'tcp://#{HOST}:#{control_tcp_port}', { auth_token: '#{TOKEN}' }
app do |env|
[200, {}, [env['rack.url_scheme']]]
end
Expand Down

0 comments on commit 1a8bd06

Please sign in to comment.