uninterruptible 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7f8d400309d6f9bf1354f04b9002aad29d077d2e
4
- data.tar.gz: 3cb256b49089b46fdf7820594a6919c71e9d4d9f
3
+ metadata.gz: 45b1e17d9779c26d177d31c7dcdf49b4128eb0f4
4
+ data.tar.gz: 4a59b5fef72bd683bdfdcfa10d2c27a744271418
5
5
  SHA512:
6
- metadata.gz: 4649cdbf7b3eff9fff3709f343513cf36a21814e03c1092c0d09d4a6ff4905bfdfb32ae61866a41caf513867623689429c44dfe5a8df57e824c2173699c52c63
7
- data.tar.gz: d05d7c375ab9bd546691516abbbc7205a4221cfa60ffa8ddd3ea072fa9028fb12e51dc1951f83053605e7dd37ef9793dbf9c06e29631d7d00425128495ff82bb
6
+ metadata.gz: c3920549cf5cc3b176e385769190561920c9e21abe87ee9ec4deca2b73f99382e68b12e89071282b5258d985c1dbbed1712da90cfe4639fd2df06733167a205d
7
+ data.tar.gz: 615f4a872242d4d7fbade36d0457d7f5fb2433abf22061b8c1917a3a1e36f80288882d93ac6960d9aaab67a524d48fa8e02383a770158e30a2993e8c16cec88b
@@ -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.
@@ -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
- attr_writer :bind, :bind_port, :bind_address, :pidfile_path, :start_command, :log_path, :log_level
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 socket_server_FD is set in the env,
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
@@ -1,3 +1,3 @@
1
1
  module Uninterruptible
2
- VERSION = "2.0.0"
2
+ VERSION = "2.1.0"
3
3
  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.0.0
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-07-21 00:00:00.000000000 Z
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