Skip to content

Commit

Permalink
[pkg/stanza] fix eventData format for Windows events (open-telemetry#…
Browse files Browse the repository at this point in the history
  • Loading branch information
Mikołaj Świątek committed Apr 12, 2023
1 parent 4373a11 commit 971ab11
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 64 deletions.
16 changes: 16 additions & 0 deletions .chloggen/feat_stanza_windowsinput_eventdata-map.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: bug_fix

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: pkg/stanza

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: fix eventData format for Windows events

# One or more tracking issues related to the change
issues: [20547]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:
4 changes: 2 additions & 2 deletions pkg/stanza/operator/input/windows/testdata/xmlSample.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<Security />
</System>
<EventData>
<Data>2022-04-28T19:48:52Z</Data>
<Data>RulesEngine</Data>
<Data Name="Time">2022-04-28T19:48:52Z</Data>
<Data Name="Source">RulesEngine</Data>
</EventData>
</Event>
55 changes: 38 additions & 17 deletions pkg/stanza/operator/input/windows/xml.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,22 @@ import (

// EventXML is the rendered xml of an event.
type EventXML struct {
EventID EventID `xml:"System>EventID"`
Provider Provider `xml:"System>Provider"`
Computer string `xml:"System>Computer"`
Channel string `xml:"System>Channel"`
RecordID uint64 `xml:"System>EventRecordID"`
TimeCreated TimeCreated `xml:"System>TimeCreated"`
Message string `xml:"RenderingInfo>Message"`
RenderedLevel string `xml:"RenderingInfo>Level"`
Level string `xml:"System>Level"`
RenderedTask string `xml:"RenderingInfo>Task"`
Task string `xml:"System>Task"`
RenderedOpcode string `xml:"RenderingInfo>Opcode"`
Opcode string `xml:"System>Opcode"`
RenderedKeywords []string `xml:"RenderingInfo>Keywords>Keyword"`
Keywords []string `xml:"System>Keywords"`
EventData []string `xml:"EventData>Data"`
EventID EventID `xml:"System>EventID"`
Provider Provider `xml:"System>Provider"`
Computer string `xml:"System>Computer"`
Channel string `xml:"System>Channel"`
RecordID uint64 `xml:"System>EventRecordID"`
TimeCreated TimeCreated `xml:"System>TimeCreated"`
Message string `xml:"RenderingInfo>Message"`
RenderedLevel string `xml:"RenderingInfo>Level"`
Level string `xml:"System>Level"`
RenderedTask string `xml:"RenderingInfo>Task"`
Task string `xml:"System>Task"`
RenderedOpcode string `xml:"RenderingInfo>Opcode"`
Opcode string `xml:"System>Opcode"`
RenderedKeywords []string `xml:"RenderingInfo>Keywords>Keyword"`
Keywords []string `xml:"System>Keywords"`
EventData []EventDataEntry `xml:"EventData>Data"`
}

// parseTimestamp will parse the timestamp of the event.
Expand Down Expand Up @@ -130,7 +130,7 @@ func (e *EventXML) parseBody() map[string]interface{} {
"task": task,
"opcode": opcode,
"keywords": keywords,
"event_data": e.EventData,
"event_data": parseEventData(e.EventData),
}
if len(details) > 0 {
body["details"] = details
Expand All @@ -148,6 +148,22 @@ func (e *EventXML) parseMessage() (string, map[string]interface{}) {
}
}

// parse event data entries into a map[string]string
// where the key is the Name attribute, and value is the element value
// entries without Name are ignored
// see: https://learn.microsoft.com/en-us/windows/win32/wes/eventschema-datafieldtype-complextype
func parseEventData(entries []EventDataEntry) map[string]string {
outputMap := make(map[string]string, len(entries))

for _, entry := range entries {
if entry.Name != "" {
outputMap[entry.Name] = entry.Value
}
}

return outputMap
}

// unmarshalEventXML will unmarshal EventXML from xml bytes.
func unmarshalEventXML(bytes []byte) (EventXML, error) {
var eventXML EventXML
Expand All @@ -174,3 +190,8 @@ type Provider struct {
GUID string `xml:"Guid,attr"`
EventSourceName string `xml:"EventSourceName,attr"`
}

type EventDataEntry struct {
Name string `xml:"Name,attr"`
Value string `xml:",chardata"`
}
110 changes: 71 additions & 39 deletions pkg/stanza/operator/input/windows/xml_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,17 @@ func TestParseBody(t *testing.T) {
TimeCreated: TimeCreated{
SystemTime: "2020-07-30T01:01:01.123456789Z",
},
Computer: "computer",
Channel: "application",
RecordID: 1,
Level: "Information",
Message: "message",
Task: "task",
Opcode: "opcode",
Keywords: []string{"keyword"},
EventData: []string{"this", "is", "some", "sample", "data"},
Computer: "computer",
Channel: "application",
RecordID: 1,
Level: "Information",
Message: "message",
Task: "task",
Opcode: "opcode",
Keywords: []string{"keyword"},
EventData: []EventDataEntry{
{Name: "name", Value: "value"}, {Name: "another_name", Value: "another_value"},
},
RenderedLevel: "rendered_level",
RenderedTask: "rendered_task",
RenderedOpcode: "rendered_opcode",
Expand All @@ -122,7 +124,7 @@ func TestParseBody(t *testing.T) {
"task": "rendered_task",
"opcode": "rendered_opcode",
"keywords": []string{"RenderedKeywords"},
"event_data": []string{"this", "is", "some", "sample", "data"},
"event_data": map[string]string{"name": "value", "another_name": "another_value"},
}

require.Equal(t, expected, xml.parseBody())
Expand All @@ -142,15 +144,17 @@ func TestParseNoRendered(t *testing.T) {
TimeCreated: TimeCreated{
SystemTime: "2020-07-30T01:01:01.123456789Z",
},
Computer: "computer",
Channel: "application",
RecordID: 1,
Level: "Information",
Message: "message",
Task: "task",
Opcode: "opcode",
Keywords: []string{"keyword"},
EventData: []string{"this", "is", "some", "sample", "data"},
Computer: "computer",
Channel: "application",
RecordID: 1,
Level: "Information",
Message: "message",
Task: "task",
Opcode: "opcode",
Keywords: []string{"keyword"},
EventData: []EventDataEntry{
{Name: "name", Value: "value"}, {Name: "another_name", Value: "another_value"},
},
}

expected := map[string]interface{}{
Expand All @@ -172,7 +176,7 @@ func TestParseNoRendered(t *testing.T) {
"task": "task",
"opcode": "opcode",
"keywords": []string{"keyword"},
"event_data": []string{"this", "is", "some", "sample", "data"},
"event_data": map[string]string{"name": "value", "another_name": "another_value"},
}

require.Equal(t, expected, xml.parseBody())
Expand All @@ -192,15 +196,17 @@ func TestParseBodySecurity(t *testing.T) {
TimeCreated: TimeCreated{
SystemTime: "2020-07-30T01:01:01.123456789Z",
},
Computer: "computer",
Channel: "Security",
RecordID: 1,
Level: "Information",
Message: "message",
Task: "task",
Opcode: "opcode",
Keywords: []string{"keyword"},
EventData: []string{"this", "is", "some", "sample", "data"},
Computer: "computer",
Channel: "Security",
RecordID: 1,
Level: "Information",
Message: "message",
Task: "task",
Opcode: "opcode",
Keywords: []string{"keyword"},
EventData: []EventDataEntry{
{Name: "name", Value: "value"}, {Name: "another_name", Value: "another_value"},
},
RenderedLevel: "rendered_level",
RenderedTask: "rendered_task",
RenderedOpcode: "rendered_opcode",
Expand All @@ -226,12 +232,35 @@ func TestParseBodySecurity(t *testing.T) {
"task": "rendered_task",
"opcode": "rendered_opcode",
"keywords": []string{"RenderedKeywords"},
"event_data": []string{"this", "is", "some", "sample", "data"},
"event_data": map[string]string{"name": "value", "another_name": "another_value"},
}

require.Equal(t, expected, xml.parseBody())
}

func TestParseEventData(t *testing.T) {
xmlMap := EventXML{
EventData: []EventDataEntry{
{Name: "name", Value: "value"},
},
}

parsed := xmlMap.parseBody()
expectedMap := map[string]string{"name": "value"}
require.Equal(t, expectedMap, parsed["event_data"])

xmlMixed := EventXML{
EventData: []EventDataEntry{
{Name: "name", Value: "value"},
{Value: "noname"},
},
}

parsed = xmlMixed.parseBody()
expectedSlice := map[string]string{"name": "value"}
require.Equal(t, expectedSlice, parsed["event_data"])
}

func TestInvalidUnmarshal(t *testing.T) {
_, err := unmarshalEventXML([]byte("Test \n Invalid \t Unmarshal"))
require.Error(t, err)
Expand All @@ -257,15 +286,18 @@ func TestUnmarshal(t *testing.T) {
TimeCreated: TimeCreated{
SystemTime: "2022-04-22T10:20:52.3778625Z",
},
Computer: "computer",
Channel: "Application",
RecordID: 23401,
Level: "4",
Message: "",
Task: "0",
Opcode: "0",
EventData: []string{"2022-04-28T19:48:52Z", "RulesEngine"},
Keywords: []string{"0x80000000000000"},
Computer: "computer",
Channel: "Application",
RecordID: 23401,
Level: "4",
Message: "",
Task: "0",
Opcode: "0",
EventData: []EventDataEntry{
{Name: "Time", Value: "2022-04-28T19:48:52Z"},
{Name: "Source", Value: "RulesEngine"},
},
Keywords: []string{"0x80000000000000"},
}

require.Equal(t, xml, event)
Expand Down
7 changes: 1 addition & 6 deletions receiver/windowseventlogreceiver/receiver_windows_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,7 @@ func TestReadWindowsEventLogger(t *testing.T) {
record := records.At(0)
body := record.Body().Map().AsRaw()

strs := []string{"Test log"}
test := make([]interface{}, len(strs))
for i, s := range strs {
test[i] = s
}
require.Equal(t, test, body["event_data"])
require.Equal(t, "Test log", body["message"])

eventID := body["event_id"]
require.NotNil(t, eventID)
Expand Down

0 comments on commit 971ab11

Please sign in to comment.