logstash-promtail-input-http 1.0.0-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -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-input-http'
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