logstash-input-tcp 6.0.8-java → 6.2.0-java
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 +18 -0
- data/docs/index.asciidoc +72 -11
- data/lib/logstash/inputs/tcp.rb +53 -27
- data/lib/logstash/inputs/tcp/decoder_impl.rb +12 -9
- data/logstash-input-tcp.gemspec +6 -0
- data/spec/inputs/tcp_spec.rb +134 -116
- data/vendor/jar-dependencies/org/logstash/inputs/logstash-input-tcp/{6.0.8/logstash-input-tcp-6.0.8.jar → 6.2.0/logstash-input-tcp-6.2.0.jar} +0 -0
- data/version +1 -1
- metadata +51 -5
- data/docs/testfile.asciidoc +0 -30
- data/lib/logstash/inputs/tcp/compat_ssl_options.rb +0 -147
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 29b44274cfe25c623273407b63c29125143a6ec704c274732b73e9a3fc39f085
|
4
|
+
data.tar.gz: 4bced499147e26e9f8257d2c7a489a7dae93ec2a1c06faf2b45b3d9af801d222
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d45ef4273d94e4dc3dbcc94749d0e8d907ea96acb20ee4aeff94251a5390bb26b51105fc2f6104e09b885dc195f9fbe94261047035f905884d8306649e8aec49
|
7
|
+
data.tar.gz: f00ff1165183ce006a12541b7836bb3a09496eb4370bca185104ea81c8fc8e2360aae8ed09eeb170ab93ee9e64e7233af9360e4cbb73fc5d9b49adf27d26534b
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
## 6.2.0
|
2
|
+
- Added ECS Compatibility Mode [#165](https://github.com/logstash-plugins/logstash-input-tcp/pull/165)
|
3
|
+
- When operating in an ECS Compatibility mode, metadata about the connection on which we are receiving data is nested in well-named fields under `[@metadata][input][tcp]` instead of at the root level.
|
4
|
+
- Fix: source address is no longer missing when a proxy is present
|
5
|
+
|
6
|
+
## 6.1.1
|
7
|
+
- Changed jar dependencies to reflect newer versions [#179](https://github.com/logstash-plugins/logstash-input-http/pull/179)
|
8
|
+
|
9
|
+
## 6.1.0
|
10
|
+
- Feat: improve SSL error logging/unwrapping [#178](https://github.com/logstash-plugins/logstash-input-tcp/pull/178)
|
11
|
+
- Fix: the plugin will no longer have a side effect of adding the Bouncy-Castle security provider at runtime
|
12
|
+
|
13
|
+
## 6.0.10
|
14
|
+
- bumping dependency commons-io [#174](https://github.com/logstash-plugins/logstash-input-tcp/pull/174)
|
15
|
+
|
16
|
+
## 6.0.9
|
17
|
+
- [DOC] Reorder options alphabetically [#171](https://github.com/logstash-plugins/logstash-input-tcp/pull/171)
|
18
|
+
|
1
19
|
## 6.0.8
|
2
20
|
- [DOC] better description for `tcp_keep_alive` option [#169](https://github.com/logstash-plugins/logstash-input-tcp/pull/169)
|
3
21
|
|
data/docs/index.asciidoc
CHANGED
@@ -70,6 +70,52 @@ event timestamp
|
|
70
70
|
}
|
71
71
|
}
|
72
72
|
|
73
|
+
[id="plugins-{type}s-{plugin}-ecs_metadata"]
|
74
|
+
==== Event Metadata and the Elastic Common Schema (ECS)
|
75
|
+
|
76
|
+
In addition to decoding the events, this input will add metadata about the TCP connection itself to each event.
|
77
|
+
This can be helpful when applications are configured to send events directly to this input's TCP listener without including information about themselves.
|
78
|
+
|
79
|
+
Historically, this metadata was added to a variety of non-standard top-level fields, which had the potential to create confusion and schema conflicts downstream.
|
80
|
+
With ECS compatibility mode, we can ensure a pipeline still has access to this metadata throughout the event's lifecycle without polluting the top-level namespace.
|
81
|
+
|
82
|
+
[cols="3,7,5"]
|
83
|
+
|=======================================================================
|
84
|
+
| Metadata Group | ecs: `v1`, `v8` | ecs: `disabled`
|
85
|
+
|
86
|
+
.3+|Source Metadata from the TCP connection
|
87
|
+
on which events are being received, including
|
88
|
+
the sender's name, ip, and outbound port. l|[@metadata][input][tcp][source][name] l|[host]
|
89
|
+
l|[@metadata][input][tcp][source][ip] l|[@metadata][ip_address]
|
90
|
+
l|[@metadata][input][tcp][source][port] l|[port]
|
91
|
+
|
92
|
+
.2+|Proxy Metadata from a proxied TCP connection.
|
93
|
+
Available when receiving events by proxy and
|
94
|
+
`proxy_protocol => true` l|[@metadata][input][tcp][proxy][ip] l|[proxy_host]
|
95
|
+
l|[@metadata][input][tcp][proxy][port] l|[proxy_port]
|
96
|
+
|
97
|
+
.1+|SSL Subject Metadata from a secured TCP
|
98
|
+
connection. Available when `ssl_enable => true`
|
99
|
+
AND `ssl_verify => true` l|[@metadata][input][tcp][ssl][subject] l|[sslsubject]
|
100
|
+
|=======================================================================
|
101
|
+
|
102
|
+
For example, the Elastic Common Schema reserves the https://www.elastic.co/guide/en/ecs/current/ecs-host.html[top-level `host` field] for information about the host on which the event happened.
|
103
|
+
If an event is missing this metadata, it can be copied into place from the source TCP connection metadata that has been added to the event:
|
104
|
+
|
105
|
+
[source,txt]
|
106
|
+
-----
|
107
|
+
filter {
|
108
|
+
if [@metadata][input][tcp][source] and not [host] {
|
109
|
+
mutate {
|
110
|
+
copy {
|
111
|
+
"[@metadata][input][tcp][source][name]" => "[host][name]"
|
112
|
+
"[@metadata][input][tcp][source][ip]" => "[host][ip]"
|
113
|
+
}
|
114
|
+
}
|
115
|
+
}
|
116
|
+
}
|
117
|
+
-----
|
118
|
+
|
73
119
|
[id="plugins-{type}s-{plugin}-options"]
|
74
120
|
==== Tcp Input Configuration Options
|
75
121
|
|
@@ -78,6 +124,8 @@ This plugin supports the following configuration options plus the <<plugins-{typ
|
|
78
124
|
[cols="<,<,<",options="header",]
|
79
125
|
|=======================================================================
|
80
126
|
|Setting |Input type|Required
|
127
|
+
| <<plugins-{type}s-{plugin}-dns_reverse_lookup_enabled>> |<<boolean,boolean>>|No
|
128
|
+
| <<plugins-{type}s-{plugin}-ecs_compatibility>> | <<string,string>>|No
|
81
129
|
| <<plugins-{type}s-{plugin}-host>> |<<string,string>>|No
|
82
130
|
| <<plugins-{type}s-{plugin}-mode>> |<<string,string>>, one of `["server", "client"]`|No
|
83
131
|
| <<plugins-{type}s-{plugin}-port>> |<<number,number>>|Yes
|
@@ -90,7 +138,6 @@ This plugin supports the following configuration options plus the <<plugins-{typ
|
|
90
138
|
| <<plugins-{type}s-{plugin}-ssl_key_passphrase>> |<<password,password>>|No
|
91
139
|
| <<plugins-{type}s-{plugin}-ssl_verify>> |<<boolean,boolean>>|No
|
92
140
|
| <<plugins-{type}s-{plugin}-tcp_keep_alive>> |<<boolean,boolean>>|No
|
93
|
-
| <<plugins-{type}s-{plugin}-dns_reverse_lookup_enabled>> |<<boolean,boolean>>|No
|
94
141
|
|=======================================================================
|
95
142
|
|
96
143
|
Also see <<plugins-{type}s-{plugin}-common-options>> for a list of options supported by all
|
@@ -98,6 +145,30 @@ input plugins.
|
|
98
145
|
|
99
146
|
|
100
147
|
|
148
|
+
[id="plugins-{type}s-{plugin}-dns_reverse_lookup_enabled"]
|
149
|
+
===== `dns_reverse_lookup_enabled`
|
150
|
+
|
151
|
+
* Value type is <<boolean,boolean>>
|
152
|
+
* Default value is `true`
|
153
|
+
|
154
|
+
It is possible to avoid DNS reverse-lookups by disabling this setting. If disabled,
|
155
|
+
the address metadata that is added to events will contain the source address as-specified
|
156
|
+
at the TCP layer and IPs will not be resolved to hostnames.
|
157
|
+
|
158
|
+
[id="plugins-{type}s-{plugin}-ecs_compatibility"]
|
159
|
+
===== `ecs_compatibility`
|
160
|
+
|
161
|
+
* Value type is <<string,string>>
|
162
|
+
* Supported values are:
|
163
|
+
** `disabled`: unstructured connection metadata added at root level
|
164
|
+
** `v1`,`v8`: structured connection metadata added under `[@metadata][input][tcp]`
|
165
|
+
* Default value depends on which version of Logstash is running:
|
166
|
+
** When Logstash provides a `pipeline.ecs_compatibility` setting, its value is used as the default
|
167
|
+
** Otherwise, the default value is `disabled`.
|
168
|
+
|
169
|
+
Controls this plugin's compatibility with the https://www.elastic.co/guide/en/ecs/current/index.html[Elastic Common Schema (ECS)].
|
170
|
+
The value of this setting affects the <<plugins-{type}s-{plugin}-ecs_metadata,placement of a TCP connection's metadata>> on events.
|
171
|
+
|
101
172
|
[id="plugins-{type}s-{plugin}-host"]
|
102
173
|
===== `host`
|
103
174
|
|
@@ -206,16 +277,6 @@ Instruct the socket to use TCP keep alive. If it's `true` then the underlying so
|
|
206
277
|
will use the OS defaults settings for keep alive. If it's `false` it doesn't configure any
|
207
278
|
keep alive setting for the underlying socket.
|
208
279
|
|
209
|
-
[id="plugins-{type}s-{plugin}-dns_reverse_lookup_enabled"]
|
210
|
-
===== `dns_reverse_lookup_enabled`
|
211
|
-
|
212
|
-
* Value type is <<boolean,boolean>>
|
213
|
-
* Default value is `true`
|
214
|
-
|
215
|
-
It is possible to avoid DNS reverse-lookups by disabling this setting. If disabled,
|
216
|
-
the address metadata that is added to events will contain the source address as-specified
|
217
|
-
at the TCP layer and IPs will not be resolved to hostnames.
|
218
|
-
|
219
280
|
|
220
281
|
[id="plugins-{type}s-{plugin}-common-options"]
|
221
282
|
include::{include_path}/{type}.asciidoc[]
|
data/lib/logstash/inputs/tcp.rb
CHANGED
@@ -5,8 +5,7 @@ require "java"
|
|
5
5
|
require "logstash/inputs/base"
|
6
6
|
require "logstash/util/socket_peer"
|
7
7
|
require "logstash-input-tcp_jars"
|
8
|
-
require
|
9
|
-
require "logstash/inputs/tcp/compat_ssl_options"
|
8
|
+
require 'logstash/plugin_mixins/ecs_compatibility_support'
|
10
9
|
|
11
10
|
require "socket"
|
12
11
|
require "openssl"
|
@@ -61,7 +60,13 @@ require "openssl"
|
|
61
60
|
# }
|
62
61
|
class LogStash::Inputs::Tcp < LogStash::Inputs::Base
|
63
62
|
|
64
|
-
java_import org.logstash.tcp.InputLoop
|
63
|
+
java_import 'org.logstash.tcp.InputLoop'
|
64
|
+
java_import 'org.logstash.tcp.SslContextBuilder'
|
65
|
+
|
66
|
+
require_relative "tcp/decoder_impl"
|
67
|
+
|
68
|
+
# ecs_compatibility option, provided by Logstash core or the support adapter.
|
69
|
+
include LogStash::PluginMixins::ECSCompatibilitySupport(:disabled, :v1, :v8 => :v1)
|
65
70
|
|
66
71
|
config_name "tcp"
|
67
72
|
|
@@ -103,7 +108,8 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
|
|
103
108
|
# Useful when the CA chain is not necessary in the system store.
|
104
109
|
config :ssl_extra_chain_certs, :validate => :array, :default => []
|
105
110
|
|
106
|
-
# Validate client certificates against these authorities. You can define multiple files or paths.
|
111
|
+
# Validate client certificates against these authorities. You can define multiple files or paths.
|
112
|
+
# All the certificates will be read and added to the trust store.
|
107
113
|
config :ssl_certificate_authorities, :validate => :array, :default => []
|
108
114
|
|
109
115
|
# Instruct the socket to use TCP keep alives. Uses OS defaults for keep alive settings.
|
@@ -112,13 +118,6 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
|
|
112
118
|
# Option to allow users to avoid DNS Reverse Lookup.
|
113
119
|
config :dns_reverse_lookup_enabled, :validate => :boolean, :default => true
|
114
120
|
|
115
|
-
HOST_FIELD = "host".freeze
|
116
|
-
HOST_IP_FIELD = "[@metadata][ip_address]".freeze
|
117
|
-
PORT_FIELD = "port".freeze
|
118
|
-
PROXY_HOST_FIELD = "proxy_host".freeze
|
119
|
-
PROXY_PORT_FIELD = "proxy_port".freeze
|
120
|
-
SSLSUBJECT_FIELD = "sslsubject".freeze
|
121
|
-
|
122
121
|
# Monkey patch TCPSocket and SSLSocket to include socket peer
|
123
122
|
# @private
|
124
123
|
def self.patch_socket_peer!
|
@@ -133,6 +132,8 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
|
|
133
132
|
def initialize(*args)
|
134
133
|
super(*args)
|
135
134
|
|
135
|
+
setup_fields!
|
136
|
+
|
136
137
|
self.class.patch_socket_peer!
|
137
138
|
|
138
139
|
# threadsafe socket bookkeeping
|
@@ -148,10 +149,7 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
|
|
148
149
|
fix_streaming_codecs
|
149
150
|
|
150
151
|
if server?
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
@loop = InputLoop.new(@host, @port, DecoderImpl.new(@codec, self), @tcp_keep_alive, ssl_context)
|
152
|
+
@loop = InputLoop.new(@host, @port, DecoderImpl.new(@codec, self), @tcp_keep_alive, java_ssl_context)
|
155
153
|
end
|
156
154
|
end
|
157
155
|
|
@@ -188,8 +186,8 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
|
|
188
186
|
proxy_port, tbuf, socket)
|
189
187
|
codec.decode(tbuf) do |event|
|
190
188
|
if @proxy_protocol
|
191
|
-
event.set(
|
192
|
-
event.set(
|
189
|
+
event.set(@field_proxy_host, proxy_address) unless event.get(@field_proxy_host)
|
190
|
+
event.set(@field_proxy_port, proxy_port) unless event.get(@field_proxy_port)
|
193
191
|
end
|
194
192
|
enqueue_decorated(event, client_ip_address, client_address, client_port, socket)
|
195
193
|
end
|
@@ -262,14 +260,24 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
|
|
262
260
|
end
|
263
261
|
|
264
262
|
def enqueue_decorated(event, client_ip_address, client_address, client_port, socket)
|
265
|
-
event.set(
|
266
|
-
event.set(
|
267
|
-
event.set(
|
268
|
-
event.set(
|
263
|
+
event.set(@field_host, client_address) unless event.get(@field_host)
|
264
|
+
event.set(@field_host_ip, client_ip_address) unless event.get(@field_host_ip)
|
265
|
+
event.set(@field_port, client_port) unless event.get(@field_port)
|
266
|
+
event.set(@field_sslsubject, socket.peer_cert.subject.to_s) if socket && @ssl_enable && @ssl_verify && event.get(@field_sslsubject).nil?
|
269
267
|
decorate(event)
|
270
268
|
@output_queue << event
|
271
269
|
end
|
272
270
|
|
271
|
+
# setup the field names, with respect to ECS compatibility.
|
272
|
+
def setup_fields!
|
273
|
+
@field_host = ecs_select[disabled: "host", v1: "[@metadata][input][tcp][source][name]" ].freeze
|
274
|
+
@field_host_ip = ecs_select[disabled: "[@metadata][ip_address]", v1: "[@metadata][input][tcp][source][ip]" ].freeze
|
275
|
+
@field_port = ecs_select[disabled: "port", v1: "[@metadata][input][tcp][source][port]" ].freeze
|
276
|
+
@field_proxy_host = ecs_select[disabled: "proxy_host", v1: "[@metadata][input][tcp][proxy][ip]" ].freeze
|
277
|
+
@field_proxy_port = ecs_select[disabled: "proxy_port", v1: "[@metadata][input][tcp][proxy][port]" ].freeze
|
278
|
+
@field_sslsubject = ecs_select[disabled: "sslsubject", v1: "[@metadata][input][tcp][tls][client][subject]"].freeze
|
279
|
+
end
|
280
|
+
|
273
281
|
def server?
|
274
282
|
@mode == "server"
|
275
283
|
end
|
@@ -320,7 +328,7 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
|
|
320
328
|
|
321
329
|
socket
|
322
330
|
rescue OpenSSL::SSL::SSLError => e
|
323
|
-
@logger.error("SSL Error", :exception => e, :backtrace => e.backtrace)
|
331
|
+
@logger.error("SSL Error", :message => e.message, :exception => e.class, :backtrace => e.backtrace)
|
324
332
|
# catch all rescue nil on close to discard any close errors or invalid socket
|
325
333
|
socket.close rescue nil
|
326
334
|
sleep(1) # prevent hammering peer
|
@@ -362,15 +370,33 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
|
|
362
370
|
@socket_mutex.synchronize{@connection_sockets.keys.dup}
|
363
371
|
end
|
364
372
|
|
365
|
-
def
|
366
|
-
|
367
|
-
.
|
373
|
+
def java_ssl_context
|
374
|
+
SslContextBuilder.new
|
375
|
+
.set_ssl_enabled(@ssl_enable)
|
368
376
|
.set_should_verify(@ssl_verify)
|
369
377
|
.set_ssl_cert(@ssl_cert)
|
370
378
|
.set_ssl_key(@ssl_key)
|
371
|
-
.
|
379
|
+
.set_ssl_key_password(@ssl_key_passphrase.value)
|
372
380
|
.set_ssl_extra_chain_certs(@ssl_extra_chain_certs.to_java(:string))
|
373
381
|
.set_ssl_certificate_authorities(@ssl_certificate_authorities.to_java(:string))
|
374
|
-
.
|
382
|
+
.build_context
|
383
|
+
rescue java.lang.IllegalArgumentException => e
|
384
|
+
@logger.error("SSL configuration invalid", error_details(e))
|
385
|
+
raise LogStash::ConfigurationError, e
|
386
|
+
rescue java.lang.Exception => e
|
387
|
+
@logger.error("SSL configuration failed", error_details(e, true))
|
388
|
+
raise e
|
389
|
+
end
|
390
|
+
|
391
|
+
def error_details(e, trace = false)
|
392
|
+
error_details = { :exception => e.class, :message => e.message }
|
393
|
+
error_details[:backtrace] = e.backtrace if trace || @logger.debug?
|
394
|
+
cause = e.cause
|
395
|
+
if cause && e != cause
|
396
|
+
error_details[:cause] = { :exception => cause.class, :message => cause.message }
|
397
|
+
error_details[:cause][:backtrace] = cause.backtrace if trace || @logger.debug?
|
398
|
+
end
|
399
|
+
error_details
|
375
400
|
end
|
401
|
+
|
376
402
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require 'java'
|
3
3
|
|
4
|
-
class DecoderImpl
|
4
|
+
class LogStash::Inputs::Tcp::DecoderImpl
|
5
5
|
|
6
6
|
include org.logstash.tcp.Decoder
|
7
7
|
|
@@ -24,7 +24,7 @@ class DecoderImpl
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def copy
|
27
|
-
|
27
|
+
self.class.new(@codec.clone, @tcp)
|
28
28
|
end
|
29
29
|
|
30
30
|
def flush
|
@@ -41,16 +41,17 @@ class DecoderImpl
|
|
41
41
|
@tcp.logger.error("Invalid proxy protocol header label", :header => pp_hdr)
|
42
42
|
raise IOError.new("Invalid proxy protocol header label #{pp_hdr.inspect}")
|
43
43
|
else
|
44
|
-
@proxy_address = pp_info[3]
|
45
|
-
@proxy_port = pp_info[5]
|
46
|
-
@
|
47
|
-
@
|
44
|
+
@proxy_address = pp_info[3] # layer 3 destination address (proxy's receiving address)
|
45
|
+
@proxy_port = pp_info[5] # TCP destination port (proxy's receiving port)
|
46
|
+
@ip_address = pp_info[2] # layer 3 source address (outgoing ip of sender)
|
47
|
+
@address = extract_host_name(@ip_address)
|
48
|
+
@port = pp_info[4] # TCP source port (outgoing port on sender [probably random])
|
48
49
|
end
|
49
50
|
else
|
50
51
|
filtered = received
|
51
|
-
@ip_address = channel_addr.get_address.get_host_address
|
52
|
-
@address = extract_host_name(channel_addr)
|
53
|
-
@port = channel_addr.get_port
|
52
|
+
@ip_address = channel_addr.get_address.get_host_address # ip address of sender
|
53
|
+
@address = extract_host_name(channel_addr) # name _or_ address of sender
|
54
|
+
@port = channel_addr.get_port # outgoing port of sender (probably random)
|
54
55
|
end
|
55
56
|
@first_read = false
|
56
57
|
filtered
|
@@ -58,6 +59,8 @@ class DecoderImpl
|
|
58
59
|
|
59
60
|
private
|
60
61
|
def extract_host_name(channel_addr)
|
62
|
+
channel_addr = java.net.InetSocketAddress.new(channel_addr, 0) if channel_addr.kind_of?(String)
|
63
|
+
|
61
64
|
return channel_addr.get_host_string unless @tcp.dns_reverse_lookup_enabled?
|
62
65
|
|
63
66
|
channel_addr.get_host_name
|
data/logstash-input-tcp.gemspec
CHANGED
@@ -21,6 +21,12 @@ Gem::Specification.new do |s|
|
|
21
21
|
|
22
22
|
# Gem dependencies
|
23
23
|
s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
|
24
|
+
s.add_runtime_dependency 'logstash-mixin-ecs_compatibility_support', '~>1.2'
|
25
|
+
|
26
|
+
s.add_runtime_dependency 'logstash-core', '>= 6.7.0'
|
27
|
+
|
28
|
+
# we depend on bouncycastle's bcpkix-jdk15on being on the class-path
|
29
|
+
s.add_runtime_dependency 'jruby-openssl', '>= 0.10.2', '< 0.12'
|
24
30
|
|
25
31
|
# line vs streaming codecs required for fix_streaming_codecs
|
26
32
|
# TODO: fix_streaming_codecs should be refactored to not
|
data/spec/inputs/tcp_spec.rb
CHANGED
@@ -15,9 +15,11 @@ java_import "io.netty.handler.ssl.util.SelfSignedCertificate"
|
|
15
15
|
|
16
16
|
require_relative "../spec_helper"
|
17
17
|
|
18
|
+
require 'logstash/plugin_mixins/ecs_compatibility_support/spec_helper'
|
19
|
+
|
18
20
|
#Cabin::Channel.get(LogStash).subscribe(STDOUT)
|
19
21
|
#Cabin::Channel.get(LogStash).level = :debug
|
20
|
-
describe LogStash::Inputs::Tcp do
|
22
|
+
describe LogStash::Inputs::Tcp, :ecs_compatibility_support do
|
21
23
|
|
22
24
|
def get_port
|
23
25
|
begin
|
@@ -52,160 +54,176 @@ describe LogStash::Inputs::Tcp do
|
|
52
54
|
end
|
53
55
|
end
|
54
56
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
57
|
+
ecs_compatibility_matrix(:disabled,:v1, :v8 => :v1) do |ecs_select|
|
58
|
+
before(:each) do
|
59
|
+
allow_any_instance_of(described_class).to receive(:ecs_compatibility).and_return(ecs_compatibility)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should read plain with unicode" do
|
63
|
+
event_count = 10
|
64
|
+
conf = <<-CONFIG
|
65
|
+
input {
|
66
|
+
tcp {
|
67
|
+
port => #{port}
|
68
|
+
}
|
61
69
|
}
|
62
|
-
|
63
|
-
|
70
|
+
CONFIG
|
71
|
+
|
72
|
+
host = 'localhost'
|
73
|
+
events = input(conf) do |pipeline, queue|
|
74
|
+
socket = Stud::try(5.times) { TCPSocket.new(host, port) }
|
75
|
+
event_count.times do |i|
|
76
|
+
# unicode smiley for testing unicode support!
|
77
|
+
socket.puts("#{i} ☹")
|
78
|
+
socket.flush
|
79
|
+
end
|
80
|
+
socket.close
|
64
81
|
|
65
|
-
|
66
|
-
events = input(conf) do |pipeline, queue|
|
67
|
-
socket = Stud::try(5.times) { TCPSocket.new(host, port) }
|
68
|
-
event_count.times do |i|
|
69
|
-
# unicode smiley for testing unicode support!
|
70
|
-
socket.puts("#{i} ☹")
|
71
|
-
socket.flush
|
82
|
+
event_count.times.collect {queue.pop}
|
72
83
|
end
|
73
|
-
socket.close
|
74
84
|
|
75
|
-
|
76
|
-
|
85
|
+
expect(events.length).to eq(event_count)
|
86
|
+
events = events.sort_by {|e| e.get("message")} # the ordering of events in the queue is highly timing-dependent
|
87
|
+
event_count.times do |i|
|
88
|
+
event = events[i]
|
77
89
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
insist { event.get("[@metadata][ip_address]") } == '127.0.0.1'
|
90
|
+
aggregate_failures("event #{i}") do
|
91
|
+
expect(event.get("message")).to eq("#{i} ☹")
|
92
|
+
expect(event.get(ecs_select[disabled: "host", v1: "[@metadata][input][tcp][source][name]"])).to eq("localhost").or eq("ip6-localhost")
|
93
|
+
expect(event.get(ecs_select[disabled: "[@metadata][ip_address]", v1: "[@metadata][input][tcp][source][ip]"])).to eq('127.0.0.1')
|
94
|
+
end
|
95
|
+
end
|
85
96
|
end
|
86
|
-
end
|
87
97
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
98
|
+
it "should handle PROXY protocol v1 connections" do
|
99
|
+
event_count = 10
|
100
|
+
conf = <<-CONFIG
|
101
|
+
input {
|
102
|
+
tcp {
|
103
|
+
proxy_protocol => true
|
104
|
+
port => '#{port}'
|
105
|
+
}
|
95
106
|
}
|
96
|
-
|
97
|
-
CONFIG
|
107
|
+
CONFIG
|
98
108
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
socket.flush
|
103
|
-
event_count.times do |i|
|
104
|
-
# unicode smiley for testing unicode support!
|
105
|
-
socket.puts("#{i} ☹")
|
109
|
+
events = input(conf) do |pipeline, queue|
|
110
|
+
socket = Stud::try(5.times) { TCPSocket.new("127.0.0.1", port) }
|
111
|
+
socket.puts("PROXY TCP4 1.2.3.4 5.6.7.8 1234 5678\r");
|
106
112
|
socket.flush
|
107
|
-
|
108
|
-
|
113
|
+
event_count.times do |i|
|
114
|
+
# unicode smiley for testing unicode support!
|
115
|
+
socket.puts("#{i} ☹")
|
116
|
+
socket.flush
|
117
|
+
end
|
118
|
+
socket.close
|
109
119
|
|
110
|
-
|
111
|
-
|
120
|
+
event_count.times.collect {queue.pop}
|
121
|
+
end
|
112
122
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
123
|
+
expect(events.length).to eq(event_count)
|
124
|
+
events = events.sort_by {|e| e.get("message")} # the ordering of events in the queue is highly timing-dependent
|
125
|
+
events.each_with_index do |event, i|
|
126
|
+
aggregate_failures("event #{i}") do
|
127
|
+
expect(event.get("message")).to eq("#{i} ☹")
|
128
|
+
expect(event.get(ecs_select[disabled: "host", v1: "[@metadata][input][tcp][source][name]"])).to eq('1.2.3.4')
|
129
|
+
expect(event.get(ecs_select[disabled: "[@metadata][ip_address]", v1: "[@metadata][input][tcp][source][ip]" ])).to eq('1.2.3.4')
|
130
|
+
expect(event.get(ecs_select[disabled: "port", v1: "[@metadata][input][tcp][source][port]"])).to eq('1234')
|
131
|
+
expect(event.get(ecs_select[disabled: "proxy_host", v1: "[@metadata][input][tcp][proxy][ip]" ])).to eq('5.6.7.8')
|
132
|
+
expect(event.get(ecs_select[disabled: "proxy_port", v1: "[@metadata][input][tcp][proxy][port]" ])).to eq('5678')
|
133
|
+
end
|
134
|
+
end
|
121
135
|
end
|
122
|
-
end
|
123
136
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
137
|
+
it "should read events with json codec" do
|
138
|
+
conf = <<-CONFIG
|
139
|
+
input {
|
140
|
+
tcp {
|
141
|
+
port => #{port}
|
142
|
+
codec => json
|
143
|
+
}
|
131
144
|
}
|
145
|
+
CONFIG
|
146
|
+
|
147
|
+
data = {
|
148
|
+
"hello" => "world",
|
149
|
+
"foo" => [1,2,3],
|
150
|
+
"baz" => { "1" => "2" },
|
151
|
+
"host" => "example host"
|
132
152
|
}
|
133
|
-
CONFIG
|
134
153
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
socket.puts(text)
|
140
|
-
socket.close
|
154
|
+
event = input(conf) do |pipeline, queue|
|
155
|
+
socket = Stud::try(5.times) { TCPSocket.new("127.0.0.1", port) }
|
156
|
+
socket.puts(LogStash::Json.dump(data))
|
157
|
+
socket.close
|
141
158
|
|
142
|
-
|
143
|
-
|
159
|
+
queue.pop
|
160
|
+
end
|
144
161
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
insist { event.get("message") } == "£"
|
149
|
-
end
|
162
|
+
insist { event.get("hello") } == data["hello"]
|
163
|
+
insist { event.get("foo").to_a } == data["foo"] # to_a to cast Java ArrayList produced by JrJackson
|
164
|
+
insist { event.get("baz") } == data["baz"]
|
150
165
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
166
|
+
# Make sure the tcp input, w/ json codec, uses the event's 'host' value,
|
167
|
+
# if present, instead of providing its own
|
168
|
+
insist { event.get("host") } == data["host"]
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should read events with json codec (testing 'host' handling)" do
|
172
|
+
conf = <<-CONFIG
|
173
|
+
input {
|
174
|
+
tcp {
|
175
|
+
port => #{port}
|
176
|
+
codec => json
|
177
|
+
}
|
157
178
|
}
|
179
|
+
CONFIG
|
180
|
+
|
181
|
+
data = {
|
182
|
+
"hello" => "world"
|
158
183
|
}
|
159
|
-
CONFIG
|
160
184
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
"host" => "example host"
|
166
|
-
}
|
185
|
+
event = input(conf) do |pipeline, queue|
|
186
|
+
socket = Stud::try(5.times) { TCPSocket.new("127.0.0.1", port) }
|
187
|
+
socket.puts(LogStash::Json.dump(data))
|
188
|
+
socket.close
|
167
189
|
|
168
|
-
|
169
|
-
|
170
|
-
socket.puts(LogStash::Json.dump(data))
|
171
|
-
socket.close
|
190
|
+
queue.pop
|
191
|
+
end
|
172
192
|
|
173
|
-
|
193
|
+
aggregate_failures("event") do
|
194
|
+
expect(event.get("hello")).to eq(data["hello"])
|
195
|
+
expect(event).to include(ecs_select[disabled: "host", v1: "[@metadata][input][tcp][source][name]"])
|
196
|
+
expect(event).to include(ecs_select[disabled: "[@metadata][ip_address]", v1: "[@metadata][input][tcp][source][ip]" ])
|
197
|
+
end
|
174
198
|
end
|
175
|
-
|
176
|
-
insist { event.get("hello") } == data["hello"]
|
177
|
-
insist { event.get("foo").to_a } == data["foo"] # to_a to cast Java ArrayList produced by JrJackson
|
178
|
-
insist { event.get("baz") } == data["baz"]
|
179
|
-
|
180
|
-
# Make sure the tcp input, w/ json codec, uses the event's 'host' value,
|
181
|
-
# if present, instead of providing its own
|
182
|
-
insist { event.get("host") } == data["host"]
|
183
199
|
end
|
184
200
|
|
185
|
-
it "should read events with
|
201
|
+
it "should read events with plain codec and ISO-8859-1 charset" do
|
202
|
+
charset = "ISO-8859-1"
|
186
203
|
conf = <<-CONFIG
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
204
|
+
input {
|
205
|
+
tcp {
|
206
|
+
port => #{port}
|
207
|
+
codec => plain { charset => "#{charset}" }
|
208
|
+
}
|
191
209
|
}
|
192
|
-
}
|
193
210
|
CONFIG
|
194
211
|
|
195
|
-
data = {
|
196
|
-
"hello" => "world"
|
197
|
-
}
|
198
|
-
|
199
212
|
event = input(conf) do |pipeline, queue|
|
200
213
|
socket = Stud::try(5.times) { TCPSocket.new("127.0.0.1", port) }
|
201
|
-
|
214
|
+
text = "\xA3" # the £ symbol in ISO-8859-1 aka Latin-1
|
215
|
+
text.force_encoding("ISO-8859-1")
|
216
|
+
socket.puts(text)
|
202
217
|
socket.close
|
203
218
|
|
204
219
|
queue.pop
|
205
220
|
end
|
206
221
|
|
207
|
-
|
208
|
-
|
222
|
+
# Make sure the 0xA3 latin-1 code converts correctly to UTF-8.
|
223
|
+
aggregate_failures("event") do
|
224
|
+
expect(event.get("message")).to have_attributes(size: 1, bytesize: 2, encoding: Encoding.find("UTF-8"))
|
225
|
+
expect(event.get("message")).to eq("£")
|
226
|
+
end
|
209
227
|
end
|
210
228
|
|
211
229
|
it "should read events with json_lines codec" do
|
Binary file
|
data/version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
6.0
|
1
|
+
6.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: 6.0
|
4
|
+
version: 6.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: 2021-
|
11
|
+
date: 2021-06-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -30,6 +30,54 @@ dependencies:
|
|
30
30
|
- - "<="
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: '2.99'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
35
|
+
requirements:
|
36
|
+
- - "~>"
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '1.2'
|
39
|
+
name: logstash-mixin-ecs_compatibility_support
|
40
|
+
prerelease: false
|
41
|
+
type: :runtime
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.2'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 6.7.0
|
53
|
+
name: logstash-core
|
54
|
+
prerelease: false
|
55
|
+
type: :runtime
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 6.7.0
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
requirement: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 0.10.2
|
67
|
+
- - "<"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0.12'
|
70
|
+
name: jruby-openssl
|
71
|
+
prerelease: false
|
72
|
+
type: :runtime
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 0.10.2
|
78
|
+
- - "<"
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0.12'
|
33
81
|
- !ruby/object:Gem::Dependency
|
34
82
|
requirement: !ruby/object:Gem::Requirement
|
35
83
|
requirements:
|
@@ -171,15 +219,13 @@ files:
|
|
171
219
|
- NOTICE.TXT
|
172
220
|
- README.md
|
173
221
|
- docs/index.asciidoc
|
174
|
-
- docs/testfile.asciidoc
|
175
222
|
- lib/logstash-input-tcp_jars.rb
|
176
223
|
- lib/logstash/inputs/tcp.rb
|
177
|
-
- lib/logstash/inputs/tcp/compat_ssl_options.rb
|
178
224
|
- lib/logstash/inputs/tcp/decoder_impl.rb
|
179
225
|
- logstash-input-tcp.gemspec
|
180
226
|
- spec/inputs/tcp_spec.rb
|
181
227
|
- spec/spec_helper.rb
|
182
|
-
- vendor/jar-dependencies/org/logstash/inputs/logstash-input-tcp/6.0
|
228
|
+
- vendor/jar-dependencies/org/logstash/inputs/logstash-input-tcp/6.2.0/logstash-input-tcp-6.2.0.jar
|
183
229
|
- version
|
184
230
|
homepage: http://www.elastic.co/guide/en/logstash/current/index.html
|
185
231
|
licenses:
|
data/docs/testfile.asciidoc
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
:plugin: tcp-test
|
2
|
-
:type: input
|
3
|
-
:default_codec: line
|
4
|
-
|
5
|
-
///////////////////////////////////////////
|
6
|
-
START - GENERATED VARIABLES, DO NOT EDIT!
|
7
|
-
///////////////////////////////////////////
|
8
|
-
:version: %VERSION%
|
9
|
-
:release_date: %RELEASE_DATE%
|
10
|
-
:changelog_url: %CHANGELOG_URL%
|
11
|
-
:include_path: ../../../../logstash/docs/include
|
12
|
-
///////////////////////////////////////////
|
13
|
-
END - GENERATED VARIABLES, DO NOT EDIT!
|
14
|
-
///////////////////////////////////////////
|
15
|
-
|
16
|
-
[id="plugins-{type}s-{plugin}"]
|
17
|
-
|
18
|
-
=== Tcp-test input plugin
|
19
|
-
|
20
|
-
include::{include_path}/plugin_header.asciidoc[]
|
21
|
-
|
22
|
-
==== Description
|
23
|
-
|
24
|
-
This is only a test.
|
25
|
-
|
26
|
-
|
27
|
-
[id="plugins-{type}s-{plugin}-common-options"]
|
28
|
-
include::{include_path}/{type}.asciidoc[]
|
29
|
-
|
30
|
-
:default_codec!:
|
@@ -1,147 +0,0 @@
|
|
1
|
-
require 'openssl'
|
2
|
-
require "logstash/util/loggable"
|
3
|
-
|
4
|
-
# Simulate a normal SslOptions builder:
|
5
|
-
#
|
6
|
-
# ssl_context = SslOptions.builder
|
7
|
-
# .set_is_ssl_enabled(@ssl_enable)
|
8
|
-
# .set_should_verify(@ssl_verify)
|
9
|
-
# .set_ssl_cert(@ssl_cert)
|
10
|
-
# .set_ssl_key(@ssl_key)
|
11
|
-
# .set_ssl_key_passphrase(@ssl_key_passphrase.value)
|
12
|
-
# .set_ssl_extra_chain_certs(@ssl_extra_chain_certs.to_java(:string))
|
13
|
-
# .set_ssl_certificate_authorities(@ssl_certificate_authorities.to_java(:string))
|
14
|
-
# .build.toSslContext()
|
15
|
-
class SslOptions
|
16
|
-
include LogStash::Util::Loggable
|
17
|
-
|
18
|
-
java_import 'io.netty.handler.ssl.ClientAuth'
|
19
|
-
java_import 'io.netty.handler.ssl.SslContextBuilder'
|
20
|
-
java_import 'java.security.cert.X509Certificate'
|
21
|
-
java_import 'javax.crypto.Cipher'
|
22
|
-
java_import 'org.bouncycastle.asn1.pkcs.PrivateKeyInfo'
|
23
|
-
java_import 'org.bouncycastle.jce.provider.BouncyCastleProvider'
|
24
|
-
java_import 'org.bouncycastle.openssl.PEMKeyPair'
|
25
|
-
java_import 'org.bouncycastle.openssl.PEMParser'
|
26
|
-
java_import 'org.bouncycastle.openssl.PEMEncryptedKeyPair'
|
27
|
-
java_import 'org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter'
|
28
|
-
java_import 'org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder'
|
29
|
-
java_import 'org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder'
|
30
|
-
java_import 'org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo'
|
31
|
-
|
32
|
-
def self.builder
|
33
|
-
new
|
34
|
-
end
|
35
|
-
|
36
|
-
def set_is_ssl_enabled(boolean)
|
37
|
-
@ssl_enabled = boolean
|
38
|
-
self
|
39
|
-
end
|
40
|
-
|
41
|
-
def set_should_verify(boolean)
|
42
|
-
@ssl_verify = boolean
|
43
|
-
self
|
44
|
-
end
|
45
|
-
|
46
|
-
def set_ssl_cert(path)
|
47
|
-
@ssl_cert_path = path
|
48
|
-
self
|
49
|
-
end
|
50
|
-
|
51
|
-
def set_ssl_key(path)
|
52
|
-
@ssl_key_path = path
|
53
|
-
self
|
54
|
-
end
|
55
|
-
|
56
|
-
def set_ssl_key_passphrase(passphrase)
|
57
|
-
@ssl_key_passphrase = passphrase
|
58
|
-
self
|
59
|
-
end
|
60
|
-
|
61
|
-
def set_ssl_extra_chain_certs(certs)
|
62
|
-
@ssl_extra_chain_certs = certs
|
63
|
-
self
|
64
|
-
end
|
65
|
-
|
66
|
-
def set_ssl_certificate_authorities(certs)
|
67
|
-
@ssl_certificate_authorities = certs
|
68
|
-
self
|
69
|
-
end
|
70
|
-
|
71
|
-
def build; self; end
|
72
|
-
|
73
|
-
def toSslContext
|
74
|
-
return nil unless @ssl_enabled
|
75
|
-
|
76
|
-
# Check key strength
|
77
|
-
logger.warn("JCE Unlimited Strength Jurisdiction Policy not installed - max key length is 128 bits") unless Cipher.getMaxAllowedKeyLength("AES") > 128
|
78
|
-
# create certificate object
|
79
|
-
cf = java.security.cert.CertificateFactory.getInstance("X.509")
|
80
|
-
cert_chain = []
|
81
|
-
fetch_certificates_from_file(@ssl_cert_path, cf) do |cert|
|
82
|
-
cert_chain << cert
|
83
|
-
end
|
84
|
-
|
85
|
-
# convert key from pkcs1 to pkcs8 and get PrivateKey object
|
86
|
-
pem_parser = PEMParser.new(java.io.FileReader.new(@ssl_key_path))
|
87
|
-
java.security.Security.addProvider(BouncyCastleProvider.new)
|
88
|
-
converter = JcaPEMKeyConverter.new
|
89
|
-
case obj = pem_parser.readObject
|
90
|
-
when PEMKeyPair # unencrypted pkcs#1
|
91
|
-
private_key = converter.getKeyPair(obj).private
|
92
|
-
when PrivateKeyInfo # unencrypted pkcs#8
|
93
|
-
private_key = converter.getPrivateKey(obj)
|
94
|
-
when PEMEncryptedKeyPair # encrypted pkcs#1
|
95
|
-
key_char_array = @ssl_key_passphrase.to_java.toCharArray
|
96
|
-
decryptor = JcePEMDecryptorProviderBuilder.new.build(key_char_array)
|
97
|
-
key_pair = obj.decryptKeyPair(decryptor)
|
98
|
-
private_key = converter.getKeyPair(key_pair).private
|
99
|
-
when PKCS8EncryptedPrivateKeyInfo # encrypted pkcs#8
|
100
|
-
key_char_array = @ssl_key_passphrase.to_java.toCharArray
|
101
|
-
key = JceOpenSSLPKCS8DecryptorProviderBuilder.new.build(key_char_array)
|
102
|
-
private_key = converter.getPrivateKey(obj.decryptPrivateKeyInfo(key))
|
103
|
-
else
|
104
|
-
raise "Could not recognize 'ssl_key' format. Class: #{obj.class}"
|
105
|
-
end
|
106
|
-
|
107
|
-
@ssl_extra_chain_certs.each do |file|
|
108
|
-
fetch_certificates_from_file(file, cf) do |cert|
|
109
|
-
cert_chain << cert
|
110
|
-
end
|
111
|
-
end
|
112
|
-
sslContextBuilder = SslContextBuilder.forServer(private_key, @ssl_key_passphrase, cert_chain.to_java(X509Certificate))
|
113
|
-
|
114
|
-
trust_certs = []
|
115
|
-
|
116
|
-
@ssl_certificate_authorities.each do |file|
|
117
|
-
fetch_certificates_from_file(file, cf) do |cert|
|
118
|
-
trust_certs << cert
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
if trust_certs.any?
|
123
|
-
sslContextBuilder.trustManager(trust_certs.to_java(X509Certificate))
|
124
|
-
end
|
125
|
-
|
126
|
-
sslContextBuilder.clientAuth(@ssl_verify ? ClientAuth::REQUIRE : ClientAuth::NONE)
|
127
|
-
sslContextBuilder.build()
|
128
|
-
end
|
129
|
-
|
130
|
-
private
|
131
|
-
def fetch_certificates_from_file(file, cf)
|
132
|
-
fis = java.io.FileInputStream.new(file)
|
133
|
-
|
134
|
-
while (fis.available > 0) do
|
135
|
-
cert = generate_certificate(cf, fis)
|
136
|
-
yield cert if cert
|
137
|
-
end
|
138
|
-
ensure
|
139
|
-
fis.close if fis
|
140
|
-
end
|
141
|
-
|
142
|
-
def generate_certificate(cf, fis)
|
143
|
-
cf.generateCertificate(fis)
|
144
|
-
rescue Java::JavaSecurityCert::CertificateException => e
|
145
|
-
raise e unless e.cause.message == "Empty input"
|
146
|
-
end
|
147
|
-
end
|