sp-logstash-input-http 3.3.7-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,293 @@
1
+ # encoding: utf-8
2
+ require "logstash/inputs/base"
3
+ require "logstash/namespace"
4
+ require "stud/interval"
5
+ require "logstash-input-http_jars"
6
+
7
+ # Using this input you can receive single or multiline events over http(s).
8
+ # Applications can send a HTTP POST request with a body to the endpoint started by this
9
+ # input and Logstash will convert it into an event for subsequent processing. Users
10
+ # can pass plain text, JSON, or any formatted data and use a corresponding codec with this
11
+ # input. For Content-Type `application/json` the `json` codec is used, but for all other
12
+ # data formats, `plain` codec is used.
13
+ #
14
+ # This input can also be used to receive webhook requests to integrate with other services
15
+ # and applications. By taking advantage of the vast plugin ecosystem available in Logstash
16
+ # you can trigger actionable events right from your application.
17
+ #
18
+ # ==== Security
19
+ # This plugin supports standard HTTP basic authentication headers to identify the requester.
20
+ # You can pass in an username, password combination while sending data to this input
21
+ #
22
+ # You can also setup SSL and send data securely over https, with an option of validating
23
+ # the client's certificate. Currently, the certificate setup is through
24
+ # https://docs.oracle.com/cd/E19509-01/820-3503/ggfen/index.html[Java Keystore
25
+ # format]
26
+ #
27
+ class LogStash::Inputs::Http < LogStash::Inputs::Base
28
+ require "logstash/inputs/http/tls"
29
+
30
+ java_import "io.netty.handler.codec.http.HttpUtil"
31
+
32
+ config_name "http"
33
+
34
+ # Codec used to decode the incoming data.
35
+ # This codec will be used as a fall-back if the content-type
36
+ # is not found in the "additional_codecs" hash
37
+ default :codec, "plain"
38
+
39
+ # The host or ip to bind
40
+ config :host, :validate => :string, :default => "0.0.0.0"
41
+
42
+ # The TCP port to bind to
43
+ config :port, :validate => :number, :default => 8080
44
+
45
+ # Username for basic authorization
46
+ config :user, :validate => :string, :required => false
47
+
48
+ # Password for basic authorization
49
+ config :password, :validate => :password, :required => false
50
+
51
+ # Events are by default sent in plain text. You can
52
+ # enable encryption by setting `ssl` to true and configuring
53
+ # the `ssl_certificate` and `ssl_key` options.
54
+ config :ssl, :validate => :boolean, :default => false
55
+
56
+ # SSL certificate to use.
57
+ config :ssl_certificate, :validate => :path
58
+
59
+ # SSL key to use.
60
+ # NOTE: This key need to be in the PKCS8 format, you can convert it with https://www.openssl.org/docs/man1.1.0/apps/pkcs8.html[OpenSSL]
61
+ # for more information.
62
+ config :ssl_key, :validate => :path
63
+
64
+ # SSL key passphrase to use.
65
+ config :ssl_key_passphrase, :validate => :password
66
+
67
+ # Validate client certificates against these authorities.
68
+ # You can define multiple files or paths. All the certificates will
69
+ # be read and added to the trust store. You need to configure the `ssl_verify_mode`
70
+ # to `peer` or `force_peer` to enable the verification.
71
+ config :ssl_certificate_authorities, :validate => :array, :default => []
72
+
73
+ # By default the server doesn't do any client verification.
74
+ #
75
+ # `peer` will make the server ask the client to provide a certificate.
76
+ # If the client provides a certificate, it will be validated.
77
+ #
78
+ # `force_peer` will make the server ask the client to provide a certificate.
79
+ # If the client doesn't provide a certificate, the connection will be closed.
80
+ #
81
+ # This option needs to be used with `ssl_certificate_authorities` and a defined list of CAs.
82
+ config :ssl_verify_mode, :validate => ["none", "peer", "force_peer"], :default => "none"
83
+
84
+ # Time in milliseconds for an incomplete ssl handshake to timeout
85
+ config :ssl_handshake_timeout, :validate => :number, :default => 10000
86
+
87
+ # The minimum TLS version allowed for the encrypted connections. The value must be one of the following:
88
+ # 1.0 for TLS 1.0, 1.1 for TLS 1.1, 1.2 for TLS 1.2
89
+ config :tls_min_version, :validate => :number, :default => TLS.min.version
90
+
91
+ # The maximum TLS version allowed for the encrypted connections. The value must be the one of the following:
92
+ # 1.0 for TLS 1.0, 1.1 for TLS 1.1, 1.2 for TLS 1.2
93
+ config :tls_max_version, :validate => :number, :default => TLS.max.version
94
+
95
+ # The list of ciphers suite to use, listed by priorities.
96
+ config :cipher_suites, :validate => :array, :default => org.logstash.plugins.inputs.http.util.SslSimpleBuilder.getDefaultCiphers
97
+
98
+ # Apply specific codecs for specific content types.
99
+ # The default codec will be applied only after this list is checked
100
+ # and no codec for the request's content-type is found
101
+ config :additional_codecs, :validate => :hash, :default => { "application/json" => "json" }
102
+
103
+ # specify a custom set of response headers
104
+ config :response_headers, :validate => :hash, :default => { 'Content-Type' => 'text/plain' }
105
+
106
+ # target field for the client host of the http request
107
+ config :remote_host_target_field, :validate => :string, :default => "host"
108
+
109
+ # target field for the client host of the http request
110
+ config :request_headers_target_field, :validate => :string, :default => "headers"
111
+
112
+ config :threads, :validate => :number, :required => false, :default => ::LogStash::Config::CpuCoreStrategy.maximum
113
+
114
+ config :max_pending_requests, :validate => :number, :required => false, :default => 200
115
+
116
+ config :max_content_length, :validate => :number, :required => false, :default => 100 * 1024 * 1024
117
+
118
+ config :response_code, :validate => [200, 201, 202, 204], :default => 200
119
+ # Deprecated options
120
+
121
+ # The JKS keystore to validate the client's certificates
122
+ config :keystore, :validate => :path, :deprecated => "Set 'ssl_certificate' and 'ssl_key' instead."
123
+ config :keystore_password, :validate => :password, :deprecated => "Set 'ssl_key_passphrase' instead."
124
+
125
+ config :verify_mode, :validate => ['none', 'peer', 'force_peer'], :default => 'none',
126
+ :deprecated => "Set 'ssl_verify_mode' instead."
127
+
128
+ public
129
+ def register
130
+
131
+ validate_ssl_settings!
132
+
133
+ if @user && @password then
134
+ token = Base64.strict_encode64("#{@user}:#{@password.value}")
135
+ @auth_token = "Basic #{token}"
136
+ end
137
+
138
+ @codecs = Hash.new
139
+
140
+ @additional_codecs.each do |content_type, codec|
141
+ @codecs[content_type] = LogStash::Plugin.lookup("codec", codec).new
142
+ end
143
+
144
+ require "logstash/inputs/http/message_handler"
145
+ message_handler = MessageHandler.new(self, @codec, @codecs, @auth_token)
146
+ @http_server = create_http_server(message_handler)
147
+ end # def register
148
+
149
+ def run(queue)
150
+ @queue = queue
151
+ @logger.info("Starting http input listener", :address => "#{@host}:#{@port}", :ssl => "#{@ssl}")
152
+ @http_server.run()
153
+ end
154
+
155
+ def stop
156
+ @http_server.close() rescue nil
157
+ end
158
+
159
+ def close
160
+ @http_server.close() rescue nil
161
+ end
162
+
163
+ def decode_body(headers, remote_address, body, default_codec, additional_codecs)
164
+ content_type = headers.fetch("content_type", "")
165
+ codec = additional_codecs.fetch(HttpUtil.getMimeType(content_type), default_codec)
166
+ codec.decode(body) { |event| push_decoded_event(headers, remote_address, event) }
167
+ codec.flush { |event| push_decoded_event(headers, remote_address, event) }
168
+ true
169
+ rescue => e
170
+ @logger.error(
171
+ "unable to process event.",
172
+ :message => e.message,
173
+ :class => e.class.name,
174
+ :backtrace => e.backtrace
175
+ )
176
+ false
177
+ end
178
+
179
+ def push_decoded_event(headers, remote_address, event)
180
+ event.set(@request_headers_target_field, headers)
181
+ event.set(@remote_host_target_field, remote_address)
182
+ decorate(event)
183
+ @queue << event
184
+ end
185
+
186
+ def validate_ssl_settings!
187
+ if !@ssl
188
+ @logger.warn("SSL Certificate will not be used") if @ssl_certificate
189
+ @logger.warn("SSL Key will not be used") if @ssl_key
190
+ @logger.warn("SSL Java Key Store will not be used") if @keystore
191
+ elsif !(ssl_key_configured? || ssl_jks_configured?)
192
+ raise LogStash::ConfigurationError, "Certificate or JKS must be configured"
193
+ end
194
+
195
+ if @ssl && (original_params.key?("verify_mode") && original_params.key?("ssl_verify_mode"))
196
+ raise LogStash::ConfigurationError, "Both 'ssl_verify_mode' and 'verify_mode' were set. Use only 'ssl_verify_mode'."
197
+ elsif original_params.key?("verify_mode")
198
+ @ssl_verify_mode_final = @verify_mode
199
+ elsif original_params.key?("ssl_verify_mode")
200
+ @ssl_verify_mode_final = @ssl_verify_mode
201
+ else
202
+ @ssl_verify_mode_final = @ssl_verify_mode
203
+ end
204
+
205
+ if @ssl && require_certificate_authorities? && !client_authentication?
206
+ raise LogStash::ConfigurationError, "Using `ssl_verify_mode` or `verify_mode` set to PEER or FORCE_PEER, requires the configuration of `ssl_certificate_authorities`"
207
+ elsif @ssl && !require_certificate_authorities? && client_authentication?
208
+ raise LogStash::ConfigurationError, "The configuration of `ssl_certificate_authorities` requires setting `ssl_verify_mode` or `verify_mode` to PEER or FORCE_PEER"
209
+ end
210
+ end
211
+
212
+ def create_http_server(message_handler)
213
+ org.logstash.plugins.inputs.http.NettyHttpServer.new(
214
+ @host, @port, message_handler, build_ssl_params(), @threads, @max_pending_requests, @max_content_length, @response_code)
215
+ end
216
+
217
+ def build_ssl_params
218
+ return nil unless @ssl
219
+
220
+ if @keystore && @keystore_password
221
+ ssl_builder = org.logstash.plugins.inputs.http.util.JksSslBuilder.new(@keystore, @keystore_password.value)
222
+ else
223
+ begin
224
+ ssl_builder = org.logstash.plugins.inputs.http.util.SslSimpleBuilder
225
+ .new(@ssl_certificate, @ssl_key, @ssl_key_passphrase.nil? ? nil : @ssl_key_passphrase.value)
226
+ .setCipherSuites(normalized_ciphers)
227
+ rescue java.lang.IllegalArgumentException => e
228
+ @logger.error("SSL configuration invalid", error_details(e))
229
+ raise LogStash::ConfigurationError, e
230
+ end
231
+
232
+ if client_authentication?
233
+ ssl_builder.setCertificateAuthorities(@ssl_certificate_authorities)
234
+ end
235
+ end
236
+
237
+ new_ssl_handshake_provider(ssl_builder)
238
+ end
239
+
240
+ def ssl_key_configured?
241
+ !!(@ssl_certificate && @ssl_key)
242
+ end
243
+
244
+ def ssl_jks_configured?
245
+ !!(@keystore && @keystore_password)
246
+ end
247
+
248
+ def client_authentication?
249
+ @ssl_certificate_authorities && @ssl_certificate_authorities.size > 0
250
+ end
251
+
252
+ def require_certificate_authorities?
253
+ @ssl_verify_mode_final == "force_peer" || @ssl_verify_mode_final == "peer"
254
+ end
255
+
256
+ private
257
+
258
+ def normalized_ciphers
259
+ @cipher_suites.map(&:upcase)
260
+ end
261
+
262
+ def convert_protocols
263
+ TLS.get_supported(@tls_min_version..@tls_max_version).map(&:name)
264
+ end
265
+
266
+ def new_ssl_handshake_provider(ssl_builder)
267
+ begin
268
+ ssl_handler_provider = org.logstash.plugins.inputs.http.util.SslHandlerProvider.new(ssl_builder.build())
269
+ ssl_handler_provider.setVerifyMode(@ssl_verify_mode_final.upcase)
270
+ ssl_handler_provider.setProtocols(convert_protocols)
271
+ ssl_handler_provider.setHandshakeTimeoutMilliseconds(@ssl_handshake_timeout)
272
+ ssl_handler_provider
273
+ rescue java.lang.IllegalArgumentException => e
274
+ @logger.error("SSL configuration invalid", error_details(e))
275
+ raise LogStash::ConfigurationError, e
276
+ rescue java.lang.Exception => e
277
+ @logger.error("SSL configuration failed", error_details(e, true))
278
+ raise e
279
+ end
280
+ end
281
+
282
+ def error_details(e, trace = false)
283
+ error_details = { :exception => e.class, :message => e.message }
284
+ error_details[:backtrace] = e.backtrace if trace || @logger.debug?
285
+ cause = e.cause
286
+ if cause && e != cause
287
+ error_details[:cause] = { :exception => cause.class, :message => cause.message }
288
+ error_details[:cause][:backtrace] = cause.backtrace if trace || @logger.debug?
289
+ end
290
+ error_details
291
+ end
292
+
293
+ end # class LogStash::Inputs::Http
@@ -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,6 @@
1
+ # AUTOGENERATED BY THE GRADLE SCRIPT. DO NOT EDIT.
2
+
3
+ require 'jar_dependencies'
4
+ require_jar('io.netty', 'netty-all', '4.1.49.Final')
5
+ require_jar('org.apache.logging.log4j', 'log4j-api', '2.11.1')
6
+ require_jar('org.logstash.plugins.input.http', 'logstash-input-http', '3.3.7')
@@ -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 = 'sp-logstash-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