166 lines
5.5 KiB
Python
166 lines
5.5 KiB
Python
|
import hashlib
|
||
|
import os
|
||
|
import platform
|
||
|
import sys
|
||
|
import yaml
|
||
|
|
||
|
if sys.platform.startswith("win"):
|
||
|
import win32api
|
||
|
import win32con
|
||
|
import win32evtlog
|
||
|
import win32security
|
||
|
import win32evtlogutil
|
||
|
|
||
|
sys.path.append(os.path.join(os.path.dirname(__file__), '../../../libbeat/tests/system'))
|
||
|
|
||
|
from beat.beat import TestCase
|
||
|
|
||
|
PROVIDER = "WinlogbeatTestPython"
|
||
|
APP_NAME = "SystemTest"
|
||
|
OTHER_APP_NAME = "OtherSystemTestApp"
|
||
|
|
||
|
|
||
|
class BaseTest(TestCase):
|
||
|
|
||
|
@classmethod
|
||
|
def setUpClass(self):
|
||
|
self.beat_name = "winlogbeat"
|
||
|
self.beat_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../"))
|
||
|
super(BaseTest, self).setUpClass()
|
||
|
|
||
|
|
||
|
class WriteReadTest(BaseTest):
|
||
|
providerName = PROVIDER
|
||
|
applicationName = APP_NAME
|
||
|
otherAppName = OTHER_APP_NAME
|
||
|
testSuffix = None
|
||
|
sid = None
|
||
|
sidString = None
|
||
|
api = None
|
||
|
|
||
|
def setUp(self):
|
||
|
super(WriteReadTest, self).setUp()
|
||
|
|
||
|
# Every test will use its own event log and application names to ensure
|
||
|
# isolation.
|
||
|
self.testSuffix = "_" + hashlib.sha256(self.api + self._testMethodName).hexdigest()[:5]
|
||
|
self.providerName = PROVIDER + self.testSuffix
|
||
|
self.applicationName = APP_NAME + self.testSuffix
|
||
|
self.otherAppName = OTHER_APP_NAME + self.testSuffix
|
||
|
|
||
|
win32evtlogutil.AddSourceToRegistry(self.applicationName,
|
||
|
"%systemroot%\\system32\\EventCreate.exe",
|
||
|
self.providerName)
|
||
|
win32evtlogutil.AddSourceToRegistry(self.otherAppName,
|
||
|
"%systemroot%\\system32\\EventCreate.exe",
|
||
|
self.providerName)
|
||
|
|
||
|
def tearDown(self):
|
||
|
super(WriteReadTest, self).tearDown()
|
||
|
win32evtlogutil.RemoveSourceFromRegistry(
|
||
|
self.applicationName, self.providerName)
|
||
|
win32evtlogutil.RemoveSourceFromRegistry(
|
||
|
self.otherAppName, self.providerName)
|
||
|
self.clear_event_log()
|
||
|
|
||
|
def clear_event_log(self):
|
||
|
hlog = win32evtlog.OpenEventLog(None, self.providerName)
|
||
|
win32evtlog.ClearEventLog(hlog, None)
|
||
|
win32evtlog.CloseEventLog(hlog)
|
||
|
|
||
|
def write_event_log(self, message, eventID=10, sid=None,
|
||
|
level=None, source=None):
|
||
|
if sid == None:
|
||
|
sid = self.get_sid()
|
||
|
if source == None:
|
||
|
source = self.applicationName
|
||
|
if level == None:
|
||
|
level = win32evtlog.EVENTLOG_INFORMATION_TYPE
|
||
|
|
||
|
win32evtlogutil.ReportEvent(source, eventID,
|
||
|
eventType=level, strings=[message], sid=sid)
|
||
|
|
||
|
def get_sid(self):
|
||
|
if self.sid == None:
|
||
|
ph = win32api.GetCurrentProcess()
|
||
|
th = win32security.OpenProcessToken(ph, win32con.TOKEN_READ)
|
||
|
self.sid = win32security.GetTokenInformation(
|
||
|
th, win32security.TokenUser)[0]
|
||
|
|
||
|
return self.sid
|
||
|
|
||
|
def get_sid_string(self):
|
||
|
if self.sidString == None:
|
||
|
self.sidString = win32security.ConvertSidToStringSid(self.get_sid())
|
||
|
|
||
|
return self.sidString
|
||
|
|
||
|
def read_events(self, config=None, expected_events=1):
|
||
|
if config == None:
|
||
|
config = {
|
||
|
"event_logs": [
|
||
|
{"name": self.providerName, "api": self.api}
|
||
|
]
|
||
|
}
|
||
|
|
||
|
self.render_config_template(**config)
|
||
|
proc = self.start_beat()
|
||
|
self.wait_until(lambda: self.output_has(expected_events))
|
||
|
proc.check_kill_and_wait()
|
||
|
return self.read_output()
|
||
|
|
||
|
def read_registry(self, requireBookmark=False):
|
||
|
f = open(os.path.join(self.working_dir, "data", ".winlogbeat.yml"), "r")
|
||
|
data = yaml.load(f)
|
||
|
self.assertIn("update_time", data)
|
||
|
self.assertIn("event_logs", data)
|
||
|
|
||
|
event_logs = {}
|
||
|
for event_log in data["event_logs"]:
|
||
|
self.assertIn("name", event_log)
|
||
|
self.assertIn("record_number", event_log)
|
||
|
self.assertIn("timestamp", event_log)
|
||
|
if requireBookmark:
|
||
|
self.assertIn("bookmark", event_log)
|
||
|
name = event_log["name"]
|
||
|
event_logs[name] = event_log
|
||
|
|
||
|
return event_logs
|
||
|
|
||
|
def assert_common_fields(self, evt, msg=None, eventID=10, sid=None,
|
||
|
level="Information", extra=None):
|
||
|
|
||
|
assert host_name(evt["computer_name"]).lower() == host_name(platform.node()).lower()
|
||
|
assert "record_number" in evt
|
||
|
self.assertDictContainsSubset({
|
||
|
"event_id": eventID,
|
||
|
"level": level,
|
||
|
"log_name": self.providerName,
|
||
|
"source_name": self.applicationName,
|
||
|
"type": self.api,
|
||
|
}, evt)
|
||
|
|
||
|
if msg == None:
|
||
|
assert "message" not in evt
|
||
|
else:
|
||
|
self.assertEquals(evt["message"], msg)
|
||
|
self.assertDictContainsSubset({"event_data.param1": msg}, evt)
|
||
|
|
||
|
if sid == None:
|
||
|
self.assertEquals(evt["user.identifier"], self.get_sid_string())
|
||
|
self.assertEquals(evt["user.name"].lower(),
|
||
|
win32api.GetUserName().lower())
|
||
|
self.assertEquals(evt["user.type"], "User")
|
||
|
assert "user.domain" in evt
|
||
|
else:
|
||
|
self.assertEquals(evt["user.identifier"], sid)
|
||
|
assert "user.name" not in evt
|
||
|
assert "user.type" not in evt
|
||
|
|
||
|
if extra != None:
|
||
|
self.assertDictContainsSubset(extra, evt)
|
||
|
|
||
|
|
||
|
def host_name(fqdn):
|
||
|
return fqdn.split('.')[0]
|