sp-logstash-input-http 3.3.7-java

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