logstash-output-http_auth 0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 183a95d1df45ea65b0402888c9a74258dac4d849
4
+ data.tar.gz: 53ec525af25f06370ec2e062dac4e41abd152425
5
+ SHA512:
6
+ metadata.gz: e288eb3dfe9e7363a1f09a9574c8725e36acfb59b6c7077a62933932649df500d32712a4af09aa783aec981b93170f3601af51f985c6b2d4d1404fadb416265c
7
+ data.tar.gz: 65731cca9d4e0d1c1201a115bebc0611df49f825a2f4f50f8207c8b7b68e70bd9c43e3a406ed1453f8a2b1a09c3583a6985a15f5a0b47d7641a9ff71c83e3fd8
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ Gemfile.lock
2
+ .ruby-version
3
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2012-2014 Elasticsearch <http://www.elasticsearch.org>
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ @files=[]
2
+
3
+ task :default do
4
+ system("rake -T")
5
+ end
6
+
7
+ require "logstash/devutils/rake"
@@ -0,0 +1,239 @@
1
+ # encoding: utf-8
2
+ require "logstash/outputs/base"
3
+ require "logstash/namespace"
4
+ require "logstash/json"
5
+
6
+ class LogStash::Outputs::HttpAuth < LogStash::Outputs::Base
7
+ # This output lets you `PUT` or `POST` events to a
8
+ # generic HTTP(S) endpoint
9
+ #
10
+ # Additionally, you are given the option to customize
11
+ # the headers sent as well as basic customization of the
12
+ # event json itself.
13
+ #
14
+ # In addition to default http-plugin, you need 2 way authentication
15
+ # with csrf_token verification? This is you plugin!
16
+
17
+ config_name "http_auth"
18
+
19
+ # If sign in is desired
20
+ config :sign_in, :validate => :boolean, :default => false
21
+
22
+ # Params to be sent within the body
23
+ config :sign_in_params, :validate => :hash
24
+
25
+ # Host-address of the server
26
+ config :host, :validate => :string
27
+
28
+ # Port of the server
29
+ config :port, :validate => :number
30
+
31
+ # Root path of the application to get the csrf-cookie
32
+ config :root_path, :validate => :string, :default => "/"
33
+
34
+ # Path of the action to be called
35
+ config :path, :validate => :string
36
+
37
+ # Sign-In path of the application to be authenticated
38
+ config :sign_in_path, :validate => :string, :default => "/users/sign_in"
39
+
40
+ # URL to use
41
+ config :url, :validate => :string
42
+
43
+ # validate SSL?
44
+ config :verify_ssl, :validate => :boolean, :default => true
45
+
46
+ # What verb to use
47
+ # only put and post are supported for now
48
+ config :http_method, :validate => ["put", "post"], :required => :true
49
+
50
+ # Custom headers to use
51
+ # format is `headers => ["X-My-Header", "%{host}"]
52
+ config :headers, :validate => :hash
53
+
54
+ # Content type
55
+ #
56
+ # If not specified, this defaults to the following:
57
+ #
58
+ # * if format is "json", "application/json"
59
+ # * if format is "form", "application/x-www-form-urlencoded"
60
+ config :content_type, :validate => :string
61
+
62
+ # This lets you choose the structure and parts of the event that are sent.
63
+ #
64
+ #
65
+ # For example:
66
+ #
67
+ # mapping => ["foo", "%{host}", "bar", "%{type}"]
68
+ config :mapping, :validate => :hash
69
+
70
+ # Set the format of the http body.
71
+ #
72
+ # If form, then the body will be the mapping (or whole event) converted
73
+ # into a query parameter string (foo=bar&baz=fizz...)
74
+ #
75
+ # If message, then the body will be the result of formatting the event according to message
76
+ #
77
+ # Otherwise, the event is sent as json.
78
+ config :format, :validate => ["json", "form", "message"], :default => "json"
79
+
80
+ config :message, :validate => :string
81
+
82
+ public
83
+ def register
84
+ require "ftw"
85
+ require "uri"
86
+ @agent = FTW::Agent.new
87
+
88
+ if @content_type.nil?
89
+ case @format
90
+ when "form" ; @content_type = "application/x-www-form-urlencoded"
91
+ when "json" ; @content_type = "application/json"
92
+ end
93
+ end
94
+
95
+ if @format == "message"
96
+ if @message.nil?
97
+ raise "message must be set if message format is used"
98
+ end
99
+ if @content_type.nil?
100
+ raise "content_type must be set if message format is used"
101
+ end
102
+ unless @mapping.nil?
103
+ @logger.warn "mapping is not supported and will be ignored if message format is used"
104
+ end
105
+ end
106
+
107
+ @signed_in = false
108
+ @csrf_token = nil
109
+ @cookies = nil
110
+ end # def register
111
+
112
+ public
113
+ def receive(event)
114
+ return unless output?(event)
115
+
116
+ sign_in() if @sign_in
117
+
118
+ if @mapping
119
+ evt = Hash.new
120
+ @mapping.each do |k,v|
121
+ evt[k] = event.sprintf(v)
122
+ end
123
+ else
124
+ evt = event.to_hash
125
+ end
126
+
127
+ @url = URI::HTTP.build({:host => @host, :port=> @port, :path => @path}) if @url.nil?
128
+
129
+ case @http_method
130
+ when "put"
131
+ request = @agent.put(event.sprintf(@url))
132
+ when "post"
133
+ request = @agent.post(event.sprintf(@url))
134
+ else
135
+ @logger.error("Unknown verb:", :verb => @http_method)
136
+ end
137
+
138
+ if @headers
139
+ @headers.each do |k,v|
140
+ request.headers[k] = event.sprintf(v)
141
+ end
142
+ end
143
+
144
+ request["Content-Type"] = @content_type
145
+
146
+ set_header(request)
147
+
148
+ begin
149
+ if @format == "json"
150
+ request.body = evt.to_json
151
+ elsif @format == "message"
152
+ request.body = event.sprintf(@message)
153
+ else
154
+ request.body = encode(evt)
155
+ end
156
+
157
+ response = @agent.execute(request)
158
+
159
+ @signed_in = status_success?(response.status)
160
+
161
+ @logger.warn("Response Status #{response.status} for request #{@http_method} to #{@url}") if !status_success?(response.status)
162
+
163
+ rescue Exception => e
164
+ @logger.warn("Unhandled exception", :request => request, :response => response, :exception => e, :stacktrace => e.backtrace)
165
+ end
166
+ end # def receive
167
+
168
+ private
169
+ def encode(hash)
170
+ return hash.collect do |key, value|
171
+ CGI.escape(key) + "=" + CGI.escape(value)
172
+ end.join("&")
173
+ end # def encode
174
+
175
+ def set_cookies(response)
176
+ set_cookie = response.headers['set-cookie']
177
+
178
+ if(!set_cookie.nil? && !set_cookie.empty?)
179
+ cookies = []
180
+ set_cookie.each do |c|
181
+ cookie = c.split('; ')[0]
182
+
183
+ @csrf_token = CGI.unescape(cookie.split('=')[1]) if cookie.start_with?('XSRF-TOKEN')
184
+
185
+ cookies << cookie
186
+ end
187
+ @cookies = cookies.join('; ') if !cookies.empty?
188
+ end
189
+ end
190
+
191
+ def sign_in
192
+ if(!@signed_in)
193
+ if(@cookies.nil?)
194
+ request = @agent.get(
195
+ URI::HTTP.build({:host => @host, :port=> @port, :path => @root_path})
196
+ )
197
+ request["Content-Type"] = @content_type
198
+ response = @agent.execute(request)
199
+
200
+ set_cookies(response)
201
+ end
202
+
203
+ request = @agent.post(
204
+ URI::HTTP.build({:host => @host, :port=> @port, :path => @sign_in_path})
205
+ )
206
+ request["Content-Type"] = @content_type
207
+
208
+ set_header(request)
209
+
210
+ body = Hash.new
211
+ @sign_in_params.each do |k,v|
212
+ body[k] = v
213
+ end
214
+
215
+ request.body = body.to_json
216
+
217
+ response = @agent.execute(request)
218
+
219
+ set_cookies(response)
220
+
221
+ # status 2xx success
222
+ @signed_in = status_success?(response.status)
223
+ end
224
+ end
225
+
226
+ def set_header(request)
227
+ request.headers['Cookie'] = @cookies if !@cookies.nil?
228
+
229
+ if !@csrf_token.nil?
230
+ request.headers['X-Requested-With'] = 'XMLHttpRequest'
231
+ request.headers['X-CSRF-Token'] = @csrf_token
232
+ request.headers['X-XSRF-Token'] = @csrf_token
233
+ end
234
+ end
235
+
236
+ def status_success?(status)
237
+ status >= 200 && status < 300
238
+ end
239
+ end
@@ -0,0 +1,29 @@
1
+ Gem::Specification.new do |s|
2
+
3
+ s.name = 'logstash-output-http_auth'
4
+ s.version = '0.1.0'
5
+ s.licenses = ['Apache License (2.0)']
6
+ s.summary = "This output lets you `PUT` or `POST` events to a generic HTTP(S) endpoint with 2 way authentication"
7
+ s.description = "This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not a stand-alone program"
8
+ s.authors = ["Signify"]
9
+ s.email = 'dietmar@signifydata.com'
10
+ s.homepage = "http://www.signifydata.com"
11
+ s.require_paths = ["lib"]
12
+
13
+ # Files
14
+ s.files = `git ls-files`.split($\)+::Dir.glob('vendor/*')
15
+
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" => "output" }
21
+
22
+ # Gem dependencies
23
+ s.add_runtime_dependency 'logstash-core', '>= 1.4.0', '< 2.0.0'
24
+
25
+ s.add_runtime_dependency 'ftw', ['~> 0.0.40']
26
+
27
+ s.add_development_dependency 'logstash-devutils'
28
+ end
29
+
@@ -0,0 +1,5 @@
1
+ require "logstash/devutils/rspec/spec_helper"
2
+ require 'logstash/outputs/http_auth'
3
+
4
+ describe LogStash::Outputs::HttpAuth do
5
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: logstash-output-http_auth
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Signify
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-08-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - '>='
17
+ - !ruby/object:Gem::Version
18
+ version: 1.4.0
19
+ - - <
20
+ - !ruby/object:Gem::Version
21
+ version: 2.0.0
22
+ name: logstash-core
23
+ prerelease: false
24
+ type: :runtime
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.4.0
30
+ - - <
31
+ - !ruby/object:Gem::Version
32
+ version: 2.0.0
33
+ - !ruby/object:Gem::Dependency
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ~>
37
+ - !ruby/object:Gem::Version
38
+ version: 0.0.40
39
+ name: ftw
40
+ prerelease: false
41
+ type: :runtime
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: 0.0.40
47
+ - !ruby/object:Gem::Dependency
48
+ requirement: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ name: logstash-devutils
54
+ prerelease: false
55
+ type: :development
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ description: This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not a stand-alone program
62
+ email: dietmar@signifydata.com
63
+ executables: []
64
+ extensions: []
65
+ extra_rdoc_files: []
66
+ files:
67
+ - .gitignore
68
+ - Gemfile
69
+ - LICENSE
70
+ - Rakefile
71
+ - lib/logstash/outputs/http_auth.rb
72
+ - logstash-output-http_auth.gemspec
73
+ - spec/outputs/http_auth_spec.rb
74
+ homepage: http://www.signifydata.com
75
+ licenses:
76
+ - Apache License (2.0)
77
+ metadata:
78
+ logstash_plugin: 'true'
79
+ logstash_group: output
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 2.1.9
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: This output lets you `PUT` or `POST` events to a generic HTTP(S) endpoint with 2 way authentication
100
+ test_files:
101
+ - spec/outputs/http_auth_spec.rb