Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support localhost integration in ssl_bind #2764

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 @@ -191,7 +191,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 @@ -441,8 +441,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 @@ -453,21 +460,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