logstash-filter-fingerprint 3.2.4 → 3.3.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 +4 -4
- data/CHANGELOG.md +3 -0
- data/docs/index.asciidoc +31 -2
- data/lib/logstash/filters/fingerprint.rb +9 -1
- data/logstash-filter-fingerprint.gemspec +2 -1
- data/spec/filters/fingerprint_spec.rb +213 -208
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0a14dcbc1585cf2f6afea7bed7a0e056d2f098bc896dc6d7571caf3c5cc3c51d
|
4
|
+
data.tar.gz: 2c7714afaaee24b9a8995d541ffa1cab5d16dc907dd3d1e98213d7b218fb0ebf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cbaccf02918c11b39f2f1f7bc78d7a16fbbac76d7bef9edebcb907f89cba98126708c07c05497d1e1cd5862e1846bb37b5779aaa51937382d8f416264f111328
|
7
|
+
data.tar.gz: 2df22689f778872a0cd85e000ff8ef940e7a16dfec4c469c4a846e7457e599e887768d3d26bd630af0af45ae0b6740cd800d3b2d89cd08bdb08f76124cad1d2b
|
data/CHANGELOG.md
CHANGED
data/docs/index.asciidoc
CHANGED
@@ -27,11 +27,26 @@ You can use this plugin to create consistent document ids when events are
|
|
27
27
|
inserted into Elasticsearch. This approach means that existing documents can be
|
28
28
|
updated instead of creating new documents.
|
29
29
|
|
30
|
-
NOTE: When the `
|
30
|
+
NOTE: When the `method` option is set to `UUID` the result won't be
|
31
31
|
a consistent hash but a random
|
32
32
|
https://en.wikipedia.org/wiki/Universally_unique_identifier[UUID].
|
33
33
|
To generate UUIDs, prefer the {logstash-ref}/plugins-filters-uuid.html[uuid filter].
|
34
34
|
|
35
|
+
[id="plugins-{type}s-{plugin}-ecs_metadata"]
|
36
|
+
==== Event Metadata and the Elastic Common Schema (ECS)
|
37
|
+
This plugin adds a hash value to event as an identifier. You can configure the `target` option to change the output field.
|
38
|
+
|
39
|
+
When ECS compatibility is disabled, the hash value is stored in the `fingerprint` field.
|
40
|
+
When ECS is enabled, the value is stored in the `[event][hash]` field.
|
41
|
+
|
42
|
+
Here’s how ECS compatibility mode affects output.
|
43
|
+
[cols="<l,<l,e,<e"]
|
44
|
+
|=======================================================================
|
45
|
+
| ECS disabled | ECS v1 | Availability | Description
|
46
|
+
|
47
|
+
| fingerprint | [event][hash] | Always | a hash value of event
|
48
|
+
|=======================================================================
|
49
|
+
|
35
50
|
[id="plugins-{type}s-{plugin}-options"]
|
36
51
|
==== Fingerprint Filter Configuration Options
|
37
52
|
|
@@ -43,6 +58,7 @@ This plugin supports the following configuration options plus the <<plugins-{typ
|
|
43
58
|
| <<plugins-{type}s-{plugin}-base64encode>> |<<boolean,boolean>>|No
|
44
59
|
| <<plugins-{type}s-{plugin}-concatenate_sources>> |<<boolean,boolean>>|No
|
45
60
|
| <<plugins-{type}s-{plugin}-concatenate_all_fields>> |<<boolean,boolean>>|No
|
61
|
+
| <<plugins-{type}s-{plugin}-ecs_compatibility>> | <<string,string>>|No
|
46
62
|
| <<plugins-{type}s-{plugin}-key>> |<<string,string>>|No
|
47
63
|
| <<plugins-{type}s-{plugin}-method>> |<<string,string>>, one of `["SHA1", "SHA256", "SHA384", "SHA512", "MD5", "MURMUR3", "IPV4_NETWORK", "UUID", "PUNCTUATION"]`|Yes
|
48
64
|
| <<plugins-{type}s-{plugin}-source>> |<<array,array>>|No
|
@@ -133,6 +149,18 @@ fingerprint computation. If `false` and at least one source field is
|
|
133
149
|
given, the target field will be an array with fingerprints of the
|
134
150
|
source fields given.
|
135
151
|
|
152
|
+
[id="plugins-{type}s-{plugin}-ecs_compatibility"]
|
153
|
+
===== `ecs_compatibility`
|
154
|
+
|
155
|
+
* Value type is <<string,string>>
|
156
|
+
* Supported values are:
|
157
|
+
** `disabled`: unstructured data added at root level
|
158
|
+
** `v1`: uses `[event][hash]` fields that are compatible with Elastic Common Schema
|
159
|
+
|
160
|
+
Controls this plugin's compatibility with the
|
161
|
+
{ecs-ref}[Elastic Common Schema (ECS)].
|
162
|
+
See <<plugins-{type}s-{plugin}-ecs_metadata>> for detailed information.
|
163
|
+
|
136
164
|
[id="plugins-{type}s-{plugin}-key"]
|
137
165
|
===== `key`
|
138
166
|
|
@@ -184,7 +212,8 @@ to create the fingerprint. If an array is given, see the
|
|
184
212
|
===== `target`
|
185
213
|
|
186
214
|
* Value type is <<string,string>>
|
187
|
-
* Default value is `"fingerprint"`
|
215
|
+
* Default value is `"fingerprint"` when ECS is disabled
|
216
|
+
* Default value is `"[event][hash]"` when ECS is enabled
|
188
217
|
|
189
218
|
The name of the field where the generated fingerprint will be stored.
|
190
219
|
Any current contents of that field will be overwritten.
|
@@ -6,6 +6,7 @@ require "openssl"
|
|
6
6
|
require "ipaddr"
|
7
7
|
require "murmurhash3"
|
8
8
|
require "securerandom"
|
9
|
+
require "logstash/plugin_mixins/ecs_compatibility_support"
|
9
10
|
|
10
11
|
# Create consistent hashes (fingerprints) of one or more fields and store
|
11
12
|
# the result in a new field.
|
@@ -22,6 +23,8 @@ require "securerandom"
|
|
22
23
|
# https://en.wikipedia.org/wiki/Universally_unique_identifier[UUID].
|
23
24
|
# To generate UUIDs, prefer the <<plugins-filters-uuid,uuid filter>>.
|
24
25
|
class LogStash::Filters::Fingerprint < LogStash::Filters::Base
|
26
|
+
include LogStash::PluginMixins::ECSCompatibilitySupport(:disabled, :v1, :v8 => :v1)
|
27
|
+
|
25
28
|
config_name "fingerprint"
|
26
29
|
|
27
30
|
# The name(s) of the source field(s) whose contents will be used
|
@@ -31,7 +34,7 @@ class LogStash::Filters::Fingerprint < LogStash::Filters::Base
|
|
31
34
|
|
32
35
|
# The name of the field where the generated fingerprint will be stored.
|
33
36
|
# Any current contents of that field will be overwritten.
|
34
|
-
config :target, :validate => :string
|
37
|
+
config :target, :validate => :string
|
35
38
|
|
36
39
|
# When used with the `IPV4_NETWORK` method fill in the subnet prefix length.
|
37
40
|
# With other methods, optionally fill in the HMAC key.
|
@@ -76,6 +79,11 @@ class LogStash::Filters::Fingerprint < LogStash::Filters::Base
|
|
76
79
|
# without having to proide the field names in the `source` attribute
|
77
80
|
config :concatenate_all_fields, :validate => :boolean, :default => false
|
78
81
|
|
82
|
+
def initialize(*params)
|
83
|
+
super
|
84
|
+
@target ||= ecs_select[disabled: 'fingerprint', v1: '[event][hash]']
|
85
|
+
end
|
86
|
+
|
79
87
|
def register
|
80
88
|
# convert to symbol for faster comparisons
|
81
89
|
@method = @method.to_sym
|
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
|
3
3
|
s.name = 'logstash-filter-fingerprint'
|
4
|
-
s.version = '3.
|
4
|
+
s.version = '3.3.0'
|
5
5
|
s.licenses = ['Apache-2.0']
|
6
6
|
s.summary = "Fingerprints fields by replacing values with a consistent hash"
|
7
7
|
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"
|
@@ -23,5 +23,6 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
|
24
24
|
s.add_runtime_dependency "murmurhash3" #(MIT license)
|
25
25
|
s.add_development_dependency 'logstash-devutils'
|
26
|
+
s.add_runtime_dependency 'logstash-mixin-ecs_compatibility_support', '~>1.2'
|
26
27
|
end
|
27
28
|
|
@@ -1,297 +1,302 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require "logstash/devutils/rspec/spec_helper"
|
3
3
|
require "logstash/filters/fingerprint"
|
4
|
+
require 'logstash/plugin_mixins/ecs_compatibility_support/spec_helper'
|
4
5
|
|
5
|
-
describe LogStash::Filters::Fingerprint do
|
6
|
+
describe LogStash::Filters::Fingerprint, :ecs_compatibility_support, :aggregate_failures do
|
7
|
+
ecs_compatibility_matrix(:disabled, :v1, :v8 => :v1) do |ecs_select|
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
let(:plugin) { described_class.new(config) }
|
10
|
+
let(:config) { { "method" => fingerprint_method } }
|
11
|
+
let(:fingerprint_method) { "SHA1" } # default
|
12
|
+
let(:data) { {} }
|
13
|
+
let(:event) { LogStash::Event.new(data) }
|
14
|
+
let(:fingerprint) { event.get(ecs_select[disabled: "fingerprint", v1: "[event][hash]"]) }
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
16
|
+
before(:each) do
|
17
|
+
allow_any_instance_of(described_class).to receive(:ecs_compatibility).and_return(ecs_compatibility)
|
18
|
+
plugin.register
|
19
|
+
plugin.filter(event)
|
20
|
+
end
|
18
21
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
+
context "with a string field" do
|
23
|
+
let(:data) { {"clientip" => "123.123.123.123" } }
|
24
|
+
let(:config) { super().merge("source" => ["clientip" ]) }
|
22
25
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
+
describe "the IPV4_NETWORK method" do
|
27
|
+
let(:fingerprint_method) { "IPV4_NETWORK" }
|
28
|
+
let(:config) { super().merge("key" => 24) }
|
26
29
|
|
27
|
-
|
28
|
-
|
30
|
+
it "fingerprints the ip as the network" do
|
31
|
+
expect(fingerprint).to eq("123.123.123.0")
|
32
|
+
end
|
29
33
|
end
|
30
|
-
end
|
31
34
|
|
32
|
-
|
33
|
-
|
35
|
+
describe "the MURMUR3 method" do
|
36
|
+
let(:fingerprint_method) { "MURMUR3" }
|
34
37
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
+
context "string" do
|
39
|
+
it "fingerprints the value" do
|
40
|
+
expect(fingerprint).to eq(4013733395)
|
41
|
+
end
|
38
42
|
end
|
39
|
-
end
|
40
43
|
|
41
|
-
|
42
|
-
|
44
|
+
context "number" do
|
45
|
+
let(:data) { {"clientip" => 123 } }
|
43
46
|
|
44
|
-
|
45
|
-
|
47
|
+
it "fingerprints the value" do
|
48
|
+
expect(fingerprint).to eq(823512154)
|
49
|
+
end
|
46
50
|
end
|
47
51
|
end
|
48
|
-
end
|
49
52
|
|
50
|
-
|
51
|
-
|
53
|
+
describe "the SHA1 method" do
|
54
|
+
let(:fingerprint_method) { "SHA1" }
|
52
55
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
+
it "fingerprints the value" do
|
57
|
+
expect(fingerprint).to eq("3a5076c520b4b463f43806896ea0b3978d09dcae")
|
58
|
+
end
|
56
59
|
|
57
|
-
|
58
|
-
|
60
|
+
context "with HMAC" do
|
61
|
+
let(:config) { super().merge("key" => "longencryptionkey") }
|
59
62
|
|
60
|
-
|
61
|
-
|
63
|
+
it "fingerprints the value" do
|
64
|
+
expect(fingerprint).to eq("fdc60acc4773dc5ac569ffb78fcb93c9630797f4")
|
65
|
+
end
|
66
|
+
context "with HMAC and base64 encoding" do
|
67
|
+
let(:config) { super().merge("base64encode" => true) }
|
68
|
+
it "fingerprints the value" do
|
69
|
+
expect(fingerprint).to eq("/cYKzEdz3FrFaf+3j8uTyWMHl/Q=")
|
70
|
+
end
|
71
|
+
end
|
62
72
|
end
|
63
|
-
context "
|
73
|
+
context "and base64 encoding" do
|
64
74
|
let(:config) { super().merge("base64encode" => true) }
|
65
75
|
it "fingerprints the value" do
|
66
|
-
expect(fingerprint).to eq("
|
76
|
+
expect(fingerprint).to eq("OlB2xSC0tGP0OAaJbqCzl40J3K4=")
|
67
77
|
end
|
68
78
|
end
|
69
79
|
end
|
70
|
-
context "and base64 encoding" do
|
71
|
-
let(:config) { super().merge("base64encode" => true) }
|
72
|
-
it "fingerprints the value" do
|
73
|
-
expect(fingerprint).to eq("OlB2xSC0tGP0OAaJbqCzl40J3K4=")
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
80
|
|
78
|
-
|
79
|
-
|
80
|
-
it "fingerprints the value" do
|
81
|
-
expect(fingerprint).to eq("4dabcab210766e35f03e77120e6986d6e6d4752b2a9ff22980b9253d026080d8")
|
82
|
-
end
|
83
|
-
context "with HMAC" do
|
84
|
-
let(:config) { super().merge("key" => "longencryptionkey") }
|
81
|
+
context "the SHA256 algorithm" do
|
82
|
+
let(:fingerprint_method) { "SHA256" }
|
85
83
|
it "fingerprints the value" do
|
86
|
-
expect(fingerprint).to eq("
|
84
|
+
expect(fingerprint).to eq("4dabcab210766e35f03e77120e6986d6e6d4752b2a9ff22980b9253d026080d8")
|
87
85
|
end
|
88
|
-
context "
|
89
|
-
let(:config) { super().merge("
|
86
|
+
context "with HMAC" do
|
87
|
+
let(:config) { super().merge("key" => "longencryptionkey") }
|
90
88
|
it "fingerprints the value" do
|
91
|
-
expect(fingerprint).to eq("
|
89
|
+
expect(fingerprint).to eq("345bec3eff242d53b568916c2610b3e393d885d6b96d643f38494fd74bf4a9ca")
|
90
|
+
end
|
91
|
+
context "and base64 encoding" do
|
92
|
+
let(:config) { super().merge("base64encode" => true) }
|
93
|
+
it "fingerprints the value" do
|
94
|
+
expect(fingerprint).to eq("NFvsPv8kLVO1aJFsJhCz45PYhda5bWQ/OElP10v0qco=")
|
95
|
+
end
|
92
96
|
end
|
93
97
|
end
|
94
98
|
end
|
95
|
-
end
|
96
99
|
|
97
|
-
|
98
|
-
|
99
|
-
it "fingerprints the value" do
|
100
|
-
expect(fingerprint).to eq("fd605b0a3af3e04ce0d7a0b0d9c48d67a12dab811f60072e6eae84e35d567793ffb68a1807536f11c90874065c2a4392")
|
101
|
-
end
|
102
|
-
context "with HMAC" do
|
103
|
-
let(:config) { super().merge("key" => "longencryptionkey") }
|
100
|
+
context "the SHA384 algorithm" do
|
101
|
+
let(:fingerprint_method) { "SHA384" }
|
104
102
|
it "fingerprints the value" do
|
105
|
-
expect(fingerprint).to eq("
|
103
|
+
expect(fingerprint).to eq("fd605b0a3af3e04ce0d7a0b0d9c48d67a12dab811f60072e6eae84e35d567793ffb68a1807536f11c90874065c2a4392")
|
106
104
|
end
|
107
|
-
context "
|
108
|
-
let(:config) { super().merge("
|
105
|
+
context "with HMAC" do
|
106
|
+
let(:config) { super().merge("key" => "longencryptionkey") }
|
109
107
|
it "fingerprints the value" do
|
110
|
-
expect(fingerprint).to eq("
|
108
|
+
expect(fingerprint).to eq("22d4c0e8c4fbcdc4887d2038fca7650f0e2e0e2457ff41c06eb2a980dded6749561c814fe182aff93e2538d18593947a")
|
109
|
+
end
|
110
|
+
context "and base64 encoding" do
|
111
|
+
let(:config) { super().merge("base64encode" => true) }
|
112
|
+
it "fingerprints the value" do
|
113
|
+
expect(fingerprint).to eq("ItTA6MT7zcSIfSA4/KdlDw4uDiRX/0HAbrKpgN3tZ0lWHIFP4YKv+T4lONGFk5R6")
|
114
|
+
end
|
111
115
|
end
|
112
116
|
end
|
113
117
|
end
|
114
|
-
|
115
|
-
|
116
|
-
let(:fingerprint_method) { "SHA512" }
|
117
|
-
it "fingerprints the value" do
|
118
|
-
expect(fingerprint).to eq("5468e2dc64ea92b617782aae884b35af60041ac9e168a283615b6a462c54c13d42fa9542cce9b7d76a8124ac6616818905e3e5dd35d6e519f77c3b517558639a")
|
119
|
-
end
|
120
|
-
context "with HMAC" do
|
121
|
-
let(:config) { super().merge("key" => "longencryptionkey") }
|
118
|
+
context "the SHA512 algorithm" do
|
119
|
+
let(:fingerprint_method) { "SHA512" }
|
122
120
|
it "fingerprints the value" do
|
123
|
-
expect(fingerprint).to eq("
|
121
|
+
expect(fingerprint).to eq("5468e2dc64ea92b617782aae884b35af60041ac9e168a283615b6a462c54c13d42fa9542cce9b7d76a8124ac6616818905e3e5dd35d6e519f77c3b517558639a")
|
124
122
|
end
|
125
|
-
context "
|
126
|
-
let(:config) { super().merge("
|
123
|
+
context "with HMAC" do
|
124
|
+
let(:config) { super().merge("key" => "longencryptionkey") }
|
127
125
|
it "fingerprints the value" do
|
128
|
-
expect(fingerprint).to eq("
|
126
|
+
expect(fingerprint).to eq("11c19b326936c08d6c50a3c847d883e5a1362e6a64dd55201a25f2c1ac1b673f7d8bf15b8f112a4978276d573275e3b14166e17246f670c2a539401c5bfdace8")
|
127
|
+
end
|
128
|
+
context "and base64 encoding" do
|
129
|
+
let(:config) { super().merge("base64encode" => true) }
|
130
|
+
it "fingerprints the value" do
|
131
|
+
expect(fingerprint).to eq("EcGbMmk2wI1sUKPIR9iD5aE2Lmpk3VUgGiXywawbZz99i/FbjxEqSXgnbVcydeOxQWbhckb2cMKlOUAcW/2s6A==")
|
132
|
+
end
|
129
133
|
end
|
130
134
|
end
|
131
135
|
end
|
132
|
-
|
133
|
-
|
134
|
-
let(:fingerprint_method) { "MD5" }
|
135
|
-
it "fingerprints the value" do
|
136
|
-
expect(fingerprint).to eq("ccdd8d3d940a01b2fb3258c059924c0d")
|
137
|
-
end
|
138
|
-
context "with HMAC" do
|
139
|
-
let(:config) { super().merge("key" => "longencryptionkey") }
|
136
|
+
context "the MD5 algorithm" do
|
137
|
+
let(:fingerprint_method) { "MD5" }
|
140
138
|
it "fingerprints the value" do
|
141
|
-
expect(fingerprint).to eq("
|
139
|
+
expect(fingerprint).to eq("ccdd8d3d940a01b2fb3258c059924c0d")
|
142
140
|
end
|
143
|
-
context "
|
144
|
-
let(:config) { super().merge("
|
141
|
+
context "with HMAC" do
|
142
|
+
let(:config) { super().merge("key" => "longencryptionkey") }
|
145
143
|
it "fingerprints the value" do
|
146
|
-
expect(fingerprint).to eq("
|
144
|
+
expect(fingerprint).to eq("9336c879e305c9604a3843fc3e75948f")
|
145
|
+
end
|
146
|
+
context "and base64 encoding" do
|
147
|
+
let(:config) { super().merge("base64encode" => true) }
|
148
|
+
it "fingerprints the value" do
|
149
|
+
expect(fingerprint).to eq("kzbIeeMFyWBKOEP8PnWUjw==")
|
150
|
+
end
|
147
151
|
end
|
148
152
|
end
|
149
153
|
end
|
150
154
|
end
|
151
|
-
end
|
152
155
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
+
context "multiple values in the source field" do
|
157
|
+
let(:config) { super().merge("source" => ["clientip" ]) }
|
158
|
+
let(:data) { { "clientip" => [ "123.123.123.123", "223.223.223.223" ] } }
|
156
159
|
|
157
|
-
|
158
|
-
|
160
|
+
it "produces a fingerprint array" do
|
161
|
+
expect(fingerprint).to eq(["3a5076c520b4b463f43806896ea0b3978d09dcae", "47bbc4e06edebbace047fed35abeceec64968b81"])
|
162
|
+
end
|
159
163
|
end
|
160
|
-
end
|
161
164
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
165
|
+
describe "concatenate_all_fields" do
|
166
|
+
let(:config) { { "concatenate_all_fields" => true } }
|
167
|
+
# The @timestamp field is specified in this sample event as we need the event contents to be constant for the tests
|
168
|
+
let(:data) do
|
169
|
+
{ "@timestamp" => "2017-07-26T14:44:27.064Z", "clientip" => "123.123.123.123", "message" => "This is a test message", "log_level" => "INFO", "offset" => 123456789, "type" => "test" }
|
170
|
+
end
|
168
171
|
|
169
|
-
|
170
|
-
|
172
|
+
it "fingerprints the concatenated values" do
|
173
|
+
expect(fingerprint).to eq("cbf022518e97860403160ed8a41847c0db104e63")
|
174
|
+
end
|
171
175
|
end
|
172
|
-
end
|
173
176
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
+
context "when multiple fields are used" do
|
178
|
+
let(:config) { super().merge("source" => ['field1', 'field2']) }
|
179
|
+
let(:data) { { "field1" => "test1", "field2" => "test2" } }
|
177
180
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
181
|
+
it "fingerprints the value of the last value" do
|
182
|
+
# SHA1 of "test2"
|
183
|
+
expect(fingerprint).to eq("109f4b3c50d7b0df729d299bc6f8e9ef9066971f")
|
184
|
+
end
|
182
185
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
186
|
+
describe "with concatenate_sources" do
|
187
|
+
let(:config) { super().merge("concatenate_sources" => true) }
|
188
|
+
it "fingerprints the value of concatenated key/pairs" do
|
189
|
+
# SHA1 of "|field1|test1|field2|test2|"
|
190
|
+
expect(fingerprint).to eq("e3b6b71eedc656f1d29408264e8a75535db985cb")
|
191
|
+
end
|
188
192
|
end
|
189
193
|
end
|
190
|
-
end
|
191
194
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
195
|
+
describe "PUNCTUATION method" do
|
196
|
+
let(:fingerprint_method) { 'PUNCTUATION' }
|
197
|
+
let(:config) { super().merge("source" => 'field1') }
|
198
|
+
let(:data) { { "field1" => "PHP Warning: json_encode() [<a href='function.json-encode'>function.json-encode</a>]: Invalid UTF-8 sequence in argument in /var/www/htdocs/test.php on line 233" } }
|
196
199
|
|
197
|
-
|
198
|
-
|
200
|
+
it "extracts punctiation as the fingerprint" do
|
201
|
+
expect(fingerprint).to eq(":_()[<='.-'>.-</>]:-////.")
|
202
|
+
end
|
199
203
|
end
|
200
|
-
end
|
201
204
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
+
context 'Timestamps' do
|
206
|
+
epoch_time = Time.at(0).gmtime
|
207
|
+
let(:config) { super().merge("source" => ['@timestamp']) }
|
205
208
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
209
|
+
describe 'OpenSSL Fingerprinting' do
|
210
|
+
let(:config) { super().merge("key" => '0123') }
|
211
|
+
let(:fingerprint_method) { "SHA1" }
|
212
|
+
let(:data) { { "@timestamp" => epoch_time } }
|
213
|
+
it "fingerprints the timestamp correctly" do
|
214
|
+
expect(fingerprint).to eq('1d5379ec92d86a67cfc642d55aa050ca312d3b9a')
|
215
|
+
end
|
212
216
|
end
|
213
|
-
end
|
214
217
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
218
|
+
describe 'MURMUR3 Fingerprinting' do
|
219
|
+
let(:fingerprint_method) { "MURMUR3" }
|
220
|
+
let(:data) { { "@timestamp" => epoch_time } }
|
221
|
+
it "fingerprints the timestamp correctly" do
|
222
|
+
expect(fingerprint).to eq(743372282)
|
223
|
+
end
|
220
224
|
end
|
221
225
|
end
|
222
|
-
end
|
223
226
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
227
|
+
describe "post fingerprint execution triggers" do
|
228
|
+
let(:fingerprint_method) { "PUNCTUATION" }
|
229
|
+
let(:config) do
|
230
|
+
{
|
231
|
+
"source" => 'field1',
|
232
|
+
"add_field" => { 'myfield' => 'myvalue' },
|
233
|
+
"add_tag" => ['mytag']
|
234
|
+
}
|
235
|
+
end
|
236
|
+
let(:data) { { "field1" => "Hello, World!" } }
|
234
237
|
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
238
|
+
it "adds the new field" do
|
239
|
+
expect(event.get("myfield")).to eq("myvalue")
|
240
|
+
end
|
241
|
+
it "adds the new tag" do
|
242
|
+
expect(event.get("tags")).to include("mytag")
|
243
|
+
end
|
240
244
|
end
|
241
|
-
end
|
242
245
|
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
+
describe "tolerance to hash order" do
|
247
|
+
# insertion order can influence the result of to_hash's keys
|
248
|
+
let(:data1) { {
|
246
249
|
"a" => {"a0" => 0, "a1" => 1},
|
247
250
|
"b" => {"b0" => 0, "b1" => 1},
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
+
} }
|
252
|
+
let(:event1) { LogStash::Event.new(data1) }
|
253
|
+
let(:data2) { {
|
251
254
|
"b" => {"b1" => 1, "b0" => 0},
|
252
255
|
"a" => {"a1" => 1, "a0" => 0},
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
end
|
277
|
-
it "computes the same hash" do
|
278
|
-
# confirm the order of the keys in the nested hash is different
|
279
|
-
# (of course it is, we just mocked the to_hash return)
|
280
|
-
expect(event1.to_hash["a"].keys).to_not eq(event2.to_hash["a"].keys)
|
281
|
-
# let's check that the fingerprint doesn't care about the insertion order
|
282
|
-
expect(event1.get("fingerprint")).to eq(event2.get("fingerprint"))
|
283
|
-
end
|
284
|
-
context "concatenate_sources" do
|
285
|
-
let("config") { { "source" => [ "a", "b"], "concatenate_sources" => true } }
|
286
|
-
it "computes the same hash" do
|
287
|
-
expect(event1.get("fingerprint")).to eq(event2.get("fingerprint"))
|
256
|
+
} }
|
257
|
+
let(:event2) { LogStash::Event.new(data2) }
|
258
|
+
let(:config) { { "source" => [ "a" ] } }
|
259
|
+
|
260
|
+
before(:each) do
|
261
|
+
# for testing purposes we want to ensure the hash order is different.
|
262
|
+
# since we can't easily control the order on the underlying Map,
|
263
|
+
# we're mocking the order here:
|
264
|
+
allow(event1).to receive(:to_hash).and_return(data1)
|
265
|
+
allow(event2).to receive(:to_hash).and_return(data2)
|
266
|
+
# by default event.get(key) fetches data from the event.
|
267
|
+
# mocking the default value has to be done first, and only
|
268
|
+
# then we can mock the getting "a" and "b"
|
269
|
+
allow(event1).to receive(:get).and_call_original
|
270
|
+
allow(event2).to receive(:get).and_call_original
|
271
|
+
# mock event.get("a") and event.get("b") for both events
|
272
|
+
# so we can inject an inconsistent order for the tests
|
273
|
+
allow(event1).to receive(:get).with("a") {|arg| data1["a"] }
|
274
|
+
allow(event1).to receive(:get).with("b") {|arg| data1["b"] }
|
275
|
+
allow(event2).to receive(:get).with("a") {|arg| data2["a"] }
|
276
|
+
allow(event2).to receive(:get).with("b") {|arg| data2["b"] }
|
277
|
+
plugin.filter(event1)
|
278
|
+
plugin.filter(event2)
|
288
279
|
end
|
289
|
-
end
|
290
|
-
context "concatenate_all_fields => true" do
|
291
|
-
let(:config) { { "concatenate_all_fields" => true } }
|
292
280
|
it "computes the same hash" do
|
281
|
+
# confirm the order of the keys in the nested hash is different
|
282
|
+
# (of course it is, we just mocked the to_hash return)
|
283
|
+
expect(event1.to_hash["a"].keys).to_not eq(event2.to_hash["a"].keys)
|
284
|
+
# let's check that the fingerprint doesn't care about the insertion order
|
293
285
|
expect(event1.get("fingerprint")).to eq(event2.get("fingerprint"))
|
294
286
|
end
|
287
|
+
context "concatenate_sources" do
|
288
|
+
let("config") { { "source" => [ "a", "b"], "concatenate_sources" => true } }
|
289
|
+
it "computes the same hash" do
|
290
|
+
expect(event1.get("fingerprint")).to eq(event2.get("fingerprint"))
|
291
|
+
end
|
292
|
+
end
|
293
|
+
context "concatenate_all_fields => true" do
|
294
|
+
let(:config) { { "concatenate_all_fields" => true } }
|
295
|
+
it "computes the same hash" do
|
296
|
+
expect(event1.get("fingerprint")).to eq(event2.get("fingerprint"))
|
297
|
+
end
|
298
|
+
end
|
295
299
|
end
|
300
|
+
|
296
301
|
end
|
297
302
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-filter-fingerprint
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Elastic
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-06-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,6 +58,20 @@ dependencies:
|
|
58
58
|
- - ">="
|
59
59
|
- !ruby/object:Gem::Version
|
60
60
|
version: '0'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
requirement: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - "~>"
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '1.2'
|
67
|
+
name: logstash-mixin-ecs_compatibility_support
|
68
|
+
prerelease: false
|
69
|
+
type: :runtime
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '1.2'
|
61
75
|
description: This gem is a Logstash plugin required to be installed on top of the
|
62
76
|
Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This
|
63
77
|
gem is not a stand-alone program
|