uninterruptible 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -0
- data/README.md +7 -0
- data/lib/uninterruptible.rb +3 -0
- data/lib/uninterruptible/configuration.rb +35 -2
- data/lib/uninterruptible/server.rb +5 -1
- data/lib/uninterruptible/ssl_extensions.rb +30 -0
- data/lib/uninterruptible/tls_server_factory.rb +49 -0
- data/lib/uninterruptible/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 45b1e17d9779c26d177d31c7dcdf49b4128eb0f4
|
4
|
+
data.tar.gz: 4a59b5fef72bd683bdfdcfa10d2c27a744271418
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c3920549cf5cc3b176e385769190561920c9e21abe87ee9ec4deca2b73f99382e68b12e89071282b5258d985c1dbbed1712da90cfe4639fd2df06733167a205d
|
7
|
+
data.tar.gz: 615f4a872242d4d7fbade36d0457d7f5fb2433abf22061b8c1917a3a1e36f80288882d93ac6960d9aaab67a524d48fa8e02383a770158e30a2993e8c16cec88b
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
# 2.1.0
|
4
|
+
* Add TLS support for TCP connections
|
5
|
+
|
3
6
|
# 2.0.0
|
4
7
|
* Use an internal pipe for delivering signals to the main thread.
|
5
8
|
* `accept_connections` retired in favour of a select loop and `accept_client_connection` being called for each waiting connection
|
data/README.md
CHANGED
@@ -64,6 +64,9 @@ echo_server.configure do |config|
|
|
64
64
|
config.pidfile_path = 'tmp/pids/echoserver.pid' # Location to write a pidfile, falls back to ENV['PID_FILE']
|
65
65
|
config.log_path = 'log/echoserver.log' # Location to write logfile, defaults to STDOUT
|
66
66
|
config.log_level = Logger::INFO # Log writing severity, defaults to Logger::INFO
|
67
|
+
config.tls_version = 'TLSv1_2' # TLS version to use, defaults to TLSv1_2, falls back to ENV['TLS_VERSION']
|
68
|
+
config.tls_key = nil # Private key to use for TLS, reads file from ENV['TLS_KEY'] if set
|
69
|
+
config.tls_certificate = nil # Certificate to use for TLS, reads file from ENV['TLS_CERTIFICATE'] if set
|
67
70
|
end
|
68
71
|
```
|
69
72
|
|
@@ -119,6 +122,10 @@ class EchoServer
|
|
119
122
|
end
|
120
123
|
```
|
121
124
|
|
125
|
+
## TLS Support
|
126
|
+
|
127
|
+
If you would like to encrypt your TCP socket, Uninterruptible supports TLSv1.1 and TLSv1.2. Simply set `configuration.tls_key` and `configuration.tls_certificate` (see "Configuration" above) and your TCP socket will automatically be wrapped with TLS.
|
128
|
+
|
122
129
|
## Contributing
|
123
130
|
|
124
131
|
Bug reports and pull requests are welcome on GitHub at https://github.com/darkphnx/uninterruptible.
|
data/lib/uninterruptible.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
+
require 'openssl'
|
1
2
|
require "uninterruptible/version"
|
3
|
+
require 'uninterruptible/ssl_extensions'
|
2
4
|
require 'uninterruptible/configuration'
|
3
5
|
require 'uninterruptible/binder'
|
6
|
+
require 'uninterruptible/tls_server_factory'
|
4
7
|
require 'uninterruptible/server'
|
5
8
|
|
6
9
|
# All of the interesting stuff is in Uninterruptible::Server
|
@@ -3,7 +3,10 @@ module Uninterruptible
|
|
3
3
|
#
|
4
4
|
# See {Server#configure} for usage instructions.
|
5
5
|
class Configuration
|
6
|
-
|
6
|
+
AVAILABLE_SSL_VERSIONS = %w[TLSv1_1 TLSv1_2].freeze
|
7
|
+
|
8
|
+
attr_writer :bind, :bind_port, :bind_address, :pidfile_path, :start_command, :log_path, :log_level, :tls_version,
|
9
|
+
:tls_key, :tls_certificate
|
7
10
|
|
8
11
|
# Available TCP Port for the server to bind to (required). Falls back to environment variable PORT if set.
|
9
12
|
#
|
@@ -19,7 +22,7 @@ module Uninterruptible
|
|
19
22
|
@bind_address || "0.0.0.0"
|
20
23
|
end
|
21
24
|
|
22
|
-
# URI to bind to, falls back to tcp://bind_address:bind_port if unset
|
25
|
+
# URI to bind to, falls back to tcp://bind_address:bind_port if unset. Accepts tcp:// or unix:// schemes.
|
23
26
|
def bind
|
24
27
|
@bind || "tcp://#{bind_address}:#{bind_port}"
|
25
28
|
end
|
@@ -48,5 +51,35 @@ module Uninterruptible
|
|
48
51
|
def log_level
|
49
52
|
@log_level || Logger::INFO
|
50
53
|
end
|
54
|
+
|
55
|
+
# Should the socket server be wrapped with a TLS server (TCP only). Automatically enabled when #tls_key or
|
56
|
+
# #tls_certificate is set
|
57
|
+
def tls_enabled?
|
58
|
+
!tls_key.nil? || !tls_certificate.nil?
|
59
|
+
end
|
60
|
+
|
61
|
+
# TLS version to use for the connection. Must be one of +Uninterruptible::Configuration::AVAILABLE_SSL_VERSIONS+
|
62
|
+
# If unset, connection will be unencrypted.
|
63
|
+
def tls_version
|
64
|
+
version = @tls_version || ENV['TLS_VERSION'] || 'TLSv1_2'
|
65
|
+
|
66
|
+
unless AVAILABLE_SSL_VERSIONS.include?(version)
|
67
|
+
raise ConfigurationError, "Please ensure tls_version is one of #{AVAILABLE_SSL_VERSIONS.join(', ')}"
|
68
|
+
end
|
69
|
+
|
70
|
+
version
|
71
|
+
end
|
72
|
+
|
73
|
+
# Private key used for encrypting TLS connection. If environment variable TLS_KEY is set, attempt to read from a
|
74
|
+
# file at that location.
|
75
|
+
def tls_key
|
76
|
+
@tls_key || (ENV['TLS_KEY'] ? File.read(ENV['TLS_KEY']) : nil)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Certificate used for authenticating TLS connection. If environment variable TLS_CERTIFICATE is set, attempt to
|
80
|
+
# read from a file at that location
|
81
|
+
def tls_certificate
|
82
|
+
@tls_certificate || (ENV['TLS_CERTIFICATE'] ? File.read(ENV['TLS_CERTIFICATE']) : nil)
|
83
|
+
end
|
51
84
|
end
|
52
85
|
end
|
@@ -108,7 +108,7 @@ module Uninterruptible
|
|
108
108
|
end
|
109
109
|
end
|
110
110
|
|
111
|
-
# Listen (or reconnect) to the bind address and port specified in the config. If
|
111
|
+
# Listen (or reconnect) to the bind address and port specified in the config. If SERVER_FD_VAR is set in the env,
|
112
112
|
# reconnect to that file descriptor. Once @socket_server is set, write the file descriptor ID to the env.
|
113
113
|
def establish_socket_server
|
114
114
|
@socket_server = Uninterruptible::Binder.new(server_configuration.bind).bind_to_socket
|
@@ -118,6 +118,10 @@ module Uninterruptible
|
|
118
118
|
@socket_server.autoclose = false
|
119
119
|
@socket_server.close_on_exec = false
|
120
120
|
|
121
|
+
if server_configuration.tls_enabled?
|
122
|
+
@socket_server = Uninterruptible::TLSServerFactory.new(server_configuration).wrap_with_tls(@socket_server)
|
123
|
+
end
|
124
|
+
|
121
125
|
ENV[SERVER_FD_VAR] = @socket_server.to_i.to_s
|
122
126
|
end
|
123
127
|
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# Augment some parts of OpenSSL::SSL::SSLServer from stdlib for extra functionality
|
2
|
+
module OpenSSL
|
3
|
+
module SSL
|
4
|
+
# Extend this module from stdlib to delegate additional methods to the underlying TCP transport when wrapping
|
5
|
+
# with an OpenSSL::SSL::SSLServer
|
6
|
+
module SocketForwarder
|
7
|
+
# Fetch the file descriptor ID from the underlying transport
|
8
|
+
def to_i
|
9
|
+
to_io.to_i
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Extend OpenSSL::SSL::SSLServer to implement accept_nonblock (only #accept is implemented by stdlib)
|
14
|
+
class SSLServer
|
15
|
+
def accept_nonblock
|
16
|
+
sock = @svr.accept_nonblock
|
17
|
+
|
18
|
+
begin
|
19
|
+
ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx)
|
20
|
+
ssl.sync_close = true
|
21
|
+
ssl.accept if @start_immediately
|
22
|
+
ssl
|
23
|
+
rescue SSLError => ex
|
24
|
+
sock.close
|
25
|
+
raise ex
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Uninterruptible
|
2
|
+
# Wraps a bound TCP server with an OpenSSL::SSL::SSLServer according to the Uninterruptible::Configuration for
|
3
|
+
# this server.
|
4
|
+
class TLSServerFactory
|
5
|
+
attr_reader :configuration
|
6
|
+
|
7
|
+
# @param [Uninterruptible::Configuration] configuration Object with valid TLS configuration options
|
8
|
+
#
|
9
|
+
# @raise [Uninterruptible::ConfigurationError] Correct options are not set for TLS
|
10
|
+
def initialize(configuration)
|
11
|
+
@configuration = configuration
|
12
|
+
check_configuration!
|
13
|
+
end
|
14
|
+
|
15
|
+
# Accepts a TCP server, gives it a nice friendly SSLServer wrapper and returns the SSLServer
|
16
|
+
#
|
17
|
+
# @param [TCPServer] tcp_server Server to be wrapped
|
18
|
+
#
|
19
|
+
# @return [OpenSSL::SSL::SSLServer] tcp_server with a TLS layer
|
20
|
+
def wrap_with_tls(tcp_server)
|
21
|
+
server = OpenSSL::SSL::SSLServer.new(tcp_server, ssl_context)
|
22
|
+
server.start_immediately = true
|
23
|
+
server
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# Build an OpenSSL::SSL::SSLContext object from the configuration passed to the initializer
|
29
|
+
#
|
30
|
+
# @return [OpenSSL::SSL::SSLContext] SSL context for the server config
|
31
|
+
def ssl_context
|
32
|
+
context = OpenSSL::SSL::SSLContext.new
|
33
|
+
context.cert = OpenSSL::X509::Certificate.new(configuration.tls_certificate)
|
34
|
+
context.key = OpenSSL::PKey::RSA.new(configuration.tls_key)
|
35
|
+
context.ssl_version = configuration.tls_version.to_sym
|
36
|
+
context
|
37
|
+
end
|
38
|
+
|
39
|
+
# Check the configuration parameters for TLS are correct
|
40
|
+
#
|
41
|
+
# @raise [Uninterruptible::ConfigurationError] Correct options are not set for TLS
|
42
|
+
def check_configuration!
|
43
|
+
raise ConfigurationError, "TLS can only be used on TCP servers" unless configuration.bind.start_with?('tcp://')
|
44
|
+
|
45
|
+
empty = %i[tls_certificate tls_key].any? { |config_param| configuration.send(config_param).nil? }
|
46
|
+
raise ConfigurationError, "tls_certificate and tls_key must be set to use TLS" if empty
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: uninterruptible
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Wentworth
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-08-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -76,6 +76,8 @@ files:
|
|
76
76
|
- lib/uninterruptible/binder.rb
|
77
77
|
- lib/uninterruptible/configuration.rb
|
78
78
|
- lib/uninterruptible/server.rb
|
79
|
+
- lib/uninterruptible/ssl_extensions.rb
|
80
|
+
- lib/uninterruptible/tls_server_factory.rb
|
79
81
|
- lib/uninterruptible/version.rb
|
80
82
|
- uninterruptible.gemspec
|
81
83
|
homepage: https://github.com/darkphnx/uninterruptible
|