forked from puma/puma
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Automatic SSL certificate provisioning for localhost (puma#2610)
* Added puma to automatically use localhost gem to self signed https if defined. * Update files according to rubocop rules * Moved localhost authority from tcp_listener to ssl_listener Use MiniSSLContext and MiniSSLServer for localhost authority's self-signed ceritifcates * Reformatted codes according to rubocop rules * Fixed test case crashing in production env * Removed transform_keys to support ruby version < 2.5.0 * Changed wrong keystore_pass key given to context to keystore-pass * Remove accept_nonblock.rb since we are using MiniSSL Server * Removed localhost_authority test case running in JRUBY since localhost_authority doesn't suppot JKS yet. * Reload Localhost authority if not loaded runned from puma cli * Memorise localhost authority object on init * Added readme for self-signed certificates * Removed jruby version * Update readme.md * Added validations to check certificate * Remove ssl test running in no ssl implementations * Changed host in localhost authority * Update ssl events wrong arguments error * Update README.md * Update binder.rb * Update binder.rb * Update binder.rb * Update binder.rb * Update request.rb * Update binder * Removed running test in JRUBY * Removed testing localhost authority file while in JRUBY * Removed unused variables * Updated readme Co-authored-by: Nate Berkopec <nate.berkopec@gmail.com>
- Loading branch information
1 parent
c425c5f
commit ffc3dbe
Showing
4 changed files
with
151 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,3 +23,4 @@ if %w(2.2.7 2.2.8 2.2.9 2.2.10 2.3.4 2.4.1).include? RUBY_VERSION | |
end | ||
|
||
gem 'm' | ||
gem "localhost", require: false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
# Nothing in this file runs if Puma isn't compiled with ssl support | ||
# | ||
# helper is required first since it loads Puma, which needs to be | ||
# loaded so HAS_SSL is defined | ||
require_relative "helper" | ||
require "localhost/authority" | ||
|
||
if ::Puma::HAS_SSL && !Puma::IS_JRUBY | ||
require "puma/minissl" | ||
require "puma/events" | ||
require "net/http" | ||
|
||
class SSLEventsHelper < ::Puma::Events | ||
attr_accessor :addr, :cert, :error | ||
|
||
def ssl_error(error, ssl_socket) | ||
self.error = error | ||
self.addr = ssl_socket.peeraddr.last rescue "<unknown>" | ||
self.cert = ssl_socket.peercert | ||
end | ||
end | ||
|
||
# net/http (loaded in helper) does not necessarily load OpenSSL | ||
require "openssl" unless Object.const_defined? :OpenSSL | ||
end | ||
|
||
class TestPumaLocalhostAuthority < Minitest::Test | ||
parallelize_me! | ||
def setup | ||
@http = nil | ||
@server = nil | ||
end | ||
|
||
def teardown | ||
@http.finish if @http && @http.started? | ||
@server.stop(true) if @server | ||
end | ||
|
||
# yields ctx to block, use for ctx setup & configuration | ||
def start_server | ||
@host = "localhost" | ||
app = lambda { |env| [200, {}, [env['rack.url_scheme']]] } | ||
|
||
@events = SSLEventsHelper.new STDOUT, STDERR | ||
@server = Puma::Server.new app, @events | ||
@server.app = app | ||
@server.add_ssl_listener @host, 0,nil | ||
@http = Net::HTTP.new @host, @server.connected_ports[0] | ||
|
||
@http.use_ssl = true | ||
# Disabling verification since its self signed | ||
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE | ||
# @http.verify_mode = OpenSSL::SSL::VERIFY_NONE | ||
|
||
@server.run | ||
end | ||
|
||
def test_localhost_authority_file_generated | ||
# Initiate server to create localhost authority | ||
unless File.exist?(File.join(Localhost::Authority.path,"localhost.key")) | ||
start_server | ||
end | ||
assert_equal(File.exist?(File.join(Localhost::Authority.path,"localhost.key")), true) | ||
assert_equal(File.exist?(File.join(Localhost::Authority.path,"localhost.crt")), true) | ||
end | ||
|
||
end if ::Puma::HAS_SSL && !Puma::IS_JRUBY | ||
|
||
class TestPumaSSLLocalhostAuthority < Minitest::Test | ||
def test_self_signed_by_localhost_authority | ||
@host = "localhost" | ||
|
||
app = lambda { |env| [200, {}, [env['rack.url_scheme']]] } | ||
|
||
@events = SSLEventsHelper.new STDOUT, STDERR | ||
|
||
@server = Puma::Server.new app, @events | ||
@server.app = app | ||
|
||
@server.add_ssl_listener @host, 0,nil | ||
|
||
@http = Net::HTTP.new @host, @server.connected_ports[0] | ||
@http.use_ssl = true | ||
|
||
OpenSSL::PKey::RSA.new File.read(File.join(Localhost::Authority.path,"localhost.key")) | ||
local_authority_crt = OpenSSL::X509::Certificate.new File.read(File.join(Localhost::Authority.path,"localhost.crt")) | ||
|
||
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE | ||
@server.run | ||
@cert = nil | ||
begin | ||
@http.start do | ||
req = Net::HTTP::Get.new "/", {} | ||
@http.request(req) | ||
@cert = @http.peer_cert | ||
end | ||
rescue OpenSSL::SSL::SSLError, EOFError, Errno::ECONNRESET | ||
# Errno::ECONNRESET TruffleRuby | ||
# closes socket if open, may not close on error | ||
@http.send :do_finish | ||
end | ||
sleep 0.1 | ||
|
||
assert_equal(@cert.to_pem, local_authority_crt.to_pem) | ||
end | ||
end if ::Puma::HAS_SSL && !Puma::IS_JRUBY |