logstash-promtail-http-input 4.0.1-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.
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+ require "logstash-input-http_jars"
3
+
4
+ module LogStash module Inputs class Http
5
+ class MessageHandler
6
+ include org.logstash.plugins.inputs.http.IMessageHandler
7
+
8
+ attr_reader :input
9
+
10
+ def initialize(input, default_codec, additional_codecs, auth_token)
11
+ @input = input
12
+ @default_codec = default_codec
13
+ @additional_codecs = additional_codecs
14
+ @auth_token = auth_token
15
+ end
16
+
17
+ def validates_token(token)
18
+ if @auth_token
19
+ @auth_token == token
20
+ else
21
+ true
22
+ end
23
+ end
24
+
25
+ def requires_token
26
+ !!@auth_token
27
+ end
28
+
29
+ def onNewMessage(remote_address, headers, body)
30
+ @input.decode_body(headers, remote_address, body, @default_codec, @additional_codecs)
31
+ end
32
+
33
+ def copy
34
+ MessageHandler.new(@input, @default_codec.clone, clone_additional_codecs(), @auth_token)
35
+ end
36
+
37
+ def clone_additional_codecs
38
+ clone_additional_codecs = {}
39
+ @additional_codecs.each do |content_type, codec|
40
+ clone_additional_codecs[content_type] = codec.clone
41
+ end
42
+ clone_additional_codecs
43
+ end
44
+
45
+ def response_headers
46
+ @input.response_headers
47
+ end
48
+ end
49
+ end; end; end
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+ module LogStash module Inputs class Http
3
+ class TLS
4
+ class TLSOption
5
+ include Comparable
6
+
7
+ attr_reader :name, :version
8
+ def initialize(name, version)
9
+ @name = name
10
+ @version = version
11
+ end
12
+
13
+ def <=>(other)
14
+ version <=> other.version
15
+ end
16
+ end
17
+
18
+ TLS_PROTOCOL_OPTIONS = [
19
+ TLSOption.new("TLSv1", 1),
20
+ TLSOption.new("TLSv1.1", 1.1),
21
+ TLSOption.new("TLSv1.2", 1.2)
22
+ ]
23
+
24
+ def self.min
25
+ TLS_PROTOCOL_OPTIONS.min
26
+ end
27
+
28
+ def self.max
29
+ TLS_PROTOCOL_OPTIONS.max
30
+ end
31
+
32
+ def self.get_supported(versions)
33
+ if versions.is_a?(Range)
34
+ TLS_PROTOCOL_OPTIONS.select { |tls| versions.cover?(tls.version) }
35
+ else
36
+ TLS_PROTOCOL_OPTIONS.select { |tls| versions == tls.version }
37
+ end
38
+ end
39
+ end
40
+ end; end; end
@@ -0,0 +1,39 @@
1
+ class CompressedRequests
2
+ def initialize(app)
3
+ @app = app
4
+ end
5
+
6
+ def method_handled?(env)
7
+ !!(env['REQUEST_METHOD'] =~ /(POST|PUT)/)
8
+ end
9
+
10
+ def encoding_handled?(env)
11
+ ['gzip', 'deflate'].include? env['HTTP_CONTENT_ENCODING']
12
+ end
13
+
14
+ def call(env)
15
+ if method_handled?(env) && encoding_handled?(env)
16
+ begin
17
+ extracted = decode(env['rack.input'], env['HTTP_CONTENT_ENCODING'])
18
+ rescue Zlib::Error
19
+ return [400, {'Content-Type' => 'text/plain'}, ["Failed to decompress body"]]
20
+ end
21
+
22
+ env.delete('HTTP_CONTENT_ENCODING')
23
+ env['CONTENT_LENGTH'] = extracted.bytesize
24
+ env['rack.input'] = StringIO.new(extracted)
25
+ end
26
+
27
+ @app.call(env)
28
+ end
29
+
30
+ def decode(input, content_encoding)
31
+ case content_encoding
32
+ when 'gzip' then
33
+ Zlib::GzipReader.new(input).read
34
+ when 'deflate' then
35
+ Zlib::Inflate.inflate(input.read)
36
+ end
37
+ end
38
+
39
+ end
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+ require "jars/installer"
3
+ require "fileutils"
4
+
5
+ desc "vendor"
6
+ task :vendor do
7
+ exit(1) unless system './gradlew vendor'
8
+ version = File.read("VERSION").strip
9
+ end
10
+
11
+ desc "clean"
12
+ task :clean do
13
+ ["build", "vendor/jar-dependencies", "Gemfile.lock"].each do |p|
14
+ FileUtils.rm_rf(p)
15
+ end
16
+ end
@@ -0,0 +1,33 @@
1
+ HTTP_INPUT_VERSION = File.read(File.expand_path(File.join(File.dirname(__FILE__), "VERSION"))).strip unless defined?(HTTP_INPUT_VERSION)
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'logstash-promtail-http-input'
5
+ s.version = HTTP_INPUT_VERSION
6
+ s.licenses = ['Apache License (2.0)']
7
+ s.summary = "Receives events over HTTP or HTTPS"
8
+ s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
9
+ s.authors = ["Elastic"]
10
+ s.email = 'info@elastic.co'
11
+ s.homepage = "http://www.elastic.co/guide/en/logstash/current/index.html"
12
+ s.require_paths = ["lib", "vendor/jar-dependencies"]
13
+
14
+ # Files
15
+ s.files = Dir["lib/**/*","spec/**/*","*.gemspec","*.md","CONTRIBUTORS","Gemfile","LICENSE","NOTICE.TXT", "vendor/jar-dependencies/**/*.jar", "vendor/jar-dependencies/**/*.rb", "VERSION", "docs/**/*"]
16
+ # Tests
17
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
18
+
19
+ # Special flag to let us know this is actually a logstash plugin
20
+ s.metadata = { "logstash_plugin" => "true", "logstash_group" => "input" }
21
+
22
+ # Gem dependencies
23
+ s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
24
+ s.add_runtime_dependency 'logstash-codec-plain'
25
+ s.add_runtime_dependency 'jar-dependencies', '~> 0.3', '>= 0.3.4'
26
+
27
+ s.add_development_dependency 'logstash-devutils'
28
+ s.add_development_dependency 'logstash-codec-json'
29
+ s.add_development_dependency 'logstash-codec-json_lines'
30
+ s.add_development_dependency 'manticore'
31
+
32
+ s.platform = "java"
33
+ end
@@ -0,0 +1,522 @@
1
+ require "logstash/devutils/rspec/spec_helper"
2
+ require "logstash/devutils/rspec/shared_examples"
3
+ require "logstash/inputs/http"
4
+ require "json"
5
+ require "manticore"
6
+ require "stud/temporary"
7
+ require "zlib"
8
+ require "stringio"
9
+
10
+ java_import "io.netty.handler.ssl.util.SelfSignedCertificate"
11
+
12
+ describe LogStash::Inputs::Http do
13
+
14
+ before do
15
+ srand(RSpec.configuration.seed)
16
+ end
17
+
18
+ let(:client) { Manticore::Client.new(client_options) }
19
+ let(:client_options) { { } }
20
+ let(:logstash_queue) { Queue.new }
21
+ let(:port) { rand(5000) + 1025 }
22
+
23
+ it_behaves_like "an interruptible input plugin" do
24
+ let(:config) { { "port" => port } }
25
+ end
26
+
27
+ after :each do
28
+ client.clear_pending
29
+ client.close
30
+ subject.stop
31
+ end
32
+
33
+ describe "request handling" do
34
+ subject { LogStash::Inputs::Http.new("port" => port) }
35
+
36
+ before :each do
37
+ subject.register
38
+ t = Thread.new { subject.run(logstash_queue) }
39
+ ok = false
40
+ until ok
41
+ begin
42
+ client.post("http://127.0.0.1:#{port}", :body => '{}').call
43
+ rescue => e
44
+ # retry
45
+ else
46
+ ok = true
47
+ end
48
+ sleep 0.01
49
+ end
50
+ logstash_queue.pop if logstash_queue.size == 1 # pop test event
51
+ end
52
+
53
+ describe "handling overflowing requests with a 429" do
54
+ let(:logstash_queue_size) { rand(10) + 1 }
55
+ let(:max_pending_requests) { rand(5) + 1 }
56
+ let(:threads) { rand(4) + 1 }
57
+ let(:logstash_queue) { SizedQueue.new(logstash_queue_size) }
58
+ let(:client_options) { {
59
+ "request_timeout" => 0.1,
60
+ "connect_timeout" => 3,
61
+ "socket_timeout" => 0.1
62
+ } }
63
+
64
+ subject { described_class.new("port" => port, "threads" => threads, "max_pending_requests" => max_pending_requests) }
65
+
66
+ context "when sending more requests than queue slots" do
67
+ it "should block when the queue is full" do
68
+ # these will queue and return 200
69
+ logstash_queue_size.times.each do |i|
70
+ response = client.post("http://127.0.0.1:#{port}", :body => '{}').call
71
+ expect(response.code).to eq(200)
72
+ end
73
+
74
+ # these will block
75
+ (threads + max_pending_requests).times.each do |i|
76
+ expect {
77
+ client.post("http://127.0.0.1:#{port}", :body => '{}').call
78
+ }.to raise_error(Manticore::SocketTimeout)
79
+ end
80
+
81
+ # by now we should be rejecting with 429
82
+ response = client.post("http://127.0.0.1:#{port}", :body => '{}').call
83
+ expect(response.code).to eq(429)
84
+ end
85
+ end
86
+ end
87
+
88
+ describe "remote host" do
89
+ subject { LogStash::Inputs::Http.new(config.merge("port" => port)) }
90
+ context "by default" do
91
+ let(:config) { {} }
92
+ it "is written to the \"host\" field" do
93
+ client.post("http://localhost:#{port}/loki/",
94
+ :headers => { "content-type" => "text/plain" },
95
+ :body => "hello").call
96
+ event = logstash_queue.pop
97
+ expect(event.get("host")).to eq("127.0.0.1")
98
+ end
99
+ end
100
+
101
+ context "when using remote_host_target_field" do
102
+ let(:config) { { "remote_host_target_field" => "remote_host" } }
103
+ it "is written to the value of \"remote_host_target_field\" property" do
104
+ client.post("http://localhost:#{port}/meh.json",
105
+ :headers => { "content-type" => "text/plain" },
106
+ :body => "hello").call
107
+ event = logstash_queue.pop
108
+ expect(event.get("remote_host")).to eq("127.0.0.1")
109
+ end
110
+ end
111
+ end
112
+
113
+ describe "request headers" do
114
+ subject { LogStash::Inputs::Http.new(config.merge("port" => port)) }
115
+ context "by default" do
116
+ let(:config) { {} }
117
+ it "are written to the \"headers\" field" do
118
+ client.post("http://localhost:#{port}/meh.json",
119
+ :headers => { "content-type" => "text/plain" },
120
+ :body => "hello").call
121
+ event = logstash_queue.pop
122
+ expect(event.get("headers")).to be_a(Hash)
123
+ expect(event.get("headers")).to include("request_method" => "POST")
124
+ end
125
+ end
126
+ context "when using request_headers_target_field" do
127
+ let(:config) { { "request_headers_target_field" => "request_headers" } }
128
+ it "are written to the field set in \"request_headers_target_field\"" do
129
+ client.post("http://localhost:#{port}/meh.json",
130
+ :headers => { "content-type" => "text/plain" },
131
+ :body => "hello").call
132
+ event = logstash_queue.pop
133
+ expect(event.get("request_headers")).to be_a(Hash)
134
+ expect(event.get("request_headers")).to include("request_method" => "POST")
135
+ end
136
+ end
137
+ end
138
+
139
+ it "should include remote host in \"host\" property" do
140
+ client.post("http://127.0.0.1:#{port}/meh.json",
141
+ :headers => { "content-type" => "text/plain" },
142
+ :body => "hello").call
143
+ event = logstash_queue.pop
144
+ expect(event.get("host")).to eq("127.0.0.1")
145
+ end
146
+
147
+ context "with default codec" do
148
+ subject { LogStash::Inputs::Http.new("port" => port) }
149
+ context "when receiving a text/plain request" do
150
+ it "should process the request normally" do
151
+ client.post("http://127.0.0.1:#{port}/meh.json",
152
+ :headers => { "content-type" => "text/plain" },
153
+ :body => "hello").call
154
+ event = logstash_queue.pop
155
+ expect(event.get("message")).to eq("hello")
156
+ end
157
+ end
158
+ context "when receiving a application/x-protobuf request" do
159
+ it "should decompress using snappy" do
160
+ promtail_input = org.logstash.plugins.inputs.http.promtail.PromtailHandler.new
161
+ message = "My compressed and protobuf-ed message"
162
+ promtail_input.sendLogHttp("http://127.0.0.1:#{port}/template/loki", message, nil)
163
+ event = logstash_queue.pop
164
+ expect(event.get("message")).to eq(message)
165
+ end
166
+ it "should set tenant" do
167
+ promtail_input = org.logstash.plugins.inputs.http.promtail.PromtailHandler.new
168
+ message = "My compressed and protobuf-ed message"
169
+ tenant = "sometenant"
170
+ promtail_input.sendLogHttp("http://127.0.0.1:#{port}/template/loki", message, tenant)
171
+ event = logstash_queue.pop
172
+ expect(event.get("message")).to eq(message)
173
+ expect(event.get("tenant")).to eq(tenant)
174
+ end
175
+ end
176
+ context "when receiving a deflate compressed text/plain request" do
177
+ it "should process the request normally" do
178
+ client.post("http://127.0.0.1:#{port}/meh.json",
179
+ :headers => { "content-type" => "text/plain", "content-encoding" => "deflate" },
180
+ :body => Zlib::Deflate.deflate("hello")).call
181
+ event = logstash_queue.pop
182
+ expect(event.get("message")).to eq("hello")
183
+ end
184
+ end
185
+ context "when receiving a deflate text/plain request that cannot be decompressed" do
186
+ let(:response) do
187
+ response = client.post("http://127.0.0.1:#{port}/meh.json",
188
+ :headers => { "content-type" => "text/plain", "content-encoding" => "deflate" },
189
+ :body => "hello").call
190
+ end
191
+ it "should respond with 400" do
192
+ expect(response.code).to eq(400)
193
+ end
194
+ end
195
+ context "when receiving a gzip compressed text/plain request" do
196
+ it "should process the request normally" do
197
+ wio = StringIO.new("w")
198
+ z = Zlib::GzipWriter.new(wio)
199
+ z.write("hello")
200
+ z.close
201
+ entity = org.apache.http.entity.ByteArrayEntity.new(wio.string.to_java_bytes)
202
+ response = client.post("http://127.0.0.1:#{port}",
203
+ :headers => { "Content-Encoding" => "gzip" },
204
+ :entity => entity).call
205
+ expect(response.code).to eq(200)
206
+ event = logstash_queue.pop
207
+ expect(event.get("message")).to eq("hello")
208
+ end
209
+ end
210
+ context "when receiving a gzip text/plain request that cannot be decompressed" do
211
+ let(:response) do
212
+ client.post("http://127.0.0.1:#{port}",
213
+ :headers => { "Content-Encoding" => "gzip" },
214
+ :body => Zlib::Deflate.deflate("hello")).call
215
+ end
216
+ it "should respond with 400" do
217
+ expect(response.code).to eq(400)
218
+ end
219
+ end
220
+ context "when receiving an application/json request" do
221
+ it "should parse the json body" do
222
+ client.post("http://127.0.0.1:#{port}/meh.json",
223
+ :headers => { "content-type" => "application/json" },
224
+ :body => { "message_body" => "Hello" }.to_json).call
225
+ event = logstash_queue.pop
226
+ expect(event.get("message_body")).to eq("Hello")
227
+ end
228
+ end
229
+ end
230
+
231
+ context "with json codec" do
232
+ subject { LogStash::Inputs::Http.new("port" => port, "codec" => "json") }
233
+ it "should parse the json body" do
234
+ response = client.post("http://127.0.0.1:#{port}/meh.json", :body => { "message" => "Hello" }.to_json).call
235
+ event = logstash_queue.pop
236
+ expect(event.get("message")).to eq("Hello")
237
+ end
238
+ end
239
+
240
+ context "with json_lines codec without final delimiter" do
241
+ subject { LogStash::Inputs::Http.new("port" => port, "codec" => "json_lines") }
242
+ let(:line1) { '{"foo": 1}' }
243
+ let(:line2) { '{"foo": 2}' }
244
+ it "should parse all json_lines in body including last one" do
245
+ client.post("http://localhost:#{port}/meh.json", :body => "#{line1}\n#{line2}").call
246
+ expect(logstash_queue.size).to eq(2)
247
+ event = logstash_queue.pop
248
+ expect(event.get("foo")).to eq(1)
249
+ event = logstash_queue.pop
250
+ expect(event.get("foo")).to eq(2)
251
+ end
252
+ end
253
+
254
+ context "when using a custom codec mapping" do
255
+ subject { LogStash::Inputs::Http.new("port" => port,
256
+ "additional_codecs" => { "application/json" => "plain" }) }
257
+ it "should decode the message accordingly" do
258
+ body = { "message" => "Hello" }.to_json
259
+ client.post("http://127.0.0.1:#{port}/meh.json",
260
+ :headers => { "content-type" => "application/json" },
261
+ :body => body).call
262
+ event = logstash_queue.pop
263
+ expect(event.get("message")).to eq(body)
264
+ end
265
+ end
266
+
267
+ context "when receiving a content-type with a charset" do
268
+ subject { LogStash::Inputs::Http.new("port" => port,
269
+ "additional_codecs" => { "application/json" => "plain" }) }
270
+ it "should decode the message accordingly" do
271
+ body = { "message" => "Hello" }.to_json
272
+ client.post("http://127.0.0.1:#{port}/meh.json",
273
+ :headers => { "content-type" => "application/json; charset=utf-8" },
274
+ :body => body).call
275
+ event = logstash_queue.pop
276
+ expect(event.get("message")).to eq(body)
277
+ end
278
+ end
279
+
280
+ context "when using custom headers" do
281
+ let(:custom_headers) { { 'access-control-allow-origin' => '*' } }
282
+ subject { LogStash::Inputs::Http.new("port" => port, "response_headers" => custom_headers) }
283
+
284
+ describe "the response" do
285
+ it "should include the custom headers" do
286
+ response = client.post("http://127.0.0.1:#{port}/meh", :body => "hello").call
287
+ expect(response.headers.to_hash).to include(custom_headers)
288
+ end
289
+ end
290
+ end
291
+ describe "basic auth" do
292
+ user = "test"; password = "pwd"
293
+ subject { LogStash::Inputs::Http.new("port" => port, "user" => user, "password" => password) }
294
+ let(:auth_token) { Base64.strict_encode64("#{user}:#{password}") }
295
+ context "when client doesn't present auth token" do
296
+ let!(:response) { client.post("http://127.0.0.1:#{port}/meh", :body => "hi").call }
297
+ it "should respond with 401" do
298
+ expect(response.code).to eq(401)
299
+ end
300
+ it 'should include a WWW-Authenticate: Basic header' do
301
+ expect(response['WWW-Authenticate']).to_not be_nil
302
+
303
+ expect(response['WWW-Authenticate']).to start_with('Basic realm=')
304
+ end
305
+ it "should not generate an event" do
306
+ expect(logstash_queue).to be_empty
307
+ end
308
+ end
309
+ context "when client presents incorrect auth token" do
310
+ let!(:response) do
311
+ client.post("http://127.0.0.1:#{port}/meh",
312
+ :headers => {
313
+ "content-type" => "text/plain",
314
+ "authorization" => "Basic meh"
315
+ },
316
+ :body => "hi").call
317
+ end
318
+ it "should respond with 401" do
319
+ expect(response.code).to eq(401)
320
+ end
321
+ it 'should not include a WWW-Authenticate header' do
322
+ expect(response['WWW-Authenticate']).to be_nil
323
+ end
324
+ it "should not generate an event" do
325
+ expect(logstash_queue).to be_empty
326
+ end
327
+ end
328
+ context "when client presents correct auth token" do
329
+ let!(:response) do
330
+ client.post("http://127.0.0.1:#{port}/meh",
331
+ :headers => {
332
+ "content-type" => "text/plain",
333
+ "authorization" => "Basic #{auth_token}"
334
+ }, :body => "hi").call
335
+ end
336
+ it "should respond with 200" do
337
+ expect(response.code).to eq(200)
338
+ end
339
+ it "should generate an event" do
340
+ expect(logstash_queue).to_not be_empty
341
+ end
342
+ end
343
+ end
344
+
345
+ describe "HTTP Protocol Handling" do
346
+ context "when an HTTP1.1 request is made" do
347
+ let(:protocol_version) do
348
+ Java::OrgApacheHttp::HttpVersion::HTTP_1_1
349
+ end
350
+ it "responds with a HTTP1.1 response" do
351
+ response = client.post("http://127.0.0.1:#{port}", :body => "hello")
352
+ response.request.set_protocol_version(protocol_version)
353
+ response.call
354
+ response_protocol_version = response.instance_variable_get(:@response).get_protocol_version
355
+ expect(response_protocol_version).to eq(protocol_version)
356
+ end
357
+ end
358
+ context "when an HTTP1.0 request is made" do
359
+ let(:protocol_version) do
360
+ Java::OrgApacheHttp::HttpVersion::HTTP_1_0
361
+ end
362
+ it "responds with a HTTP1.0 response" do
363
+ response = client.post("http://127.0.0.1:#{port}", :body => "hello")
364
+ response.request.set_protocol_version(protocol_version)
365
+ response.call
366
+ response_protocol_version = response.instance_variable_get(:@response).get_protocol_version
367
+ expect(response_protocol_version).to eq(protocol_version)
368
+ end
369
+ end
370
+ end
371
+ describe "return code" do
372
+ it "responds with a 200" do
373
+ response = client.post("http://127.0.0.1:#{port}", :body => "hello")
374
+ response.call
375
+ expect(response.code).to eq(200)
376
+ end
377
+ context "when response_code is configured" do
378
+ let(:code) { 202 }
379
+ subject { LogStash::Inputs::Http.new("port" => port, "response_code" => code) }
380
+ it "responds with the configured code" do
381
+ response = client.post("http://127.0.0.1:#{port}", :body => "hello")
382
+ response.call
383
+ expect(response.code).to eq(202)
384
+ end
385
+ end
386
+ end
387
+ end
388
+
389
+ context "with :ssl => false" do
390
+ subject { LogStash::Inputs::Http.new("port" => port, "ssl" => false) }
391
+ it "should not raise exception" do
392
+ expect { subject.register }.to_not raise_exception
393
+ end
394
+ end
395
+ context "with :ssl => true" do
396
+ context "without :ssl_certificate" do
397
+ subject { LogStash::Inputs::Http.new("port" => port, "ssl" => true) }
398
+ it "should raise exception" do
399
+ expect { subject.register }.to raise_exception(LogStash::ConfigurationError)
400
+ end
401
+ end
402
+ context "with :ssl_certificate" do
403
+ let(:ssc) { SelfSignedCertificate.new }
404
+ let(:ssl_certificate) { ssc.certificate }
405
+ let(:ssl_key) { ssc.private_key }
406
+
407
+ let(:config) do
408
+ { "port" => port, "ssl" => true, "ssl_certificate" => ssl_certificate.path, "ssl_key" => ssl_key.path }
409
+ end
410
+
411
+ after(:each) { ssc.delete }
412
+
413
+ subject { LogStash::Inputs::Http.new(config) }
414
+
415
+ it "should not raise exception" do
416
+ expect { subject.register }.to_not raise_exception
417
+ end
418
+
419
+ context "with ssl_verify_mode = none" do
420
+ subject { LogStash::Inputs::Http.new(config.merge("ssl_verify_mode" => "none")) }
421
+
422
+ it "should not raise exception" do
423
+ expect { subject.register }.to_not raise_exception
424
+ end
425
+ end
426
+ ["peer", "force_peer"].each do |verify_mode|
427
+ context "with ssl_verify_mode = #{verify_mode}" do
428
+ subject { LogStash::Inputs::Http.new("port" => port, "ssl" => true,
429
+ "ssl_certificate" => ssl_certificate.path,
430
+ "ssl_certificate_authorities" => ssl_certificate.path,
431
+ "ssl_key" => ssl_key.path,
432
+ "ssl_verify_mode" => verify_mode
433
+ ) }
434
+ it "should not raise exception" do
435
+ expect { subject.register }.to_not raise_exception
436
+ end
437
+ end
438
+ end
439
+ context "with verify_mode = none" do
440
+ subject { LogStash::Inputs::Http.new(config.merge("verify_mode" => "none")) }
441
+
442
+ it "should not raise exception" do
443
+ expect { subject.register }.to_not raise_exception
444
+ end
445
+ end
446
+ ["peer", "force_peer"].each do |verify_mode|
447
+ context "with verify_mode = #{verify_mode}" do
448
+ subject { LogStash::Inputs::Http.new("port" => port, "ssl" => true,
449
+ "ssl_certificate" => ssl_certificate.path,
450
+ "ssl_certificate_authorities" => ssl_certificate.path,
451
+ "ssl_key" => ssl_key.path,
452
+ "verify_mode" => verify_mode
453
+ ) }
454
+ it "should not raise exception" do
455
+ expect { subject.register }.to_not raise_exception
456
+ end
457
+ end
458
+ end
459
+
460
+ context "with invalid cipher_suites" do
461
+ let(:config) { super().merge("cipher_suites" => "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA38") }
462
+
463
+ it "should raise a configuration error" do
464
+ expect( subject.logger ).to receive(:error) do |msg, opts|
465
+ expect( msg ).to match /.*?configuration invalid/
466
+ expect( opts[:message] ).to match /TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA38.*? not available/
467
+ end
468
+ expect { subject.register }.to raise_error(LogStash::ConfigurationError)
469
+ end
470
+ end
471
+
472
+ context "with invalid ssl certificate" do
473
+ before do
474
+ cert = File.readlines path = config["ssl_certificate"]
475
+ i = cert.index { |line| line.index('END CERTIFICATE') }
476
+ cert[i - 1] = ''
477
+ File.write path, cert.join("\n")
478
+ end
479
+
480
+ it "should raise a configuration error" do
481
+ expect( subject.logger ).to receive(:error) do |msg, opts|
482
+ expect( msg ).to match /SSL configuration invalid/
483
+ expect( opts[:message] ).to match /File does not contain valid certificate/i
484
+ end
485
+ expect { subject.register }.to raise_error(LogStash::ConfigurationError)
486
+ end
487
+ end
488
+
489
+ context "with invalid ssl key config" do
490
+ let(:config) { super().merge("ssl_key_passphrase" => "1234567890") }
491
+
492
+ it "should raise a configuration error" do
493
+ expect( subject.logger ).to receive(:error) do |msg, opts|
494
+ expect( msg ).to match /SSL configuration invalid/
495
+ expect( opts[:message] ).to match /File does not contain valid private key/i
496
+ end
497
+ expect { subject.register }.to raise_error(LogStash::ConfigurationError)
498
+ end
499
+ end
500
+
501
+ context "with invalid ssl certificate_authorities" do
502
+ let(:config) do
503
+ super().merge("ssl_verify_mode" => "peer",
504
+ "ssl_certificate_authorities" => [ ssc.certificate.path, ssc.private_key.path ])
505
+ end
506
+
507
+ it "should raise a cert error" do
508
+ expect( subject.logger ).to receive(:error) do |msg, opts|
509
+ expect( msg ).to match(/SSL configuration failed/), lambda { "unexpected: logger.error #{msg.inspect}, #{opts.inspect}" }
510
+ expect( opts[:message] ).to match /signed fields invalid/
511
+ end
512
+ begin
513
+ subject.register
514
+ rescue Java::JavaSecurityCert::CertificateParsingException
515
+ :pass
516
+ end
517
+ end
518
+ end
519
+
520
+ end
521
+ end
522
+ end