logstash-input-tcp 5.1.0-java → 5.2.0-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/Gemfile +4 -0
- data/docs/index.asciidoc +17 -5
- data/lib/logstash/inputs/tcp.rb +26 -62
- data/lib/logstash/inputs/tcp/compat_ssl_options.rb +103 -0
- data/spec/inputs/tcp_spec.rb +104 -79
- data/vendor/jar-dependencies/org/logstash/inputs/logstash-input-tcp/{5.1.0/logstash-input-tcp-5.1.0.jar → 5.2.0/logstash-input-tcp-5.2.0.jar} +0 -0
- data/version +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f821e3a9df2b90606b5fd46026262b5c7a0054d5e24bf7545d322efbedec40a
|
4
|
+
data.tar.gz: 202f4eeb3fe522d4df635599b7557faaab6884db8d80c1a92a17f140915c1d02
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cee3f82c41bfefea68c3e0337a5ad15f50e17ba6e72fe4fbcf004c6580d755107d47435667c73022938fe852a7e4a7401e793f6640c70bac0486f8fcbbd63642
|
7
|
+
data.tar.gz: a588b4ca240e7eb9e6cca0aec296999270c89b375d7b8038de989529447bf8f5df1c38faae49d71821f2051906e34e32e5f834f248ad2a2856583a7b16704caf
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
## 5.2.0
|
2
|
+
- Added support for pkcs1 and pkcs8 key formats [#122](https://github.com/logstash-plugins/logstash-input-tcp/issues/122)
|
3
|
+
- Changed server-mode SSL to run on top of Netty [#122](https://github.com/logstash-plugins/logstash-input-tcp/issues/122)
|
4
|
+
- Changed travis testing infra to use logstash tarballs [#122](https://github.com/logstash-plugins/logstash-input-tcp/issues/122)
|
5
|
+
- Fixed certificate chain handling and validation [#124](https://github.com/logstash-plugins/logstash-input-tcp/issues/124)
|
6
|
+
|
1
7
|
## 5.1.0
|
2
8
|
- Added new configuration option `dns_reverse_lookup_enabled` to allow users to disable costly DNS reverse lookups [#100](https://github.com/logstash-plugins/logstash-input-tcp/issues/100)
|
3
9
|
|
data/Gemfile
CHANGED
@@ -9,3 +9,7 @@ if Dir.exist?(logstash_path) && use_logstash_source
|
|
9
9
|
gem 'logstash-core', :path => "#{logstash_path}/logstash-core"
|
10
10
|
gem 'logstash-core-plugin-api', :path => "#{logstash_path}/logstash-core-plugin-api"
|
11
11
|
end
|
12
|
+
|
13
|
+
if RUBY_VERSION == "1.9.3"
|
14
|
+
gem 'rake', '12.2.1'
|
15
|
+
end
|
data/docs/index.asciidoc
CHANGED
@@ -83,6 +83,7 @@ This plugin supports the following configuration options plus the <<plugins-{typ
|
|
83
83
|
| <<plugins-{type}s-{plugin}-port>> |<<number,number>>|Yes
|
84
84
|
| <<plugins-{type}s-{plugin}-proxy_protocol>> |<<boolean,boolean>>|No
|
85
85
|
| <<plugins-{type}s-{plugin}-ssl_cert>> |a valid filesystem path|No
|
86
|
+
| <<plugins-{type}s-{plugin}-ssl_certificate_authorities>> |<<array,array>>|No
|
86
87
|
| <<plugins-{type}s-{plugin}-ssl_enable>> |<<boolean,boolean>>|No
|
87
88
|
| <<plugins-{type}s-{plugin}-ssl_extra_chain_certs>> |<<array,array>>|No
|
88
89
|
| <<plugins-{type}s-{plugin}-ssl_key>> |a valid filesystem path|No
|
@@ -140,7 +141,17 @@ http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt
|
|
140
141
|
* Value type is <<path,path>>
|
141
142
|
* There is no default value for this setting.
|
142
143
|
|
143
|
-
|
144
|
+
Path to certificate in PEM format. This certificate will be presented
|
145
|
+
to the connecting clients.
|
146
|
+
|
147
|
+
[id="plugins-{type}s-{plugin}-ssl_certificate_authorities"]
|
148
|
+
===== `ssl_extra_chain_certs`
|
149
|
+
|
150
|
+
* Value type is <<array,array>>
|
151
|
+
* Default value is `[]`
|
152
|
+
|
153
|
+
Validate client certificate or certificate chain against these authorities.
|
154
|
+
You can define multiple files or paths. All the certificates will be read and added to the trust store.
|
144
155
|
|
145
156
|
[id="plugins-{type}s-{plugin}-ssl_enable"]
|
146
157
|
===== `ssl_enable`
|
@@ -156,8 +167,9 @@ Enable SSL (must be set for other `ssl_` options to take effect).
|
|
156
167
|
* Value type is <<array,array>>
|
157
168
|
* Default value is `[]`
|
158
169
|
|
159
|
-
An Array of extra X509 certificates
|
160
|
-
|
170
|
+
An Array of paths to extra X509 certificates.
|
171
|
+
These are used together with the certificate to construct the certificate chain
|
172
|
+
presented to the client.
|
161
173
|
|
162
174
|
[id="plugins-{type}s-{plugin}-ssl_key"]
|
163
175
|
===== `ssl_key`
|
@@ -165,7 +177,7 @@ Useful when the CA chain is not necessary in the system store.
|
|
165
177
|
* Value type is <<path,path>>
|
166
178
|
* There is no default value for this setting.
|
167
179
|
|
168
|
-
|
180
|
+
The path to the private key corresponding to the specified certificate (PEM format).
|
169
181
|
|
170
182
|
[id="plugins-{type}s-{plugin}-ssl_key_passphrase"]
|
171
183
|
===== `ssl_key_passphrase`
|
@@ -173,7 +185,7 @@ SSL key path
|
|
173
185
|
* Value type is <<password,password>>
|
174
186
|
* Default value is `nil`
|
175
187
|
|
176
|
-
SSL key passphrase
|
188
|
+
SSL key passphrase for the private key.
|
177
189
|
|
178
190
|
[id="plugins-{type}s-{plugin}-ssl_verify"]
|
179
191
|
===== `ssl_verify`
|
data/lib/logstash/inputs/tcp.rb
CHANGED
@@ -6,6 +6,7 @@ require "logstash/inputs/base"
|
|
6
6
|
require "logstash/util/socket_peer"
|
7
7
|
require "logstash-input-tcp_jars"
|
8
8
|
require "logstash/inputs/tcp/decoder_impl"
|
9
|
+
require "logstash/inputs/tcp/compat_ssl_options"
|
9
10
|
|
10
11
|
require "socket"
|
11
12
|
require "openssl"
|
@@ -105,6 +106,9 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
|
|
105
106
|
# Useful when the CA chain is not necessary in the system store.
|
106
107
|
config :ssl_extra_chain_certs, :validate => :array, :default => []
|
107
108
|
|
109
|
+
# Validate client certificates against these authorities. You can define multiple files or paths. All the certificates will be read and added to the trust store.
|
110
|
+
config :ssl_certificate_authorities, :validate => :array, :default => []
|
111
|
+
|
108
112
|
# Instruct the socket to use TCP keep alives. Uses OS defaults for keep alive settings.
|
109
113
|
config :tcp_keep_alive, :validate => :boolean, :default => false
|
110
114
|
|
@@ -143,22 +147,17 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
|
|
143
147
|
|
144
148
|
@logger.info("Starting tcp input listener", :address => "#{@host}:#{@port}", :ssl_enable => "#{@ssl_enable}")
|
145
149
|
if server?
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
end
|
150
|
+
ssl_context = get_ssl_context(SslOptions)
|
151
|
+
|
152
|
+
@loop = InputLoop.new(@host, @port, DecoderImpl.new(@codec, self), @tcp_keep_alive,
|
153
|
+
ssl_context, @logger.to_java(org.apache.logging.log4j.Logger))
|
151
154
|
end
|
152
155
|
end
|
153
156
|
|
154
157
|
def run(output_queue)
|
155
158
|
@output_queue = output_queue
|
156
159
|
if server?
|
157
|
-
|
158
|
-
run_ssl_server
|
159
|
-
else
|
160
|
-
@loop.run
|
161
|
-
end
|
160
|
+
@loop.run
|
162
161
|
else
|
163
162
|
run_client()
|
164
163
|
end
|
@@ -206,30 +205,6 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
|
|
206
205
|
|
207
206
|
private
|
208
207
|
|
209
|
-
RUN_LOOP_ERROR_MESSAGE="TCP input server encountered error"
|
210
|
-
def run_ssl_server()
|
211
|
-
while !stop?
|
212
|
-
begin
|
213
|
-
socket = add_connection_socket(server_socket.accept)
|
214
|
-
# start a new thread for each connection.
|
215
|
-
server_connection_thread(socket)
|
216
|
-
rescue OpenSSL::SSL::SSLError => e
|
217
|
-
# log error, close socket, accept next connection
|
218
|
-
@logger.debug? && @logger.debug("SSL Error", :exception => e, :backtrace => e.backtrace)
|
219
|
-
rescue => e
|
220
|
-
@logger.error(
|
221
|
-
RUN_LOOP_ERROR_MESSAGE,
|
222
|
-
:message => e.message,
|
223
|
-
:class => e.class.name,
|
224
|
-
:backtrace => e.backtrace
|
225
|
-
)
|
226
|
-
end
|
227
|
-
end
|
228
|
-
ensure
|
229
|
-
# catch all rescue nil on close to discard any close errors or invalid socket
|
230
|
-
server_socket.close rescue nil
|
231
|
-
end
|
232
|
-
|
233
208
|
def run_client()
|
234
209
|
while !stop?
|
235
210
|
self.client_socket = new_client_socket
|
@@ -240,17 +215,6 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
|
|
240
215
|
client_socket.close rescue nil
|
241
216
|
end
|
242
217
|
|
243
|
-
def server_connection_thread(socket)
|
244
|
-
Thread.new(socket) do |s|
|
245
|
-
begin
|
246
|
-
@logger.debug? && @logger.debug("Accepted connection", :client => s.peer, :server => "#{@host}:#{@port}")
|
247
|
-
handle_socket(s)
|
248
|
-
ensure
|
249
|
-
delete_connection_socket(s)
|
250
|
-
end
|
251
|
-
end
|
252
|
-
end
|
253
|
-
|
254
218
|
def handle_socket(socket)
|
255
219
|
client_address = socket.peeraddr[3]
|
256
220
|
client_ip_address = socket.peeraddr[2]
|
@@ -317,6 +281,10 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
|
|
317
281
|
@ssl_context = OpenSSL::SSL::SSLContext.new
|
318
282
|
@ssl_context.cert = OpenSSL::X509::Certificate.new(File.read(@ssl_cert))
|
319
283
|
@ssl_context.key = OpenSSL::PKey::RSA.new(File.read(@ssl_key),@ssl_key_passphrase.value)
|
284
|
+
if @ssl_extra_chain_certs.any?
|
285
|
+
@ssl_context.extra_chain_cert = @ssl_extra_chain_certs.map {|cert_path| OpenSSL::X509::Certificate.new(File.read(cert_path)) }
|
286
|
+
@ssl_context.extra_chain_cert.unshift(OpenSSL::X509::Certificate.new(File.read(@ssl_cert)))
|
287
|
+
end
|
320
288
|
if @ssl_verify
|
321
289
|
@ssl_context.cert_store = load_cert_store
|
322
290
|
@ssl_context.verify_mode = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
|
@@ -332,28 +300,12 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
|
|
332
300
|
def load_cert_store
|
333
301
|
cert_store = OpenSSL::X509::Store.new
|
334
302
|
cert_store.set_default_paths
|
335
|
-
@
|
303
|
+
@ssl_certificate_authorities.each do |cert|
|
336
304
|
cert_store.add_file(cert)
|
337
305
|
end
|
338
306
|
cert_store
|
339
307
|
end
|
340
308
|
|
341
|
-
def new_server_socket
|
342
|
-
begin
|
343
|
-
socket = TCPServer.new(@host, @port)
|
344
|
-
socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, @tcp_keep_alive)
|
345
|
-
rescue Errno::EADDRINUSE
|
346
|
-
@logger.error("Could not start TCP server: Address in use", :host => @host, :port => @port)
|
347
|
-
raise
|
348
|
-
end
|
349
|
-
|
350
|
-
if @ssl_enable
|
351
|
-
socket = OpenSSL::SSL::SSLServer.new(socket, ssl_context)
|
352
|
-
socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, @tcp_keep_alive)
|
353
|
-
end
|
354
|
-
socket
|
355
|
-
end
|
356
|
-
|
357
309
|
def new_client_socket
|
358
310
|
socket = TCPSocket.new(@host, @port)
|
359
311
|
socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, @tcp_keep_alive)
|
@@ -409,4 +361,16 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
|
|
409
361
|
def connection_sockets
|
410
362
|
@socket_mutex.synchronize{@connection_sockets.keys.dup}
|
411
363
|
end
|
364
|
+
|
365
|
+
def get_ssl_context(options_class)
|
366
|
+
ssl_context = options_class.builder
|
367
|
+
.set_is_ssl_enabled(@ssl_enable)
|
368
|
+
.set_should_verify(@ssl_verify)
|
369
|
+
.set_ssl_cert(@ssl_cert)
|
370
|
+
.set_ssl_key(@ssl_key)
|
371
|
+
.set_ssl_key_passphrase(@ssl_key_passphrase.value)
|
372
|
+
.set_ssl_extra_chain_certs(@ssl_extra_chain_certs.to_java(:string))
|
373
|
+
.set_ssl_certificate_authorities(@ssl_certificate_authorities.to_java(:string))
|
374
|
+
.build.toSslContext()
|
375
|
+
end
|
412
376
|
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
|
3
|
+
java_import 'io.netty.handler.ssl.ClientAuth'
|
4
|
+
java_import 'io.netty.handler.ssl.SslContextBuilder'
|
5
|
+
java_import 'java.io.FileInputStream'
|
6
|
+
java_import 'java.io.FileReader'
|
7
|
+
java_import 'java.security.cert.CertificateFactory'
|
8
|
+
java_import 'java.security.cert.X509Certificate'
|
9
|
+
java_import 'org.bouncycastle.asn1.pkcs.PrivateKeyInfo'
|
10
|
+
java_import 'org.bouncycastle.openssl.PEMKeyPair'
|
11
|
+
java_import 'org.bouncycastle.openssl.PEMParser'
|
12
|
+
java_import 'org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter'
|
13
|
+
|
14
|
+
# Simulate a normal SslOptions builder:
|
15
|
+
#
|
16
|
+
# ssl_context = SslOptions.builder
|
17
|
+
# .set_is_ssl_enabled(@ssl_enable)
|
18
|
+
# .set_should_verify(@ssl_verify)
|
19
|
+
# .set_ssl_cert(@ssl_cert)
|
20
|
+
# .set_ssl_key(@ssl_key)
|
21
|
+
# .set_ssl_key_passphrase(@ssl_key_passphrase.value)
|
22
|
+
# .set_ssl_extra_chain_certs(@ssl_extra_chain_certs.to_java(:string))
|
23
|
+
# .set_ssl_certificate_authorities(@ssl_certificate_authorities.to_java(:string))
|
24
|
+
# .build.toSslContext()
|
25
|
+
class SslOptions
|
26
|
+
def self.builder
|
27
|
+
new
|
28
|
+
end
|
29
|
+
|
30
|
+
def set_is_ssl_enabled(boolean)
|
31
|
+
@ssl_enabled = boolean
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
def set_should_verify(boolean)
|
36
|
+
@ssl_verify = boolean
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def set_ssl_cert(path)
|
41
|
+
@ssl_cert_path = path
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
def set_ssl_key(path)
|
46
|
+
@ssl_key_path = path
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
def set_ssl_key_passphrase(passphrase)
|
51
|
+
@ssl_key_passphrase = passphrase
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
55
|
+
def set_ssl_extra_chain_certs(certs)
|
56
|
+
@ssl_extra_chain_certs = certs
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
def set_ssl_certificate_authorities(certs)
|
61
|
+
@ssl_certificate_authorities = certs
|
62
|
+
self
|
63
|
+
end
|
64
|
+
|
65
|
+
def build; self; end
|
66
|
+
|
67
|
+
def toSslContext
|
68
|
+
return nil unless @ssl_enabled
|
69
|
+
|
70
|
+
# create certificate object
|
71
|
+
cf = CertificateFactory.getInstance("X.509")
|
72
|
+
cert_chain = []
|
73
|
+
cert_chain << cf.generateCertificate(FileInputStream.new(@ssl_cert_path))
|
74
|
+
|
75
|
+
# convert key from pkcs1 to pkcs8 and get PrivateKey object
|
76
|
+
pem_parser = PEMParser.new(FileReader.new(@ssl_key_path))
|
77
|
+
|
78
|
+
case obj = pem_parser.read_object
|
79
|
+
when PEMKeyPair # likely pkcs#1
|
80
|
+
private_key = JcaPEMKeyConverter.new.get_key_pair(obj).private
|
81
|
+
when PrivateKeyInfo # likely pkcs#8
|
82
|
+
private_key = JcaPEMKeyConverter.new.get_private_key(obj)
|
83
|
+
else
|
84
|
+
raise "Could not recognize 'ssl_key' format. Class: #{obj.class}"
|
85
|
+
end
|
86
|
+
|
87
|
+
@ssl_extra_chain_certs.each do |cert|
|
88
|
+
cert_chain << cf.generateCertificate(FileInputStream.new(cert))
|
89
|
+
end
|
90
|
+
sslContextBuilder = SslContextBuilder.forServer(private_key, @ssl_key_passphrase, cert_chain.to_java(java.security.cert.X509Certificate))
|
91
|
+
|
92
|
+
trust_certs = @ssl_certificate_authorities.map do |cert|
|
93
|
+
cf.generateCertificate(FileInputStream.new(cert))
|
94
|
+
end
|
95
|
+
|
96
|
+
if trust_certs.any?
|
97
|
+
sslContextBuilder.trustManager(trust_certs.to_java(java.security.cert.X509Certificate))
|
98
|
+
end
|
99
|
+
|
100
|
+
sslContextBuilder.clientAuth(@ssl_verify ? ClientAuth::REQUIRE : ClientAuth::NONE)
|
101
|
+
sslContextBuilder.build()
|
102
|
+
end
|
103
|
+
end
|
data/spec/inputs/tcp_spec.rb
CHANGED
@@ -9,6 +9,8 @@ require "stud/task"
|
|
9
9
|
require "flores/pki"
|
10
10
|
require "openssl"
|
11
11
|
|
12
|
+
java_import "io.netty.handler.ssl.util.SelfSignedCertificate"
|
13
|
+
|
12
14
|
require_relative "../spec_helper"
|
13
15
|
|
14
16
|
#Cabin::Channel.get(LogStash).subscribe(STDOUT)
|
@@ -310,13 +312,14 @@ describe LogStash::Inputs::Tcp do
|
|
310
312
|
# - pipelineless_input has been basically copied from the udp input specs, it should be DRYied up
|
311
313
|
# - see if we should miminc the udp input UDPClient helper class instead of directly using TCPSocket
|
312
314
|
|
313
|
-
|
315
|
+
context "LogStash::Inputs::Tcp new specs style" do
|
314
316
|
|
315
317
|
before do
|
316
318
|
srand(RSpec.configuration.seed)
|
317
319
|
end
|
318
320
|
|
319
|
-
|
321
|
+
let(:config) { { "port" => port } }
|
322
|
+
subject { described_class.new(config) }
|
320
323
|
let!(:helper) { TcpHelpers.new }
|
321
324
|
|
322
325
|
after :each do
|
@@ -324,9 +327,62 @@ describe LogStash::Inputs::Tcp do
|
|
324
327
|
end
|
325
328
|
|
326
329
|
describe "#register" do
|
330
|
+
|
327
331
|
it "should register without errors" do
|
328
332
|
expect { subject.register }.to_not raise_error
|
329
333
|
end
|
334
|
+
|
335
|
+
context "when using ssl" do
|
336
|
+
let(:config) do
|
337
|
+
{
|
338
|
+
"host" => "127.0.0.1",
|
339
|
+
"port" => port,
|
340
|
+
"ssl_enable" => true,
|
341
|
+
"ssl_cert" => certificate_file.path,
|
342
|
+
"ssl_key" => key_file.path,
|
343
|
+
"ssl_extra_chain_certs" => certificate_file.path
|
344
|
+
}
|
345
|
+
end
|
346
|
+
|
347
|
+
context "with pkcs#1 keys" do
|
348
|
+
let(:pki) { Flores::PKI.generate }
|
349
|
+
let(:certificate) { pki[0] }
|
350
|
+
let(:key) { pki[1] }
|
351
|
+
let(:certificate_file) { Stud::Temporary.file }
|
352
|
+
let(:key_file) { Stud::Temporary.file }
|
353
|
+
|
354
|
+
before do
|
355
|
+
certificate_file.write(certificate)
|
356
|
+
key_file.write(key)
|
357
|
+
certificate_file.close
|
358
|
+
key_file.close
|
359
|
+
end
|
360
|
+
|
361
|
+
it "should configure ssl manager correctly without errors" do
|
362
|
+
expect { subject.register }.to_not raise_error
|
363
|
+
end
|
364
|
+
|
365
|
+
after do
|
366
|
+
File.unlink(certificate_file.path)
|
367
|
+
File.unlink(key_file.path)
|
368
|
+
end
|
369
|
+
|
370
|
+
end
|
371
|
+
|
372
|
+
context "with pkcs#8 keys" do
|
373
|
+
let(:ssc) { SelfSignedCertificate.new }
|
374
|
+
let(:certificate_file) { ssc.certificate }
|
375
|
+
let(:key_file) { ssc.private_key}
|
376
|
+
|
377
|
+
it "should configure ssl manager correctly without errors" do
|
378
|
+
expect { subject.register }.to_not raise_error
|
379
|
+
end
|
380
|
+
|
381
|
+
after do
|
382
|
+
ssc.delete
|
383
|
+
end
|
384
|
+
end
|
385
|
+
end
|
330
386
|
end
|
331
387
|
|
332
388
|
describe "#receive" do
|
@@ -335,11 +391,9 @@ describe LogStash::Inputs::Tcp do
|
|
335
391
|
end
|
336
392
|
|
337
393
|
context "when ssl_enable is true" do
|
338
|
-
let(:
|
339
|
-
let(:
|
340
|
-
let(:
|
341
|
-
let(:certificate_file) { Stud::Temporary.file }
|
342
|
-
let(:key_file) { Stud::Temporary.file }
|
394
|
+
let(:ssc) { SelfSignedCertificate.new }
|
395
|
+
let(:certificate_file) { ssc.certificate }
|
396
|
+
let(:key_file) { ssc.private_key}
|
343
397
|
let(:queue) { Queue.new }
|
344
398
|
|
345
399
|
let(:config) do
|
@@ -349,35 +403,60 @@ describe LogStash::Inputs::Tcp do
|
|
349
403
|
"ssl_enable" => true,
|
350
404
|
"ssl_cert" => certificate_file.path,
|
351
405
|
"ssl_key" => key_file.path,
|
352
|
-
|
353
|
-
# Trust our self-signed cert.
|
354
|
-
# TODO(sissel): Make this a separate certificate for the client
|
355
|
-
"ssl_extra_chain_certs" => certificate_file.path
|
406
|
+
"ssl_certificate_authorities" => [ certificate_file.path ]
|
356
407
|
}
|
357
408
|
end
|
358
409
|
|
359
|
-
|
410
|
+
let(:input) { subject }
|
411
|
+
before(:each) { input.register }
|
412
|
+
after(:each) { ssc.delete }
|
413
|
+
|
414
|
+
context "when using a certificate chain" do
|
415
|
+
let(:chain_of_certificates) { helper.chain_of_certificates }
|
416
|
+
let(:config) do
|
417
|
+
{
|
418
|
+
"host" => "127.0.0.1",
|
419
|
+
"port" => port,
|
420
|
+
"ssl_enable" => true,
|
421
|
+
"ssl_cert" => chain_of_certificates[:b_cert].path,
|
422
|
+
"ssl_key" => chain_of_certificates[:b_key].path,
|
423
|
+
"ssl_extra_chain_certs" => [ chain_of_certificates[:a_cert].path ],
|
424
|
+
"ssl_certificate_authorities" => [ chain_of_certificates[:root_ca].path ],
|
425
|
+
"ssl_verify" => true
|
426
|
+
}
|
427
|
+
end
|
428
|
+
let(:tcp) { TCPSocket.new("127.0.0.1", port) }
|
429
|
+
let(:sslcontext) do
|
430
|
+
sslcontext = OpenSSL::SSL::SSLContext.new
|
431
|
+
sslcontext.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
432
|
+
sslcontext.ca_file = chain_of_certificates[:root_ca].path
|
433
|
+
sslcontext.cert = OpenSSL::X509::Certificate.new(File.read(chain_of_certificates[:aa_cert].path))
|
434
|
+
sslcontext.key = OpenSSL::PKey::RSA.new(File.read(chain_of_certificates[:aa_key].path))
|
435
|
+
sslcontext
|
436
|
+
end
|
437
|
+
let(:sslsocket) { OpenSSL::SSL::SSLSocket.new(tcp, sslcontext) }
|
438
|
+
let(:input_task) { Stud::Task.new { input.run(queue) } }
|
360
439
|
|
361
|
-
|
362
|
-
|
363
|
-
|
440
|
+
before do
|
441
|
+
input_task
|
442
|
+
end
|
364
443
|
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
444
|
+
it "should be able to connect and write data" do
|
445
|
+
sslsocket.connect
|
446
|
+
sslsocket.write("Hello world\n")
|
447
|
+
tcp.flush
|
448
|
+
sslsocket.close
|
449
|
+
tcp.close
|
450
|
+
result = input_task.thread.join(0.5)
|
451
|
+
expect(result).to be_nil
|
452
|
+
expect(queue.size).to eq(1)
|
453
|
+
end
|
370
454
|
|
371
|
-
after do
|
372
|
-
File.unlink(certificate_file.path)
|
373
|
-
File.unlink(key_file.path)
|
374
455
|
end
|
375
456
|
|
376
457
|
context "with a poorly-behaving client" do
|
377
458
|
let!(:input_task) { Stud::Task.new { input.run(queue) } }
|
378
459
|
|
379
|
-
after { input.close }
|
380
|
-
|
381
460
|
context "that disconnects before doing TLS handshake" do
|
382
461
|
before do
|
383
462
|
client = TCPSocket.new("127.0.0.1", port)
|
@@ -402,29 +481,6 @@ describe LogStash::Inputs::Tcp do
|
|
402
481
|
raise StandardError, "blah"
|
403
482
|
end
|
404
483
|
end
|
405
|
-
|
406
|
-
it "should log the error on accept" do
|
407
|
-
allow(input.logger).to receive(:error).with(any_args)
|
408
|
-
|
409
|
-
stop = Thread.new {
|
410
|
-
sleep 2
|
411
|
-
input.do_stop
|
412
|
-
}
|
413
|
-
expect do
|
414
|
-
input.run(Queue.new)
|
415
|
-
end.not_to raise_error
|
416
|
-
|
417
|
-
expect(input.logger).to have_received(:error).with(
|
418
|
-
::LogStash::Inputs::Tcp::RUN_LOOP_ERROR_MESSAGE,
|
419
|
-
:message => "blah",
|
420
|
-
:class => "StandardError",
|
421
|
-
:backtrace => anything
|
422
|
-
).at_least(:once)
|
423
|
-
|
424
|
-
stop.join
|
425
|
-
# Wait for stop to actually happen
|
426
|
-
sleep 1
|
427
|
-
end
|
428
484
|
end
|
429
485
|
|
430
486
|
context "that sends garbage instead of TLS handshake" do
|
@@ -446,37 +502,6 @@ describe LogStash::Inputs::Tcp do
|
|
446
502
|
expect(result).to be_nil
|
447
503
|
end
|
448
504
|
end
|
449
|
-
|
450
|
-
context "connection was healthy but now has garbage or corruption" do
|
451
|
-
let!(:input_task) { Stud::Task.new { input.run(queue) } }
|
452
|
-
let(:tcp) { TCPSocket.new("127.0.0.1", port) }
|
453
|
-
let(:sslcontext) { OpenSSL::SSL::SSLContext.new }
|
454
|
-
let(:sslsocket) { OpenSSL::SSL::SSLSocket.new(tcp, sslcontext) }
|
455
|
-
let(:max_length) { 1000 }
|
456
|
-
let(:garbage) { Flores::Random.iterations(max_length).collect { Flores::Random.integer(1...255) }.pack("C*") }
|
457
|
-
|
458
|
-
before do
|
459
|
-
sslcontext.cert = certificate
|
460
|
-
sslcontext.key = key
|
461
|
-
sslcontext.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
462
|
-
|
463
|
-
sslsocket.connect
|
464
|
-
sslsocket.write("Hello world\n")
|
465
|
-
|
466
|
-
# Assertion to verify this test is actually sending something.
|
467
|
-
expect(garbage.length).to be > 0
|
468
|
-
tcp.write(garbage)
|
469
|
-
tcp.flush
|
470
|
-
sslsocket.close
|
471
|
-
tcp.close
|
472
|
-
end
|
473
|
-
|
474
|
-
it "should not negatively impact the plugin" do
|
475
|
-
# TODO(sissel): Look for a better way to detect this failure besides a sleep/wait.
|
476
|
-
result = input_task.thread.join(0.5)
|
477
|
-
expect(result).to be_nil
|
478
|
-
end
|
479
|
-
end
|
480
505
|
end
|
481
506
|
|
482
507
|
# TODO(sissel): Spec multiple clients where only one is bad.
|
Binary file
|
data/version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
5.
|
1
|
+
5.2.0
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-input-tcp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.2.0
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Elastic
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-10-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -159,11 +159,12 @@ files:
|
|
159
159
|
- docs/index.asciidoc
|
160
160
|
- lib/logstash-input-tcp_jars.rb
|
161
161
|
- lib/logstash/inputs/tcp.rb
|
162
|
+
- lib/logstash/inputs/tcp/compat_ssl_options.rb
|
162
163
|
- lib/logstash/inputs/tcp/decoder_impl.rb
|
163
164
|
- logstash-input-tcp.gemspec
|
164
165
|
- spec/inputs/tcp_spec.rb
|
165
166
|
- spec/spec_helper.rb
|
166
|
-
- vendor/jar-dependencies/org/logstash/inputs/logstash-input-tcp/5.
|
167
|
+
- vendor/jar-dependencies/org/logstash/inputs/logstash-input-tcp/5.2.0/logstash-input-tcp-5.2.0.jar
|
167
168
|
- version
|
168
169
|
homepage: http://www.elastic.co/guide/en/logstash/current/index.html
|
169
170
|
licenses:
|