using OCSentinelCli; using Xunit; namespace OCSentinelCli.Tests; public sealed class ExchangeIisLogParserTests { [Fact] public void ParsesFailedOwaLoginWithActualIisPort() { string[] lines = [ "#Fields: date time s-ip cs-method cs-uri-stem cs-username c-ip s-port sc-status", "2026-08-02 04:15:00 10.0.0.10 POST /owa/auth.owa - 203.0.113.20 443 401" ]; AttackEvent attack = Assert.Single(ExchangeIisLogParser.ParseLines(lines, new DateTimeOffset(2026, 8, 2, 4, 0, 0, TimeSpan.Zero))); Assert.Equal("Exchange OWA login", attack.Target); Assert.Equal("OWA", attack.Service); Assert.Equal(443, attack.DestinationPort); Assert.Equal("/owa/auth.owa", attack.Endpoint); Assert.Equal("203.0.113.20", attack.SourceIp); } [Fact] public void ParsesMapiAndIgnoresSuccessfulRequests() { string[] lines = [ "#Fields: date time cs-uri-stem cs-username c-ip s-port sc-status", "2026-08-02 04:15:00 /mapi/emsmdb/ user@example.test 198.51.100.8 444 403", "2026-08-02 04:16:00 /ecp/ user@example.test 198.51.100.9 443 200" ]; AttackEvent attack = Assert.Single(ExchangeIisLogParser.ParseLines(lines, new DateTimeOffset(2026, 8, 2, 4, 0, 0, TimeSpan.Zero))); Assert.Equal("MAPI/HTTP", attack.Service); Assert.Equal(444, attack.DestinationPort); Assert.Equal("user@example.test", attack.Username); } }