logstash-output-syslog 3.0.4 → 3.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.
@@ -0,0 +1,276 @@
1
+ # encoding: utf-8
2
+
3
+ require "logstash/devutils/rspec/spec_helper"
4
+ require "logstash/outputs/syslog"
5
+ require "logstash/codecs/plain"
6
+ require "json"
7
+
8
+ describe LogStash::Outputs::Syslog do
9
+ FIXTURES_PATH = File.expand_path("../fixtures", File.dirname(__FILE__))
10
+
11
+ subject do
12
+ plugin = LogStash::Plugin.lookup("output", "syslog").new(options)
13
+ plugin.register
14
+ plugin
15
+ end
16
+
17
+ let(:port) do
18
+ begin
19
+ # Start high to better avoid common services
20
+ port = rand(10000..65535)
21
+ s = TCPServer.new("127.0.0.1", port)
22
+ s.close
23
+
24
+ port
25
+ rescue Errno::EADDRINUSE
26
+ retry
27
+ end
28
+ end
29
+
30
+ let(:server) { TCPServer.new("127.0.0.1", port) }
31
+
32
+ shared_examples "syslog output" do
33
+ it "should write expected format" do
34
+ Thread.start { sleep 0.25; subject.receive event }
35
+ socket = secure_server.accept
36
+ expect(socket.cipher).to eq(chosen_cipher) if defined?(chosen_cipher)
37
+ expect(socket.ssl_version).to eq(chosen_tls_version) if defined?(chosen_tls_version)
38
+ read = socket.sysread(100)
39
+ expect(read.size).to be > 0
40
+ expect(read).to match(output)
41
+ end
42
+ end
43
+
44
+ context "connects with TLS" do
45
+ let(:event) { LogStash::Event.new({ "message" => "foo bar", "host" => "baz" }) }
46
+ let(:options) { { "host" => "localhost", "port" => port, "protocol" => "ssl-tcp",
47
+ "ssl_cacert" => File.join(FIXTURES_PATH, "ca.pem"),
48
+ "ssl_cert" => File.join(FIXTURES_PATH, "client.pem"),
49
+ "ssl_key" => File.join(FIXTURES_PATH, "client-key.pem") } }
50
+ # The output details are tested in syslog_spec.rb so simply check for message to be present.
51
+ let(:output) { /foo bar/ }
52
+
53
+ let(:secure_server) do
54
+ # Create TLS server with given certificate and private key, and verify client certificate against CA.
55
+ ssl_context = OpenSSL::SSL::SSLContext.new
56
+ ssl_context.cert = OpenSSL::X509::Certificate.new(File.read(server_cert_file))
57
+ ssl_context.key = OpenSSL::PKey::read(File.read(server_pkey_file), nil)
58
+ ssl_context.verify_mode = OpenSSL::SSL::VERIFY_PEER
59
+ ssl_context.ciphers = "ALL"
60
+ ssl_context.cert_store = OpenSSL::X509::Store.new
61
+ ssl_context.cert_store.add_cert(OpenSSL::X509::Certificate.new(File.read(File.join(FIXTURES_PATH, "ca.pem"))))
62
+ OpenSSL::SSL::SSLServer.new(server, ssl_context)
63
+ end
64
+
65
+ after(:each) do
66
+ secure_server.close rescue nil
67
+ end
68
+
69
+ context "server with valid certificates" do
70
+ let(:server_cert_file) { File.join(FIXTURES_PATH, "valid-server.pem") }
71
+ let(:server_pkey_file) { File.join(FIXTURES_PATH, "valid-server-key.pem") }
72
+
73
+ context "with SSL verification" do
74
+ let(:options ) { super().merge("ssl_verify" => true) }
75
+
76
+ it_behaves_like "syslog output"
77
+ end
78
+
79
+ context "with TLSv1.2" do
80
+ let(:options ) { super().merge("ssl_supported_protocols" => ["TLSv1.2"]) }
81
+ let(:chosen_tls_version) { "TLSv1.2" }
82
+
83
+ it_behaves_like "syslog output"
84
+ end
85
+
86
+ context "with TLSv1.3" do
87
+ let(:options ) { super().merge("ssl_supported_protocols" => ["TLSv1.3"]) }
88
+ let(:chosen_tls_version) { "TLSv1.3" }
89
+
90
+ it_behaves_like "syslog output"
91
+ end
92
+
93
+ context "with TLSv1.2 and TLSv1.3" do
94
+ let(:options ) { super().merge("ssl_supported_protocols" => ["TLSv1.2", "TLSv1.3"]) }
95
+ let(:chosen_tls_version) { "TLSv1.3" }
96
+
97
+ it_behaves_like "syslog output"
98
+ end
99
+
100
+ context "with cipher suites" do
101
+ let(:options ) { super().merge("ssl_cipher_suites" => ["TLS_CHACHA20_POLY1305_SHA256"]) }
102
+ let(:chosen_cipher) { "TLS_CHACHA20_POLY1305_SHA256" }
103
+
104
+ it_behaves_like "syslog output"
105
+ end
106
+
107
+ context "with deprecated ssl_cert and ssl_cacert" do
108
+ # Override parent options to test only deprecated options.
109
+ let(:options) { { "host" => "localhost", "port" => port, "protocol" => "ssl-tcp", "ssl_verify" => true,
110
+ "ssl_cert" => File.join(FIXTURES_PATH, "client.pem"),
111
+ "ssl_key" => File.join(FIXTURES_PATH, "client-key.pem"),
112
+ "ssl_cacert" => File.join(FIXTURES_PATH, "ca.pem")
113
+ } }
114
+
115
+ it_behaves_like "syslog output"
116
+ end
117
+
118
+ end
119
+
120
+ context "server with untrusted certificates" do
121
+ let(:server_cert_file) { File.join(FIXTURES_PATH, "untrusted-server.pem") }
122
+ let(:server_pkey_file) { File.join(FIXTURES_PATH, "untrusted-server-key.pem") }
123
+
124
+ context "ssl_verify disabled" do
125
+ let(:options ) { super().merge("ssl_verify" => false) }
126
+
127
+ it_behaves_like "syslog output"
128
+ end
129
+
130
+ context "ssl_verify enabled" do
131
+ let(:options ) { super().merge("ssl_verify" => true) }
132
+
133
+ it "should refuse to connect" do
134
+ Thread.start { secure_server.accept rescue nil }
135
+ expect(subject.logger).to receive(:error).with(/SSL Error/i, hash_including(exception: OpenSSL::SSL::SSLError)).once.and_throw :TEST_DONE
136
+ expect { subject.receive event }.to throw_symbol(:TEST_DONE)
137
+ end
138
+ end
139
+
140
+ end
141
+
142
+ context "server with revoked certificates" do
143
+ let(:options ) { super().merge("ssl_verify" => true, "ssl_crl_path" => File.join(FIXTURES_PATH, "ca-crl.pem")) }
144
+ let(:server_cert_file) { File.join(FIXTURES_PATH, "revoked-server.pem") }
145
+ let(:server_pkey_file) { File.join(FIXTURES_PATH, "revoked-server-key.pem") }
146
+
147
+ shared_examples "refuses connection" do
148
+ it "syslog output refuses to connect" do
149
+ Thread.start { secure_server.accept rescue nil }
150
+ expect(subject.logger).to receive(:error).with(/SSL Error/i, hash_including(exception: OpenSSL::SSL::SSLError)).once.and_throw :TEST_DONE
151
+ expect { subject.receive event }.to throw_symbol(:TEST_DONE)
152
+ end
153
+ end
154
+
155
+ context "with default ssl_crl_check" do
156
+ it_behaves_like "refuses connection"
157
+ end
158
+
159
+ context "with chain ssl_crl_check" do
160
+ let(:options ) { super().merge("ssl_crl_check" => ["chain"]) }
161
+
162
+ it_behaves_like "refuses connection"
163
+ end
164
+ end
165
+ end
166
+
167
+ context "read PEM" do
168
+ let(:options) { { "host" => "localhost", "port" => port, "protocol" => "ssl-tcp", "ssl_verify" => true } }
169
+
170
+ context "RSA certificate and private key" do
171
+ let(:options ) { super().merge(
172
+ "ssl_certificate" => File.join(FIXTURES_PATH, "client.pem"),
173
+ "ssl_key" => File.join(FIXTURES_PATH, "client-key.pem"),
174
+ "ssl_certificate_authorities" => [File.join(FIXTURES_PATH, "ca.pem")],
175
+ "ssl_crl_path" => File.join(FIXTURES_PATH, "ca-crl.pem")
176
+ ) }
177
+
178
+ it "register succeeds" do
179
+ expect { subject.register }.not_to raise_error
180
+ end
181
+ end
182
+
183
+ context "EC certificate and private key" do
184
+ let(:options ) { super().merge(
185
+ "ssl_certificate" => File.join(FIXTURES_PATH, "client-ec.pem"),
186
+ "ssl_key" => File.join(FIXTURES_PATH, "client-ec-key.pem"),
187
+ "ssl_certificate_authorities" => [File.join(FIXTURES_PATH, "ca.pem")],
188
+ "ssl_crl_path" => File.join(FIXTURES_PATH, "ca-crl.pem")
189
+ ) }
190
+
191
+ it "register succeeds" do
192
+ expect { subject.register }.not_to raise_error
193
+ end
194
+ end
195
+
196
+ context "invalid client certificate" do
197
+ let(:options ) { super().merge(
198
+ "ssl_certificate" => File.join(FIXTURES_PATH, "invalid.pem"),
199
+ "ssl_key" => File.join(FIXTURES_PATH, "client-key.pem"),
200
+ "ssl_certificate_authorities" => [File.join(FIXTURES_PATH, "ca.pem")],
201
+ "ssl_crl_path" => File.join(FIXTURES_PATH, "ca-crl.pem")
202
+ ) }
203
+
204
+ it "register raises error" do
205
+ expect { subject.register }.to raise_error(OpenSSL::X509::CertificateError, /malformed PEM data/)
206
+ end
207
+ end
208
+
209
+ context "invalid client private key" do
210
+ let(:options ) { super().merge(
211
+ "ssl_certificate" => File.join(FIXTURES_PATH, "client.pem"),
212
+ "ssl_key" => File.join(FIXTURES_PATH, "invalid.pem"),
213
+ "ssl_certificate_authorities" => [File.join(FIXTURES_PATH, "ca.pem")],
214
+ "ssl_crl_path" => File.join(FIXTURES_PATH, "ca-crl.pem")
215
+ ) }
216
+
217
+ it "register raises error" do
218
+ expect { subject.register }.to raise_error(OpenSSL::PKey::PKeyError, /Could not parse PKey/)
219
+ end
220
+ end
221
+
222
+ context "invalid CRL" do
223
+ let(:options ) { super().merge(
224
+ "ssl_certificate" => File.join(FIXTURES_PATH, "client.pem"),
225
+ "ssl_key" => File.join(FIXTURES_PATH, "client-key.pem"),
226
+ "ssl_certificate_authorities" => [File.join(FIXTURES_PATH, "ca.pem")],
227
+ "ssl_crl_path" => File.join(FIXTURES_PATH, "invalid.pem")
228
+ ) }
229
+
230
+ it "register raises error" do
231
+ expect { subject.register }.to raise_error(OpenSSL::X509::CRLError, /malformed PEM data/)
232
+ end
233
+ end
234
+
235
+ end
236
+
237
+ context "CRL options validation" do
238
+ let(:options) { { "host" => "localhost", "port" => port, "protocol" => "ssl-tcp", "ssl_verify" => true,
239
+ "ssl_certificate" => File.join(FIXTURES_PATH, "client.pem"),
240
+ "ssl_key" => File.join(FIXTURES_PATH, "client-key.pem"),
241
+ "ssl_certificate_authorities" => [File.join(FIXTURES_PATH, "ca.pem")],
242
+ "ssl_crl_path" => File.join(FIXTURES_PATH, "ca-crl.pem") } }
243
+
244
+ context "when ssl_crl_check contains only leaf" do
245
+ let(:options) { super().merge("ssl_crl_check" => ["leaf"]) }
246
+
247
+ it "should register without errors" do
248
+ expect { subject.register }.not_to raise_error
249
+ end
250
+ end
251
+
252
+ context "when ssl_crl_check contains only chain" do
253
+ let(:options) { super().merge("ssl_crl_check" => ["chain"]) }
254
+
255
+ it "should register without errors" do
256
+ expect { subject.register }.not_to raise_error
257
+ end
258
+ end
259
+
260
+ context "when ssl_crl_check contains both leaf and chain" do
261
+ let(:options) { super().merge("ssl_crl_check" => ["leaf", "chain"]) }
262
+
263
+ it "should raise ConfigurationError for mutually exclusive options" do
264
+ expect { subject.register }.to raise_error(LogStash::ConfigurationError, /ssl_crl_check can only contain one of 'leaf' or 'chain'/)
265
+ end
266
+ end
267
+
268
+ context "when ssl_crl_check is set without ssl_crl_path" do
269
+ let(:options) { super().reject { |k| k == "ssl_crl_path" }.merge("ssl_crl_check" => ["leaf"]) }
270
+
271
+ it "should raise ConfigurationError for missing ssl_crl_path" do
272
+ expect { subject.register }.to raise_error(LogStash::ConfigurationError, /ssl_crl_check is set but ssl_crl_path is not set/)
273
+ end
274
+ end
275
+ end
276
+ end
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-output-syslog
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.4
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elastic
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2017-11-13 00:00:00.000000000 Z
10
+ date: 2025-12-23 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
13
+ name: logstash-core-plugin-api
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
16
  - - ">="
@@ -19,9 +19,8 @@ dependencies:
19
19
  - - "<="
20
20
  - !ruby/object:Gem::Version
21
21
  version: '2.99'
22
- name: logstash-core-plugin-api
23
- prerelease: false
24
22
  type: :runtime
23
+ prerelease: false
25
24
  version_requirements: !ruby/object:Gem::Requirement
26
25
  requirements:
27
26
  - - ">="
@@ -31,42 +30,56 @@ dependencies:
31
30
  - !ruby/object:Gem::Version
32
31
  version: '2.99'
33
32
  - !ruby/object:Gem::Dependency
33
+ name: logstash-codec-plain
34
34
  requirement: !ruby/object:Gem::Requirement
35
35
  requirements:
36
36
  - - ">="
37
37
  - !ruby/object:Gem::Version
38
38
  version: '0'
39
- name: logstash-codec-plain
40
- prerelease: false
41
39
  type: :runtime
40
+ prerelease: false
42
41
  version_requirements: !ruby/object:Gem::Requirement
43
42
  requirements:
44
43
  - - ">="
45
44
  - !ruby/object:Gem::Version
46
45
  version: '0'
47
46
  - !ruby/object:Gem::Dependency
47
+ name: logstash-mixin-normalize_config_support
48
48
  requirement: !ruby/object:Gem::Requirement
49
49
  requirements:
50
50
  - - ">="
51
51
  - !ruby/object:Gem::Version
52
52
  version: '0'
53
- name: logstash-devutils
53
+ type: :runtime
54
54
  prerelease: false
55
- type: :development
56
55
  version_requirements: !ruby/object:Gem::Requirement
57
56
  requirements:
58
57
  - - ">="
59
58
  - !ruby/object:Gem::Version
60
59
  version: '0'
61
60
  - !ruby/object:Gem::Dependency
61
+ name: logstash-devutils
62
62
  requirement: !ruby/object:Gem::Requirement
63
63
  requirements:
64
64
  - - ">="
65
65
  - !ruby/object:Gem::Version
66
66
  version: '0'
67
- name: logstash-codec-json
67
+ type: :development
68
68
  prerelease: false
69
+ version_requirements: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ - !ruby/object:Gem::Dependency
75
+ name: logstash-codec-json
76
+ requirement: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
69
81
  type: :development
82
+ prerelease: false
70
83
  version_requirements: !ruby/object:Gem::Requirement
71
84
  requirements:
72
85
  - - ">="
@@ -89,14 +102,30 @@ files:
89
102
  - docs/index.asciidoc
90
103
  - lib/logstash/outputs/syslog.rb
91
104
  - logstash-output-syslog.gemspec
105
+ - spec/fixtures/README.txt
106
+ - spec/fixtures/ca-crl.pem
107
+ - spec/fixtures/ca-key.pem
108
+ - spec/fixtures/ca.pem
109
+ - spec/fixtures/certs.yaml
110
+ - spec/fixtures/client-ec-key.pem
111
+ - spec/fixtures/client-ec.pem
112
+ - spec/fixtures/client-key.pem
113
+ - spec/fixtures/client.pem
114
+ - spec/fixtures/invalid.pem
115
+ - spec/fixtures/revoked-server-key.pem
116
+ - spec/fixtures/revoked-server.pem
117
+ - spec/fixtures/untrusted-server-key.pem
118
+ - spec/fixtures/untrusted-server.pem
119
+ - spec/fixtures/valid-server-key.pem
120
+ - spec/fixtures/valid-server.pem
92
121
  - spec/outputs/syslog_spec.rb
122
+ - spec/outputs/syslog_tls_spec.rb
93
123
  homepage: http://www.elastic.co/guide/en/logstash/current/index.html
94
124
  licenses:
95
125
  - Apache License (2.0)
96
126
  metadata:
97
127
  logstash_plugin: 'true'
98
128
  logstash_group: output
99
- post_install_message:
100
129
  rdoc_options: []
101
130
  require_paths:
102
131
  - lib
@@ -111,10 +140,25 @@ required_rubygems_version: !ruby/object:Gem::Requirement
111
140
  - !ruby/object:Gem::Version
112
141
  version: '0'
113
142
  requirements: []
114
- rubyforge_project:
115
- rubygems_version: 2.6.11
116
- signing_key:
143
+ rubygems_version: 3.6.3
117
144
  specification_version: 4
118
145
  summary: Sends events to a `syslog` server
119
146
  test_files:
147
+ - spec/fixtures/README.txt
148
+ - spec/fixtures/ca-crl.pem
149
+ - spec/fixtures/ca-key.pem
150
+ - spec/fixtures/ca.pem
151
+ - spec/fixtures/certs.yaml
152
+ - spec/fixtures/client-ec-key.pem
153
+ - spec/fixtures/client-ec.pem
154
+ - spec/fixtures/client-key.pem
155
+ - spec/fixtures/client.pem
156
+ - spec/fixtures/invalid.pem
157
+ - spec/fixtures/revoked-server-key.pem
158
+ - spec/fixtures/revoked-server.pem
159
+ - spec/fixtures/untrusted-server-key.pem
160
+ - spec/fixtures/untrusted-server.pem
161
+ - spec/fixtures/valid-server-key.pem
162
+ - spec/fixtures/valid-server.pem
120
163
  - spec/outputs/syslog_spec.rb
164
+ - spec/outputs/syslog_tls_spec.rb