Select Git revision
Forked from
ai3 / thirdparty / systemd-docker
Source project has a limited visibility.
-
Gernot Vormayr authoredGernot Vormayr authored
collector_test.go 8.55 KiB
package reportscollector
import (
"io/ioutil"
"net/http"
"net/http/httptest"
"path/filepath"
"strings"
"testing"
"github.com/chrj/smtpd"
)
type countingSink struct {
counter int
}
func (c *countingSink) Send(e Event) {
c.counter++
}
func (c *countingSink) reset() { c.counter = 0 }
func createTestCollector() (*countingSink, string, func()) {
sink := new(countingSink)
c := NewCollector(
sink,
new(ReportHandler),
new(TLSRPTHandler),
new(LegacyCSPHandler),
new(DMARCHandler),
)
srv := httptest.NewServer(c)
return sink, srv.URL, func() {
srv.Close()
}
}
func doRequest(t *testing.T, uri, contentType, data string) {
req, err := http.NewRequest("POST", uri, strings.NewReader(data))
if err != nil {
t.Fatalf("NewRequest failed: %v", err)
}
req.Header.Set("Content-Type", contentType)
client := new(http.Client)
resp, err := client.Do(req)
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode >= 300 {
t.Fatalf("request failed with status %d: %s", resp.StatusCode, resp.Status)
}
}
var reportsTestData = `[{
"type": "csp",
"age": 10,
"url": "https://example.com/vulnerable-page/",
"user_agent": "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0",
"body": {
"blocked": "https://evil.com/evil.js",
"directive": "script-src",
"policy": "script-src 'self'; object-src 'none'",
"status": 200,
"referrer": "https://evil.com/"
}
}, {
"type": "hpkp",
"age": 32,
"url": "https://www.example.com/",
"user_agent": "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0",
"body": {
"date-time": "2014-04-06T13:00:50Z",
"hostname": "www.example.com",
"port": 443,
"effective-expiration-date": "2014-05-01T12:40:50Z",
"include-subdomains": false,
"served-certificate-chain": [
"-----BEGIN CERTIFICATE-----\nMIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT\nHFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto\nWHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6\nyuGnBXj8ytqU0CwIPX4WecigUCAkVDNx\n-----END CERTIFICATE-----"
]
}
}, {
"type": "nel",
"age": 29,
"url": "https://example.com/thing.js",
"user_agent": "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0",
"body": {
"referrer": "https://www.example.com/",
"server-ip": "234.233.232.231",
"protocol": "",
"status-code": 0,
"elapsed-time": 143,
"age": 0,
"type": "http.dns.name_not_resolved"
}
}]`
func TestBrowserReports(t *testing.T) {
sink, uri, cleanup := createTestCollector()
defer cleanup()
doRequest(t, uri, "application/reports+json", reportsTestData)
if sink.counter != 3 {
t.Fatalf("parsed %d events, expected 3", sink.counter)
}
}
var tlsrptTestData = `{
"organization-name": "Company-X",
"date-range": {
"start-datetime": "2016-04-01T00:00:00Z",
"end-datetime": "2016-04-01T23:59:59Z"
},
"contact-info": "sts-reporting@company-x.example",
"report-id": "5065427c-23d3-47ca-b6e0-946ea0e8c4be",
"policies": [{
"policy": {
"policy-type": "sts",
"policy-string": ["version: STSv1","mode: testing",
"mx: *.mail.company-y.example","max_age: 86400"],
"policy-domain": "company-y.example",
"mx-host": "*.mail.company-y.example"
},
"summary": {
"total-successful-session-count": 5326,
"total-failure-session-count": 303
},
"failure-details": [{
"result-type": "certificate-expired",
"sending-mta-ip": "2001:db8:abcd:0012::1",
"receiving-mx-hostname": "mx1.mail.company-y.example",
"failed-session-count": 100
}, {
"result-type": "starttls-not-supported",
"sending-mta-ip": "2001:db8:abcd:0013::1",
"receiving-mx-hostname": "mx2.mail.company-y.example",
"receiving-ip": "203.0.113.56",
"failed-session-count": 200,
"additional-information": "https://reports.company-x.example/\n report_info ? id = 5065427 c - 23 d3# StarttlsNotSupported "
}, {
"result-type": "validation-failure",
"sending-mta-ip": "198.51.100.62",
"receiving-ip": "203.0.113.58",
"receiving-mx-hostname": "mx-backup.mail.company-y.example",
"failed-session-count": 3,
"failure-reason-code": "X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED"
}]
}]
}`
func TestTLSRPT(t *testing.T) {
sink, uri, cleanup := createTestCollector()
defer cleanup()
doRequest(t, uri, "application/tlsrpt+json", tlsrptTestData)
if sink.counter != 3 {
t.Fatalf("parsed %d events, expected 3", sink.counter)
}
}
var dmarcTestData1 = `<?xml version="1.0"?>
<feedback>
<version>0.1</version>
<report_metadata>
<org_name>AMAZON-SES</org_name>
<email>postmaster@amazonses.com</email>
<report_id>bf9cb2b6-cdd5-49c3-bfb4-38cc8c29b8e4</report_id>
<date_range>
<begin>1602806400</begin>
<end>1602892800</end>
</date_range>
</report_metadata>
<policy_published>
<domain>example.com</domain>
<adkim>r</adkim>
<aspf>r</aspf>
<p>none</p>
<sp>none</sp>
<pct>0</pct>
<fo>0</fo>
</policy_published>
<record>
<row>
<source_ip>1.2.3.4</source_ip>
<count>2</count>
<policy_evaluated>
<disposition>none</disposition>
<dkim>fail</dkim>
<spf>fail</spf>
</policy_evaluated>
</row>
<identifiers>
<envelope_from>example.com</envelope_from>
<header_from>example.com</header_from>
</identifiers>
<auth_results>
<spf>
<domain>example.com</domain>
<result>fail</result>
</spf>
</auth_results>
</record>
</feedback>`
var dmarcTestData2 = `<?xml version="1.0" encoding="UTF-8" ?>
<feedback>
<report_metadata>
<org_name>vodafone.it</org_name>
<email>noreply-dmarc-support@vodafone.it</email>
<report_id>lists.example.com:1602943261</report_id>
<date_range>
<begin>1602857214</begin>
<end>1602940407</end>
</date_range>
</report_metadata>
<policy_published>
<domain>lists.example.com</domain>
<adkim>r</adkim>
<aspf>r</aspf>
<p>none</p>
<sp>none</sp>
<pct>0</pct>
</policy_published>
<record>
<row>
<source_ip>1.2.3.4</source_ip>
<count>1</count>
<policy_evaluated>
<disposition>none</disposition>
<dkim>pass</dkim>
<spf>pass</spf>
</policy_evaluated>
</row>
<identifiers>
<header_from>lists.example.com</header_from>
</identifiers>
<auth_results>
<spf>
<domain>lists.example.com</domain>
<result>pass</result>
</spf>
<dkim>
<domain>lists.example.com</domain>
<result>pass</result>
</dkim>
</auth_results>
</record>
<record>
<row>
<source_ip>1.2.3.4</source_ip>
<count>1</count>
<policy_evaluated>
<disposition>none</disposition>
<dkim>pass</dkim>
<spf>pass</spf>
</policy_evaluated>
</row>
<identifiers>
<header_from>lists.example.com</header_from>
</identifiers>
<auth_results>
<spf>
<domain>lists.example.com</domain>
<result>pass</result>
</spf>
<dkim>
<domain>lists.example.com</domain>
<result>pass</result>
</dkim>
</auth_results>
</record>
</feedback>`
func TestDMARC(t *testing.T) {
sink, uri, cleanup := createTestCollector()
defer cleanup()
doRequest(t, uri, "text/xml", dmarcTestData1)
if sink.counter != 1 {
t.Fatalf("parsed %d events, expected 1", sink.counter)
}
}
func TestDMARC_IgnoreSuccesses(t *testing.T) {
sink, uri, cleanup := createTestCollector()
defer cleanup()
doRequest(t, uri, "text/xml", dmarcTestData2)
if sink.counter != 0 {
t.Fatalf("parsed %d events, expected 0", sink.counter)
}
}
func TestDMARC_Emails(t *testing.T) {
files, err := filepath.Glob("dmarc/email-samples/*.txt")
if err != nil {
t.Skip()
}
sink := new(countingSink)
c := NewCollector(
sink,
new(DMARCHandler),
)
for _, testf := range files {
data, _ := ioutil.ReadFile(testf)
sink.reset()
err := c.ServeSMTP(
smtpd.Peer{},
smtpd.Envelope{Data: data},
)
if err != nil {
t.Errorf("error parsing %s: %v", testf, err)
continue
}
}
}
var cspTestData = `{
"csp-report": {
"document-uri": "http://localhost:3000/content",
"referrer": "",
"violated-directive": "frame-src",
"effective-directive": "frame-src",
"original-policy": "default-src 'self'; frame-src https://*.mozilla.org; report-uri /report",
"disposition": "enforce",
"blocked-uri": "https://mozilla.org",
"line-number": 1,
"source-file": "http://localhost:3000/content",
"status-code": 200,
"script-sample": ""
}
}`
func TestCSP(t *testing.T) {
sink, uri, cleanup := createTestCollector()
defer cleanup()
doRequest(t, uri, "application/csp-report", cspTestData)
if sink.counter != 1 {
t.Fatalf("parsed %d events, expected 1", sink.counter)
}
}