diff --git a/assets/parser_auth_families_journalctl_short_full.log b/assets/parser_auth_families_journalctl_short_full.log index df00924..f823b9e 100644 --- a/assets/parser_auth_families_journalctl_short_full.log +++ b/assets/parser_auth_families_journalctl_short_full.log @@ -1,7 +1,13 @@ Wed 2026-03-11 10:00:01 UTC example-host sshd[3100]: Accepted publickey for alice from 203.0.113.70 port 53000 ssh2: ED25519 SHA256:SANITIZEDKEY +Wed 2026-03-11 10:00:20 UTC example-host sshd[3101]: Accepted password for bob from 203.0.113.73 port 53001 ssh2 +Wed 2026-03-11 10:00:36 UTC example-host sshd[3102]: Failed publickey for invalid user svc-deploy from 203.0.113.74 port 53002 ssh2 Wed 2026-03-11 10:00:42 UTC example-host pam_faillock(sshd:auth): Consecutive login failures for user alice account temporarily locked from 203.0.113.71 Wed 2026-03-11 10:01:13 UTC example-host pam_faillock(sshd:auth): Authentication failure for user bob from 203.0.113.72 +Wed 2026-03-11 10:01:40 UTC example-host pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=203.0.113.75 user=carol Wed 2026-03-11 10:01:54 UTC example-host pam_faillock(sshd:auth): User carol successfully authenticated Wed 2026-03-11 10:02:25 UTC example-host pam_sss(sshd:auth): received for user dave: 7 (Authentication failure) -Wed 2026-03-11 10:02:56 UTC example-host pam_sss(sshd:auth): received for user erin: 10 (User not known to the underlying authentication module) -Wed 2026-03-11 10:03:27 UTC example-host pam_sss(sshd:auth): received for user frank: 9 (Authentication service cannot retrieve authentication info) +Wed 2026-03-11 10:02:44 UTC example-host pam_unix(sudo:session): session opened for user root by erin(uid=0) +Wed 2026-03-11 10:03:05 UTC example-host pam_faillock(sshd:auth): Account temporarily locked for user frank +Wed 2026-03-11 10:03:24 UTC example-host pam_sss(sshd:auth): received for user grace: 10 (User not known to the underlying authentication module) +Wed 2026-03-11 10:03:43 UTC example-host pam_sss(sshd:auth): received for user heidi: 9 (Authentication service cannot retrieve authentication info) +Wed 2026-03-11 10:04:02 UTC example-host pam_unix(sshd:session): session closed for user alice diff --git a/assets/parser_auth_families_syslog.log b/assets/parser_auth_families_syslog.log index ab745dc..5475ffa 100644 --- a/assets/parser_auth_families_syslog.log +++ b/assets/parser_auth_families_syslog.log @@ -1,7 +1,13 @@ Mar 11 10:00:01 example-host sshd[2100]: Accepted publickey for alice from 203.0.113.70 port 53000 ssh2: ED25519 SHA256:SANITIZEDKEY +Mar 11 10:00:20 example-host sshd[2101]: Accepted password for bob from 203.0.113.73 port 53001 ssh2 +Mar 11 10:00:36 example-host sshd[2102]: Failed publickey for invalid user svc-deploy from 203.0.113.74 port 53002 ssh2 Mar 11 10:00:42 example-host pam_faillock(sshd:auth): Consecutive login failures for user alice account temporarily locked from 203.0.113.71 Mar 11 10:01:13 example-host pam_faillock(sshd:auth): Authentication failure for user bob from 203.0.113.72 +Mar 11 10:01:40 example-host pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=203.0.113.75 user=carol Mar 11 10:01:54 example-host pam_faillock(sshd:auth): User carol successfully authenticated Mar 11 10:02:25 example-host pam_sss(sshd:auth): received for user dave: 7 (Authentication failure) -Mar 11 10:02:56 example-host pam_sss(sshd:auth): received for user erin: 10 (User not known to the underlying authentication module) -Mar 11 10:03:27 example-host pam_sss(sshd:auth): received for user frank: 9 (Authentication service cannot retrieve authentication info) +Mar 11 10:02:44 example-host pam_unix(sudo:session): session opened for user root by erin(uid=0) +Mar 11 10:03:05 example-host pam_faillock(sshd:auth): Account temporarily locked for user frank +Mar 11 10:03:24 example-host pam_sss(sshd:auth): received for user grace: 10 (User not known to the underlying authentication module) +Mar 11 10:03:43 example-host pam_sss(sshd:auth): received for user heidi: 9 (Authentication service cannot retrieve authentication info) +Mar 11 10:04:02 example-host pam_unix(sshd:session): session closed for user alice diff --git a/assets/parser_fixture_matrix_journalctl_short_full.log b/assets/parser_fixture_matrix_journalctl_short_full.log index 38486b4..b30acf3 100644 --- a/assets/parser_fixture_matrix_journalctl_short_full.log +++ b/assets/parser_fixture_matrix_journalctl_short_full.log @@ -4,9 +4,13 @@ Tue 2026-03-10 09:01:15 UTC example-host sshd[3002]: Invalid user backup from 20 Tue 2026-03-10 09:01:52 UTC example-host pam_unix(sshd:auth): authentication failure; user=alice euid=0 tty=ssh rhost=203.0.113.40 Tue 2026-03-10 09:02:30 UTC example-host pam_unix(sudo:session): session opened for user root(uid=0) by alice(uid=1000) Tue 2026-03-10 09:03:05 UTC example-host pam_unix(su-l:session): session opened for user root by bob(uid=1001) +Tue 2026-03-10 09:03:28 UTC example-host sshd[3008]: Accepted password for alice from 203.0.113.41 port 52003 ssh2 +Tue 2026-03-10 09:03:34 UTC example-host sshd[3009]: Accepted publickey for carol from 203.0.113.42 port 52004 ssh2: ED25519 SHA256:SANITIZEDKEY2 Tue 2026-03-10 09:03:40 UTC example-host sshd[3003]: Connection closed by user alice 203.0.113.50 port 52010 [preauth] Tue 2026-03-10 09:04:05 UTC example-host sshd[3004]: Connection closed by authenticating user carol 203.0.113.51 port 52011 [preauth] Tue 2026-03-10 09:04:28 UTC example-host sshd[3005]: Connection closed by invalid user deploy 203.0.113.52 port 52012 [preauth] Tue 2026-03-10 09:05:02 UTC example-host sshd[3006]: Disconnected from authenticating user dave 203.0.113.53 port 52013 [preauth] Tue 2026-03-10 09:05:34 UTC example-host sshd[3007]: Timeout, client not responding from 203.0.113.54 port 52014 +Tue 2026-03-10 09:05:46 UTC example-host sshd[3010]: Received disconnect from 203.0.113.55 port 52015:11: disconnected by user +Tue 2026-03-10 09:05:58 UTC example-host sshd[3011]: Unable to negotiate with 203.0.113.56 port 52016: no matching host key type found. Their offer: ssh-rsa Tue 2026-03-10 09:06:10 UTC example-host pam_unix(sshd:session): session closed for user alice diff --git a/assets/parser_fixture_matrix_syslog.log b/assets/parser_fixture_matrix_syslog.log index fface11..1c1e877 100644 --- a/assets/parser_fixture_matrix_syslog.log +++ b/assets/parser_fixture_matrix_syslog.log @@ -4,9 +4,13 @@ Mar 10 09:01:15 example-host sshd[2002]: Invalid user backup from 203.0.113.12 p Mar 10 09:01:52 example-host pam_unix(sshd:auth): authentication failure; user=alice euid=0 tty=ssh rhost=203.0.113.40 Mar 10 09:02:30 example-host pam_unix(sudo:session): session opened for user root(uid=0) by alice(uid=1000) Mar 10 09:03:05 example-host pam_unix(su-l:session): session opened for user root by bob(uid=1001) +Mar 10 09:03:28 example-host sshd[2008]: Accepted password for alice from 203.0.113.41 port 52003 ssh2 +Mar 10 09:03:34 example-host sshd[2009]: Accepted publickey for carol from 203.0.113.42 port 52004 ssh2: ED25519 SHA256:SANITIZEDKEY2 Mar 10 09:03:40 example-host sshd[2003]: Connection closed by user alice 203.0.113.50 port 52010 [preauth] Mar 10 09:04:05 example-host sshd[2004]: Connection closed by authenticating user carol 203.0.113.51 port 52011 [preauth] Mar 10 09:04:28 example-host sshd[2005]: Connection closed by invalid user deploy 203.0.113.52 port 52012 [preauth] Mar 10 09:05:02 example-host sshd[2006]: Disconnected from authenticating user dave 203.0.113.53 port 52013 [preauth] Mar 10 09:05:34 example-host sshd[2007]: Timeout, client not responding from 203.0.113.54 port 52014 +Mar 10 09:05:46 example-host sshd[2010]: Received disconnect from 203.0.113.55 port 52015:11: disconnected by user +Mar 10 09:05:58 example-host sshd[2011]: Unable to negotiate with 203.0.113.56 port 52016: no matching host key type found. Their offer: ssh-rsa Mar 10 09:06:10 example-host pam_unix(sshd:session): session closed for user alice diff --git a/tests/fixtures/report_contracts/multi_host_journalctl_short_full/input.log b/tests/fixtures/report_contracts/multi_host_journalctl_short_full/input.log index 8c9b818..d549760 100644 --- a/tests/fixtures/report_contracts/multi_host_journalctl_short_full/input.log +++ b/tests/fixtures/report_contracts/multi_host_journalctl_short_full/input.log @@ -3,9 +3,13 @@ Wed 2026-03-11 09:01:05 UTC alpha-host sshd[2302]: Failed password for root from Wed 2026-03-11 09:02:10 UTC alpha-host sshd[2303]: Failed password for test from 203.0.113.10 port 52040 ssh2 Wed 2026-03-11 09:03:44 UTC alpha-host sshd[2304]: Failed password for guest from 203.0.113.10 port 52050 ssh2 Wed 2026-03-11 09:04:05 UTC alpha-host sshd[2305]: Failed password for invalid user deploy from 203.0.113.10 port 52060 ssh2 +Wed 2026-03-11 09:05:20 UTC alpha-host sshd[2306]: Accepted password for ops from 203.0.113.60 port 52070 ssh2 +Wed 2026-03-11 09:06:02 UTC alpha-host pam_faillock(sshd:auth): Authentication failure for user svc-ci from 203.0.113.61 Wed 2026-03-11 09:10:10 UTC beta-host sshd[2401]: Accepted publickey for alice from 203.0.113.20 port 52111 ssh2 Wed 2026-03-11 09:11:00 UTC beta-host sudo: alice : TTY=pts/0 ; PWD=/home/alice ; USER=root ; COMMAND=/usr/bin/systemctl restart ssh Wed 2026-03-11 09:12:10 UTC beta-host sudo: alice : TTY=pts/0 ; PWD=/home/alice ; USER=root ; COMMAND=/usr/bin/journalctl -xe +Wed 2026-03-11 09:13:02 UTC beta-host pam_sss(sshd:auth): received for user mallory: 7 (Authentication failure) +Wed 2026-03-11 09:13:38 UTC beta-host pam_sss(sshd:auth): received for user ghost: 10 (User not known to the underlying authentication module) Wed 2026-03-11 09:14:15 UTC beta-host sudo: alice : TTY=pts/0 ; PWD=/home/alice ; USER=root ; COMMAND=/usr/bin/vi /etc/ssh/sshd_config -Wed 2026-03-11 09:15:12 UTC alpha-host sshd[2306]: Connection closed by authenticating user alice 203.0.113.50 port 52290 [preauth] +Wed 2026-03-11 09:15:12 UTC alpha-host sshd[2307]: Connection closed by authenticating user alice 203.0.113.50 port 52290 [preauth] Wed 2026-03-11 09:16:18 UTC beta-host sshd[2402]: Timeout, client not responding from 203.0.113.51 port 52291 diff --git a/tests/fixtures/report_contracts/multi_host_journalctl_short_full/report.json b/tests/fixtures/report_contracts/multi_host_journalctl_short_full/report.json index 0ab874d..a71b07d 100644 --- a/tests/fixtures/report_contracts/multi_host_journalctl_short_full/report.json +++ b/tests/fixtures/report_contracts/multi_host_journalctl_short_full/report.json @@ -4,42 +4,48 @@ "input_mode": "journalctl_short_full", "timezone_present": true, "parser_quality": { - "total_lines": 11, - "parsed_lines": 9, - "unparsed_lines": 2, - "parse_success_rate": 0.8182, + "total_lines": 15, + "parsed_lines": 12, + "unparsed_lines": 3, + "parse_success_rate": 0.8000, "top_unknown_patterns": [ + {"pattern": "pam_sss_unknown_user", "count": 1}, {"pattern": "sshd_connection_closed_preauth", "count": 1}, {"pattern": "sshd_timeout_or_disconnection", "count": 1} ] }, - "parsed_event_count": 9, - "warning_count": 2, + "parsed_event_count": 12, + "warning_count": 3, "finding_count": 3, "event_counts": [ {"event_type": "ssh_failed_password", "count": 3}, + {"event_type": "ssh_accepted_password", "count": 1}, {"event_type": "ssh_accepted_publickey", "count": 1}, {"event_type": "ssh_invalid_user", "count": 2}, + {"event_type": "pam_auth_failure", "count": 2}, {"event_type": "sudo_command", "count": 3} ], "host_summaries": [ { "hostname": "alpha-host", - "parsed_event_count": 5, + "parsed_event_count": 7, "finding_count": 2, "warning_count": 1, "event_counts": [ {"event_type": "ssh_failed_password", "count": 3}, - {"event_type": "ssh_invalid_user", "count": 2} + {"event_type": "ssh_accepted_password", "count": 1}, + {"event_type": "ssh_invalid_user", "count": 2}, + {"event_type": "pam_auth_failure", "count": 1} ] }, { "hostname": "beta-host", - "parsed_event_count": 4, + "parsed_event_count": 5, "finding_count": 1, - "warning_count": 1, + "warning_count": 2, "event_counts": [ {"event_type": "ssh_accepted_publickey", "count": 1}, + {"event_type": "pam_auth_failure", "count": 1}, {"event_type": "sudo_command", "count": 3} ] } @@ -77,7 +83,8 @@ } ], "warnings": [ - {"line_number": 10, "reason": "unrecognized auth pattern: sshd_connection_closed_preauth"}, - {"line_number": 11, "reason": "unrecognized auth pattern: sshd_timeout_or_disconnection"} + {"line_number": 12, "reason": "unrecognized auth pattern: pam_sss_unknown_user"}, + {"line_number": 14, "reason": "unrecognized auth pattern: sshd_connection_closed_preauth"}, + {"line_number": 15, "reason": "unrecognized auth pattern: sshd_timeout_or_disconnection"} ] } diff --git a/tests/fixtures/report_contracts/multi_host_journalctl_short_full/report.md b/tests/fixtures/report_contracts/multi_host_journalctl_short_full/report.md index 7326801..b7a4d93 100644 --- a/tests/fixtures/report_contracts/multi_host_journalctl_short_full/report.md +++ b/tests/fixtures/report_contracts/multi_host_journalctl_short_full/report.md @@ -5,20 +5,20 @@ - Input: `tests/fixtures/report_contracts/multi_host_journalctl_short_full/input.log` - Input mode: journalctl_short_full - Timezone present: true -- Total lines: 11 -- Parsed lines: 9 -- Unparsed lines: 2 -- Parse success rate: 81.82% -- Parsed events: 9 +- Total lines: 15 +- Parsed lines: 12 +- Unparsed lines: 3 +- Parse success rate: 80.00% +- Parsed events: 12 - Findings: 3 -- Parser warnings: 2 +- Parser warnings: 3 ## Host Summary | Host | Parsed Events | Findings | Warnings | | --- | ---: | ---: | ---: | -| alpha-host | 5 | 2 | 1 | -| beta-host | 4 | 1 | 1 | +| alpha-host | 7 | 2 | 1 | +| beta-host | 5 | 1 | 2 | ## Findings @@ -33,14 +33,17 @@ | Event Type | Count | | --- | ---: | | ssh_failed_password | 3 | +| ssh_accepted_password | 1 | | ssh_accepted_publickey | 1 | | ssh_invalid_user | 2 | +| pam_auth_failure | 2 | | sudo_command | 3 | ## Parser Quality | Unknown Pattern | Count | | --- | ---: | +| pam_sss_unknown_user | 1 | | sshd_connection_closed_preauth | 1 | | sshd_timeout_or_disconnection | 1 | @@ -48,5 +51,6 @@ | Line | Reason | | ---: | --- | -| 10 | unrecognized auth pattern: sshd_connection_closed_preauth | -| 11 | unrecognized auth pattern: sshd_timeout_or_disconnection | +| 12 | unrecognized auth pattern: pam_sss_unknown_user | +| 14 | unrecognized auth pattern: sshd_connection_closed_preauth | +| 15 | unrecognized auth pattern: sshd_timeout_or_disconnection | diff --git a/tests/fixtures/report_contracts/multi_host_syslog_legacy/input.log b/tests/fixtures/report_contracts/multi_host_syslog_legacy/input.log index 471a63d..9ac9cca 100644 --- a/tests/fixtures/report_contracts/multi_host_syslog_legacy/input.log +++ b/tests/fixtures/report_contracts/multi_host_syslog_legacy/input.log @@ -3,9 +3,13 @@ Mar 11 09:01:05 alpha-host sshd[1302]: Failed password for root from 203.0.113.1 Mar 11 09:02:10 alpha-host sshd[1303]: Failed password for test from 203.0.113.10 port 52040 ssh2 Mar 11 09:03:44 alpha-host sshd[1304]: Failed password for guest from 203.0.113.10 port 52050 ssh2 Mar 11 09:04:05 alpha-host sshd[1305]: Failed password for invalid user deploy from 203.0.113.10 port 52060 ssh2 +Mar 11 09:05:20 alpha-host sshd[1306]: Accepted password for ops from 203.0.113.60 port 52070 ssh2 +Mar 11 09:06:02 alpha-host pam_faillock(sshd:auth): Authentication failure for user svc-ci from 203.0.113.61 Mar 11 09:10:10 beta-host sshd[1401]: Accepted publickey for alice from 203.0.113.20 port 52111 ssh2 Mar 11 09:11:00 beta-host sudo: alice : TTY=pts/0 ; PWD=/home/alice ; USER=root ; COMMAND=/usr/bin/systemctl restart ssh Mar 11 09:12:10 beta-host sudo: alice : TTY=pts/0 ; PWD=/home/alice ; USER=root ; COMMAND=/usr/bin/journalctl -xe +Mar 11 09:13:02 beta-host pam_sss(sshd:auth): received for user mallory: 7 (Authentication failure) +Mar 11 09:13:38 beta-host pam_sss(sshd:auth): received for user ghost: 10 (User not known to the underlying authentication module) Mar 11 09:14:15 beta-host sudo: alice : TTY=pts/0 ; PWD=/home/alice ; USER=root ; COMMAND=/usr/bin/vi /etc/ssh/sshd_config -Mar 11 09:15:12 alpha-host sshd[1306]: Connection closed by authenticating user alice 203.0.113.50 port 52290 [preauth] +Mar 11 09:15:12 alpha-host sshd[1307]: Connection closed by authenticating user alice 203.0.113.50 port 52290 [preauth] Mar 11 09:16:18 beta-host sshd[1402]: Timeout, client not responding from 203.0.113.51 port 52291 diff --git a/tests/fixtures/report_contracts/multi_host_syslog_legacy/report.json b/tests/fixtures/report_contracts/multi_host_syslog_legacy/report.json index 7af40d3..c8d2ec6 100644 --- a/tests/fixtures/report_contracts/multi_host_syslog_legacy/report.json +++ b/tests/fixtures/report_contracts/multi_host_syslog_legacy/report.json @@ -5,42 +5,48 @@ "assume_year": 2026, "timezone_present": false, "parser_quality": { - "total_lines": 11, - "parsed_lines": 9, - "unparsed_lines": 2, - "parse_success_rate": 0.8182, + "total_lines": 15, + "parsed_lines": 12, + "unparsed_lines": 3, + "parse_success_rate": 0.8000, "top_unknown_patterns": [ + {"pattern": "pam_sss_unknown_user", "count": 1}, {"pattern": "sshd_connection_closed_preauth", "count": 1}, {"pattern": "sshd_timeout_or_disconnection", "count": 1} ] }, - "parsed_event_count": 9, - "warning_count": 2, + "parsed_event_count": 12, + "warning_count": 3, "finding_count": 3, "event_counts": [ {"event_type": "ssh_failed_password", "count": 3}, + {"event_type": "ssh_accepted_password", "count": 1}, {"event_type": "ssh_accepted_publickey", "count": 1}, {"event_type": "ssh_invalid_user", "count": 2}, + {"event_type": "pam_auth_failure", "count": 2}, {"event_type": "sudo_command", "count": 3} ], "host_summaries": [ { "hostname": "alpha-host", - "parsed_event_count": 5, + "parsed_event_count": 7, "finding_count": 2, "warning_count": 1, "event_counts": [ {"event_type": "ssh_failed_password", "count": 3}, - {"event_type": "ssh_invalid_user", "count": 2} + {"event_type": "ssh_accepted_password", "count": 1}, + {"event_type": "ssh_invalid_user", "count": 2}, + {"event_type": "pam_auth_failure", "count": 1} ] }, { "hostname": "beta-host", - "parsed_event_count": 4, + "parsed_event_count": 5, "finding_count": 1, - "warning_count": 1, + "warning_count": 2, "event_counts": [ {"event_type": "ssh_accepted_publickey", "count": 1}, + {"event_type": "pam_auth_failure", "count": 1}, {"event_type": "sudo_command", "count": 3} ] } @@ -78,7 +84,8 @@ } ], "warnings": [ - {"line_number": 10, "reason": "unrecognized auth pattern: sshd_connection_closed_preauth"}, - {"line_number": 11, "reason": "unrecognized auth pattern: sshd_timeout_or_disconnection"} + {"line_number": 12, "reason": "unrecognized auth pattern: pam_sss_unknown_user"}, + {"line_number": 14, "reason": "unrecognized auth pattern: sshd_connection_closed_preauth"}, + {"line_number": 15, "reason": "unrecognized auth pattern: sshd_timeout_or_disconnection"} ] } diff --git a/tests/fixtures/report_contracts/multi_host_syslog_legacy/report.md b/tests/fixtures/report_contracts/multi_host_syslog_legacy/report.md index 107cf71..7959f2b 100644 --- a/tests/fixtures/report_contracts/multi_host_syslog_legacy/report.md +++ b/tests/fixtures/report_contracts/multi_host_syslog_legacy/report.md @@ -6,20 +6,20 @@ - Input mode: syslog_legacy - Assume year: 2026 - Timezone present: false -- Total lines: 11 -- Parsed lines: 9 -- Unparsed lines: 2 -- Parse success rate: 81.82% -- Parsed events: 9 +- Total lines: 15 +- Parsed lines: 12 +- Unparsed lines: 3 +- Parse success rate: 80.00% +- Parsed events: 12 - Findings: 3 -- Parser warnings: 2 +- Parser warnings: 3 ## Host Summary | Host | Parsed Events | Findings | Warnings | | --- | ---: | ---: | ---: | -| alpha-host | 5 | 2 | 1 | -| beta-host | 4 | 1 | 1 | +| alpha-host | 7 | 2 | 1 | +| beta-host | 5 | 1 | 2 | ## Findings @@ -34,14 +34,17 @@ | Event Type | Count | | --- | ---: | | ssh_failed_password | 3 | +| ssh_accepted_password | 1 | | ssh_accepted_publickey | 1 | | ssh_invalid_user | 2 | +| pam_auth_failure | 2 | | sudo_command | 3 | ## Parser Quality | Unknown Pattern | Count | | --- | ---: | +| pam_sss_unknown_user | 1 | | sshd_connection_closed_preauth | 1 | | sshd_timeout_or_disconnection | 1 | @@ -49,5 +52,6 @@ | Line | Reason | | ---: | --- | -| 10 | unrecognized auth pattern: sshd_connection_closed_preauth | -| 11 | unrecognized auth pattern: sshd_timeout_or_disconnection | +| 12 | unrecognized auth pattern: pam_sss_unknown_user | +| 14 | unrecognized auth pattern: sshd_connection_closed_preauth | +| 15 | unrecognized auth pattern: sshd_timeout_or_disconnection | diff --git a/tests/test_parser.cpp b/tests/test_parser.cpp index bb4ae91..44fd266 100644 --- a/tests/test_parser.cpp +++ b/tests/test_parser.cpp @@ -197,75 +197,108 @@ void test_syslog_auth_family_fixture_file() { const auto parser = make_syslog_parser(); const auto result = parser.parse_file(asset_path("parser_auth_families_syslog.log")); - expect(result.events.size() == 4, "expected four recognized syslog auth-family events"); - expect(result.warnings.size() == 3, "expected three syslog auth-family warnings"); - expect(result.quality.total_lines == 7, "expected seven syslog auth-family lines"); - expect(result.quality.parsed_lines == 4, "expected four parsed syslog auth-family lines"); - expect(result.quality.unparsed_lines == 3, "expected three unparsed syslog auth-family lines"); - expect_close(result.quality.parse_success_rate, 4.0 / 7.0, 1e-9, + expect(result.events.size() == 8, "expected eight recognized syslog auth-family events"); + expect(result.warnings.size() == 5, "expected five syslog auth-family warnings"); + expect(result.quality.total_lines == 13, "expected thirteen syslog auth-family lines"); + expect(result.quality.parsed_lines == 8, "expected eight parsed syslog auth-family lines"); + expect(result.quality.unparsed_lines == 5, "expected five unparsed syslog auth-family lines"); + expect_close(result.quality.parse_success_rate, 8.0 / 13.0, 1e-9, "expected syslog auth-family parse success rate"); expect(result.events[0].event_type == loglens::EventType::SshAcceptedPublicKey, "expected accepted publickey auth-family event"); expect(result.events[0].source_ip == "203.0.113.70", "expected accepted publickey source ip"); - expect(result.events[1].event_type == loglens::EventType::PamAuthFailure, + expect(result.events[1].event_type == loglens::EventType::SshAcceptedPassword, + "expected accepted password auth-family event"); + expect(result.events[1].username == "bob", "expected accepted password username"); + expect(result.events[2].event_type == loglens::EventType::SshFailedPublicKey, + "expected failed publickey auth-family event"); + expect(result.events[2].username == "svc-deploy", "expected failed publickey username"); + expect(result.events[3].event_type == loglens::EventType::PamAuthFailure, "expected pam_faillock preauth auth-family event"); - expect(result.events[1].username == "alice", "expected pam_faillock preauth username"); - expect(result.events[1].source_ip == "203.0.113.71", "expected pam_faillock preauth source ip"); - expect(result.events[2].event_type == loglens::EventType::PamAuthFailure, + expect(result.events[3].username == "alice", "expected pam_faillock preauth username"); + expect(result.events[3].source_ip == "203.0.113.71", "expected pam_faillock preauth source ip"); + expect(result.events[4].event_type == loglens::EventType::PamAuthFailure, "expected pam_faillock authfail auth-family event"); - expect(result.events[2].username == "bob", "expected pam_faillock authfail username"); - expect(result.events[2].source_ip == "203.0.113.72", "expected pam_faillock authfail source ip"); - expect(result.events[3].event_type == loglens::EventType::PamAuthFailure, + expect(result.events[4].username == "bob", "expected pam_faillock authfail username"); + expect(result.events[4].source_ip == "203.0.113.72", "expected pam_faillock authfail source ip"); + expect(result.events[5].event_type == loglens::EventType::PamAuthFailure, + "expected pam_unix auth-family event"); + expect(result.events[5].username == "carol", "expected pam_unix auth-family username"); + expect(result.events[5].source_ip == "203.0.113.75", "expected pam_unix auth-family source ip"); + expect(result.events[6].event_type == loglens::EventType::PamAuthFailure, "expected pam_sss failure auth-family event"); - expect(result.events[3].username == "dave", "expected pam_sss failure username"); - expect(result.events[3].source_ip.empty(), "expected pam_sss failure fixture to stay source-less"); + expect(result.events[6].username == "dave", "expected pam_sss failure username"); + expect(result.events[6].source_ip.empty(), "expected pam_sss failure fixture to stay source-less"); + expect(result.events[7].event_type == loglens::EventType::SessionOpened, + "expected pam_unix session-opened auth-family event"); + expect(result.events[7].username == "erin", "expected pam_unix session-opened username"); - expect(result.quality.top_unknown_patterns.size() == 3, "expected three syslog auth-family buckets"); + expect(result.quality.top_unknown_patterns.size() == 5, "expected five syslog auth-family buckets"); expect(result.quality.top_unknown_patterns[0].pattern == "pam_faillock_authsucc", "expected pam_faillock authsucc telemetry bucket"); expect(result.quality.top_unknown_patterns[0].count == 1, "expected one pam_faillock authsucc line"); - expect(result.quality.top_unknown_patterns[1].pattern == "pam_sss_authinfo_unavail", + expect(result.quality.top_unknown_patterns[1].pattern == "pam_faillock_other", + "expected pam_faillock other telemetry bucket"); + expect(result.quality.top_unknown_patterns[1].count == 1, "expected one pam_faillock other line"); + expect(result.quality.top_unknown_patterns[2].pattern == "pam_sss_authinfo_unavail", "expected pam_sss authinfo-unavail telemetry bucket"); - expect(result.quality.top_unknown_patterns[1].count == 1, "expected one pam_sss authinfo-unavail line"); - expect(result.quality.top_unknown_patterns[2].pattern == "pam_sss_unknown_user", + expect(result.quality.top_unknown_patterns[2].count == 1, "expected one pam_sss authinfo-unavail line"); + expect(result.quality.top_unknown_patterns[3].pattern == "pam_sss_unknown_user", "expected pam_sss unknown-user telemetry bucket"); - expect(result.quality.top_unknown_patterns[2].count == 1, "expected one pam_sss unknown-user line"); + expect(result.quality.top_unknown_patterns[3].count == 1, "expected one pam_sss unknown-user line"); + expect(result.quality.top_unknown_patterns[4].pattern == "pam_unix_other", + "expected pam_unix other telemetry bucket"); + expect(result.quality.top_unknown_patterns[4].count == 1, "expected one pam_unix other line"); } void test_journalctl_auth_family_fixture_file() { const auto parser = make_journalctl_parser(); const auto result = parser.parse_file(asset_path("parser_auth_families_journalctl_short_full.log")); - expect(result.events.size() == 4, "expected four recognized journalctl auth-family events"); - expect(result.warnings.size() == 3, "expected three journalctl auth-family warnings"); - expect(result.quality.total_lines == 7, "expected seven journalctl auth-family lines"); - expect(result.quality.parsed_lines == 4, "expected four parsed journalctl auth-family lines"); - expect(result.quality.unparsed_lines == 3, "expected three unparsed journalctl auth-family lines"); - expect_close(result.quality.parse_success_rate, 4.0 / 7.0, 1e-9, + expect(result.events.size() == 8, "expected eight recognized journalctl auth-family events"); + expect(result.warnings.size() == 5, "expected five journalctl auth-family warnings"); + expect(result.quality.total_lines == 13, "expected thirteen journalctl auth-family lines"); + expect(result.quality.parsed_lines == 8, "expected eight parsed journalctl auth-family lines"); + expect(result.quality.unparsed_lines == 5, "expected five unparsed journalctl auth-family lines"); + expect_close(result.quality.parse_success_rate, 8.0 / 13.0, 1e-9, "expected journalctl auth-family parse success rate"); expect(result.events[0].event_type == loglens::EventType::SshAcceptedPublicKey, "expected journalctl accepted publickey auth-family event"); expect(result.events[0].source_ip == "203.0.113.70", "expected journalctl accepted publickey source ip"); - expect(result.events[1].event_type == loglens::EventType::PamAuthFailure, + expect(result.events[1].event_type == loglens::EventType::SshAcceptedPassword, + "expected journalctl accepted password auth-family event"); + expect(result.events[2].event_type == loglens::EventType::SshFailedPublicKey, + "expected journalctl failed publickey auth-family event"); + expect(result.events[3].event_type == loglens::EventType::PamAuthFailure, "expected journalctl pam_faillock preauth auth-family event"); - expect(result.events[2].event_type == loglens::EventType::PamAuthFailure, + expect(result.events[4].event_type == loglens::EventType::PamAuthFailure, "expected journalctl pam_faillock authfail auth-family event"); - expect(result.events[3].event_type == loglens::EventType::PamAuthFailure, + expect(result.events[5].event_type == loglens::EventType::PamAuthFailure, + "expected journalctl pam_unix auth-family event"); + expect(result.events[6].event_type == loglens::EventType::PamAuthFailure, "expected journalctl pam_sss failure auth-family event"); - expect(result.events[3].source_ip.empty(), "expected journalctl pam_sss failure fixture to stay source-less"); + expect(result.events[6].source_ip.empty(), "expected journalctl pam_sss failure fixture to stay source-less"); + expect(result.events[7].event_type == loglens::EventType::SessionOpened, + "expected journalctl pam_unix session-opened auth-family event"); - expect(result.quality.top_unknown_patterns.size() == 3, "expected three journalctl auth-family buckets"); + expect(result.quality.top_unknown_patterns.size() == 5, "expected five journalctl auth-family buckets"); expect(result.quality.top_unknown_patterns[0].pattern == "pam_faillock_authsucc", "expected journalctl pam_faillock authsucc telemetry bucket"); expect(result.quality.top_unknown_patterns[0].count == 1, "expected one journalctl pam_faillock authsucc line"); - expect(result.quality.top_unknown_patterns[1].pattern == "pam_sss_authinfo_unavail", + expect(result.quality.top_unknown_patterns[1].pattern == "pam_faillock_other", + "expected journalctl pam_faillock other telemetry bucket"); + expect(result.quality.top_unknown_patterns[1].count == 1, "expected one journalctl pam_faillock other line"); + expect(result.quality.top_unknown_patterns[2].pattern == "pam_sss_authinfo_unavail", "expected journalctl pam_sss authinfo-unavail telemetry bucket"); - expect(result.quality.top_unknown_patterns[1].count == 1, "expected one journalctl pam_sss authinfo-unavail line"); - expect(result.quality.top_unknown_patterns[2].pattern == "pam_sss_unknown_user", + expect(result.quality.top_unknown_patterns[2].count == 1, "expected one journalctl pam_sss authinfo-unavail line"); + expect(result.quality.top_unknown_patterns[3].pattern == "pam_sss_unknown_user", "expected journalctl pam_sss unknown-user telemetry bucket"); - expect(result.quality.top_unknown_patterns[2].count == 1, "expected one journalctl pam_sss unknown-user line"); + expect(result.quality.top_unknown_patterns[3].count == 1, "expected one journalctl pam_sss unknown-user line"); + expect(result.quality.top_unknown_patterns[4].pattern == "pam_unix_other", + "expected journalctl pam_unix other telemetry bucket"); + expect(result.quality.top_unknown_patterns[4].count == 1, "expected one journalctl pam_unix other line"); } void test_malformed_line() { @@ -346,69 +379,81 @@ void test_journalctl_metadata() { "expected normalized journalctl failure pattern"); } -void test_syslog_fixture_matrix_file() { - const auto parser = make_syslog_parser(); - const auto result = parser.parse_file(asset_path("parser_fixture_matrix_syslog.log")); - - expect(result.events.size() == 6, "expected six recognized syslog fixture events"); - expect(result.warnings.size() == 6, "expected six syslog fixture warnings"); - expect(result.quality.total_lines == 12, "expected twelve syslog fixture lines"); - expect(result.quality.parsed_lines == 6, "expected six parsed syslog fixture lines"); - expect(result.quality.unparsed_lines == 6, "expected six unparsed syslog fixture lines"); - expect_close(result.quality.parse_success_rate, 0.5, 1e-9, "expected syslog fixture parse success rate"); - - expect(result.events[0].event_type == loglens::EventType::SshInvalidUser, "expected invalid-user failed password"); - expect(result.events[1].event_type == loglens::EventType::SshFailedPublicKey, "expected failed publickey variant"); - expect(result.events[2].event_type == loglens::EventType::SshInvalidUser, "expected invalid user variant"); - expect(result.events[3].event_type == loglens::EventType::PamAuthFailure, "expected pam auth failure variant"); - expect(result.events[4].event_type == loglens::EventType::SessionOpened, "expected sudo session-opened variant"); - expect(result.events[5].event_type == loglens::EventType::SessionOpened, "expected su-l session-opened variant"); - expect(result.events[4].username == "alice", "expected sudo session actor username"); - expect(result.events[5].username == "bob", "expected su-l session actor username"); - - expect(result.quality.top_unknown_patterns.size() == 3, "expected three unknown syslog buckets"); - expect(result.quality.top_unknown_patterns[0].pattern == "sshd_connection_closed_preauth", - "expected preauth connection-close syslog bucket"); - expect(result.quality.top_unknown_patterns[0].count == 3, "expected three preauth connection-close syslog lines"); - expect(result.quality.top_unknown_patterns[1].pattern == "sshd_timeout_or_disconnection", - "expected timeout/disconnection syslog bucket"); - expect(result.quality.top_unknown_patterns[1].count == 2, "expected two timeout/disconnection syslog lines"); - expect(result.quality.top_unknown_patterns[2].pattern == "pam_unix_other", - "expected unsupported pam_unix syslog bucket"); - expect(result.quality.top_unknown_patterns[2].count == 1, "expected one unsupported pam_unix syslog line"); -} +void test_syslog_fixture_matrix_file() { + const auto parser = make_syslog_parser(); + const auto result = parser.parse_file(asset_path("parser_fixture_matrix_syslog.log")); + + expect(result.events.size() == 8, "expected eight recognized syslog fixture events"); + expect(result.warnings.size() == 8, "expected eight syslog fixture warnings"); + expect(result.quality.total_lines == 16, "expected sixteen syslog fixture lines"); + expect(result.quality.parsed_lines == 8, "expected eight parsed syslog fixture lines"); + expect(result.quality.unparsed_lines == 8, "expected eight unparsed syslog fixture lines"); + expect_close(result.quality.parse_success_rate, 0.5, 1e-9, "expected syslog fixture parse success rate"); + + expect(result.events[0].event_type == loglens::EventType::SshInvalidUser, "expected invalid-user failed password"); + expect(result.events[1].event_type == loglens::EventType::SshFailedPublicKey, "expected failed publickey variant"); + expect(result.events[2].event_type == loglens::EventType::SshInvalidUser, "expected invalid user variant"); + expect(result.events[3].event_type == loglens::EventType::PamAuthFailure, "expected pam auth failure variant"); + expect(result.events[4].event_type == loglens::EventType::SessionOpened, "expected sudo session-opened variant"); + expect(result.events[5].event_type == loglens::EventType::SessionOpened, "expected su-l session-opened variant"); + expect(result.events[6].event_type == loglens::EventType::SshAcceptedPassword, "expected accepted password variant"); + expect(result.events[7].event_type == loglens::EventType::SshAcceptedPublicKey, "expected accepted publickey variant"); + expect(result.events[4].username == "alice", "expected sudo session actor username"); + expect(result.events[5].username == "bob", "expected su-l session actor username"); + expect(result.events[6].username == "alice", "expected accepted password username"); + expect(result.events[7].username == "carol", "expected accepted publickey username"); + + expect(result.quality.top_unknown_patterns.size() == 4, "expected four unknown syslog buckets"); + expect(result.quality.top_unknown_patterns[0].pattern == "sshd_connection_closed_preauth", + "expected preauth connection-close syslog bucket"); + expect(result.quality.top_unknown_patterns[0].count == 3, "expected three preauth connection-close syslog lines"); + expect(result.quality.top_unknown_patterns[1].pattern == "sshd_timeout_or_disconnection", + "expected timeout/disconnection syslog bucket"); + expect(result.quality.top_unknown_patterns[1].count == 3, "expected three timeout/disconnection syslog lines"); + expect(result.quality.top_unknown_patterns[2].pattern == "pam_unix_other", + "expected unsupported pam_unix syslog bucket"); + expect(result.quality.top_unknown_patterns[2].count == 1, "expected one unsupported pam_unix syslog line"); + expect(result.quality.top_unknown_patterns[3].pattern == "sshd_other", + "expected unsupported sshd syslog bucket"); + expect(result.quality.top_unknown_patterns[3].count == 1, "expected one unsupported sshd syslog line"); +} -void test_journalctl_fixture_matrix_file() { - const loglens::AuthLogParser parser(loglens::ParserConfig{ - loglens::InputMode::JournalctlShortFull, - std::nullopt}); - const auto result = parser.parse_file(asset_path("parser_fixture_matrix_journalctl_short_full.log")); - - expect(result.events.size() == 6, "expected six recognized journalctl fixture events"); - expect(result.warnings.size() == 6, "expected six journalctl fixture warnings"); - expect(result.quality.total_lines == 12, "expected twelve journalctl fixture lines"); - expect(result.quality.parsed_lines == 6, "expected six parsed journalctl fixture lines"); - expect(result.quality.unparsed_lines == 6, "expected six unparsed journalctl fixture lines"); - expect_close(result.quality.parse_success_rate, 0.5, 1e-9, "expected journalctl fixture parse success rate"); - - expect(result.events[0].event_type == loglens::EventType::SshInvalidUser, "expected journalctl invalid-user failed password"); - expect(result.events[1].event_type == loglens::EventType::SshFailedPublicKey, "expected journalctl failed publickey variant"); - expect(result.events[2].event_type == loglens::EventType::SshInvalidUser, "expected journalctl invalid user variant"); - expect(result.events[3].event_type == loglens::EventType::PamAuthFailure, "expected journalctl pam auth failure variant"); - expect(result.events[4].event_type == loglens::EventType::SessionOpened, "expected journalctl sudo session-opened variant"); - expect(result.events[5].event_type == loglens::EventType::SessionOpened, "expected journalctl su-l session-opened variant"); - - expect(result.quality.top_unknown_patterns.size() == 3, "expected three unknown journalctl buckets"); - expect(result.quality.top_unknown_patterns[0].pattern == "sshd_connection_closed_preauth", - "expected preauth connection-close journalctl bucket"); - expect(result.quality.top_unknown_patterns[0].count == 3, "expected three preauth connection-close journalctl lines"); - expect(result.quality.top_unknown_patterns[1].pattern == "sshd_timeout_or_disconnection", - "expected timeout/disconnection journalctl bucket"); - expect(result.quality.top_unknown_patterns[1].count == 2, "expected two timeout/disconnection journalctl lines"); - expect(result.quality.top_unknown_patterns[2].pattern == "pam_unix_other", - "expected unsupported pam_unix journalctl bucket"); - expect(result.quality.top_unknown_patterns[2].count == 1, "expected one unsupported pam_unix journalctl line"); -} +void test_journalctl_fixture_matrix_file() { + const loglens::AuthLogParser parser(loglens::ParserConfig{ + loglens::InputMode::JournalctlShortFull, + std::nullopt}); + const auto result = parser.parse_file(asset_path("parser_fixture_matrix_journalctl_short_full.log")); + + expect(result.events.size() == 8, "expected eight recognized journalctl fixture events"); + expect(result.warnings.size() == 8, "expected eight journalctl fixture warnings"); + expect(result.quality.total_lines == 16, "expected sixteen journalctl fixture lines"); + expect(result.quality.parsed_lines == 8, "expected eight parsed journalctl fixture lines"); + expect(result.quality.unparsed_lines == 8, "expected eight unparsed journalctl fixture lines"); + expect_close(result.quality.parse_success_rate, 0.5, 1e-9, "expected journalctl fixture parse success rate"); + + expect(result.events[0].event_type == loglens::EventType::SshInvalidUser, "expected journalctl invalid-user failed password"); + expect(result.events[1].event_type == loglens::EventType::SshFailedPublicKey, "expected journalctl failed publickey variant"); + expect(result.events[2].event_type == loglens::EventType::SshInvalidUser, "expected journalctl invalid user variant"); + expect(result.events[3].event_type == loglens::EventType::PamAuthFailure, "expected journalctl pam auth failure variant"); + expect(result.events[4].event_type == loglens::EventType::SessionOpened, "expected journalctl sudo session-opened variant"); + expect(result.events[5].event_type == loglens::EventType::SessionOpened, "expected journalctl su-l session-opened variant"); + expect(result.events[6].event_type == loglens::EventType::SshAcceptedPassword, "expected journalctl accepted password variant"); + expect(result.events[7].event_type == loglens::EventType::SshAcceptedPublicKey, "expected journalctl accepted publickey variant"); + + expect(result.quality.top_unknown_patterns.size() == 4, "expected four unknown journalctl buckets"); + expect(result.quality.top_unknown_patterns[0].pattern == "sshd_connection_closed_preauth", + "expected preauth connection-close journalctl bucket"); + expect(result.quality.top_unknown_patterns[0].count == 3, "expected three preauth connection-close journalctl lines"); + expect(result.quality.top_unknown_patterns[1].pattern == "sshd_timeout_or_disconnection", + "expected timeout/disconnection journalctl bucket"); + expect(result.quality.top_unknown_patterns[1].count == 3, "expected three timeout/disconnection journalctl lines"); + expect(result.quality.top_unknown_patterns[2].pattern == "pam_unix_other", + "expected unsupported pam_unix journalctl bucket"); + expect(result.quality.top_unknown_patterns[2].count == 1, "expected one unsupported pam_unix journalctl line"); + expect(result.quality.top_unknown_patterns[3].pattern == "sshd_other", + "expected unsupported sshd journalctl bucket"); + expect(result.quality.top_unknown_patterns[3].count == 1, "expected one unsupported sshd journalctl line"); +} } // namespace