content/base/test/csp/test_bug836922_npolicies.html

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 <!DOCTYPE HTML>
     2 <html>
     3 <head>
     4   <title>Test for Content Security Policy multiple policy support (regular and Report-Only mode)</title>
     5   <script type="text/javascript" src="/MochiKit/packed.js"></script>
     6   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
     7   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
     8 </head>
     9 <body>
    10 <p id="display"></p>
    11 <div id="content" style="display: none">
    12 </div>
    14 <iframe style="width:200px;height:200px;" id='cspframe'></iframe>
    15 <script class="testbody" type="text/javascript">
    17 var path = "/tests/content/base/test/csp/";
    19 // These are test results: verified indicates whether or not the test has run.
    20 // true/false is the pass/fail result.
    21 window.loads = {
    22   css_self: {expected: true, verified: false},
    23   css_examplecom: {expected: false, verified: false},
    24   img_self: {expected: false, verified: false},
    25   img_examplecom: {expected: false, verified: false},
    26   script_self: {expected: true, verified: false},
    27 };
    29 window.violation_reports = {
    30   css_self:
    31   {expected: 0, expected_ro: 0},  /* totally fine */
    32   css_examplecom:
    33   {expected: 1, expected_ro: 0},  /* violates enforced CSP */
    34   img_self:
    35   {expected: 1, expected_ro: 0},  /* violates enforced CSP */
    36   img_examplecom:
    37   {expected: 1, expected_ro: 1},  /* violates both CSPs */
    38   script_self:
    39   {expected: 0, expected_ro: 1},  /* violates report-only */
    40 };
    42 // This is used to watch the blocked data bounce off CSP and allowed data
    43 // get sent out to the wire.  This also watches for violation reports to go out.
    44 function examiner() {
    45   SpecialPowers.addObserver(this, "csp-on-violate-policy", false);
    46   SpecialPowers.addObserver(this, "specialpowers-http-notify-request", false);
    47 }
    48 examiner.prototype  = {
    49   observe: function(subject, topic, data) {
    50     var testpat = new RegExp("testid=([a-z0-9_]+)");
    52     if (topic === "specialpowers-http-notify-request") {
    53       var uri = data;
    54       if (!testpat.test(uri)) return;
    55       var testid = testpat.exec(uri)[1];
    57       // violation reports don't come through here, but the requested resources do
    58       // if the test has already finished, move on.  Some things throw multiple
    59       // requests (preloads and such)
    60       try {
    61         if (window.loads[testid].verified) return;
    62       } catch(e) { return; }
    64       // these are requests that were allowed by CSP
    65       var testid = testpat.exec(uri)[1];
    66       window.testResult(testid, 'allowed', uri + " allowed by csp");
    67     }
    69     if(topic === "csp-on-violate-policy") {
    70       // if the violated policy was report-only, the resource will still be
    71       // loaded even if this topic is notified.
    72       var asciiSpec = SpecialPowers.getPrivilegedProps(
    73                         SpecialPowers.do_QueryInterface(subject, "nsIURI"),
    74                         "asciiSpec");
    75       if (!testpat.test(asciiSpec)) return;
    76       var testid = testpat.exec(asciiSpec)[1];
    78       // if the test has already finished, move on.
    79       try {
    80         if (window.loads[testid].verified) return;
    81       } catch(e) { return; }
    83       // record the ones that were supposed to be blocked, but don't use this
    84       // as an indicator for tests that are not blocked but do generate reports.
    85       // We skip recording the result if the load is expected since a
    86       // report-only policy will generate a request *and* a violation note.
    87       if (!window.loads[testid].expected) {
    88         window.testResult(testid,
    89                           'blocked',
    90                           asciiSpec + " blocked by \"" + data + "\"");
    91       }
    92     }
    94     // if any test is unverified, keep waiting
    95     for (var v in window.loads) {
    96       if(!window.loads[v].verified) {
    97         return;
    98       }
    99     }
   101     window.bug836922examiner.remove();
   102     window.resultPoller.pollForFinish();
   103   },
   105   // must eventually call this to remove the listener,
   106   // or mochitests might get borked.
   107   remove: function() {
   108     SpecialPowers.removeObserver(this, "csp-on-violate-policy");
   109     SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
   110   }
   111 }
   112 window.bug836922examiner = new examiner();
   115 // Poll for results and see if enough reports came in.  Keep trying
   116 // for a few seconds before failing with lack of reports.
   117 // Have to do this because there's a race between the async reporting
   118 // and this test finishing, and we don't want to win the race.
   119 window.resultPoller = {
   121   POLL_ATTEMPTS_LEFT: 14,
   123   pollForFinish:
   124   function() {
   125     var vr = resultPoller.tallyReceivedReports();
   126     if (resultPoller.verifyReports(vr, resultPoller.POLL_ATTEMPTS_LEFT < 1)) {
   127       // report success condition.
   128       resultPoller.resetReportServer();
   129       SimpleTest.finish();
   130     } else {
   131       resultPoller.POLL_ATTEMPTS_LEFT--;
   132       // try again unless we reached the threshold.
   133       setTimeout(resultPoller.pollForFinish, 100);
   134     }
   135   },
   137   resetReportServer:
   138   function() {
   139     var xhr = new XMLHttpRequest();
   140     var xhr_ro = new XMLHttpRequest();
   141     xhr.open("GET", "file_bug836922_npolicies_violation.sjs?reset", false);
   142     xhr_ro.open("GET", "file_bug836922_npolicies_ro_violation.sjs?reset", false);
   143     xhr.send(null);
   144     xhr_ro.send(null);
   145   },
   147   tallyReceivedReports:
   148   function() {
   149     var xhr = new XMLHttpRequest();
   150     var xhr_ro = new XMLHttpRequest();
   151     xhr.open("GET", "file_bug836922_npolicies_violation.sjs?results", false);
   152     xhr_ro.open("GET", "file_bug836922_npolicies_ro_violation.sjs?results", false);
   153     xhr.send(null);
   154     xhr_ro.send(null);
   156     var received = JSON.parse(xhr.responseText);
   157     var received_ro = JSON.parse(xhr_ro.responseText);
   159     var results = {enforced: {}, reportonly: {}};
   160     for (var r in window.violation_reports) {
   161       results.enforced[r] = 0;
   162       results.reportonly[r] = 0;
   163     }
   165     for (var r in received) {
   166       results.enforced[r] += received[r];
   167     }
   168     for (var r in received_ro) {
   169       results.reportonly[r] += received_ro[r];
   170     }
   172     return results;
   173   },
   175   verifyReports:
   176   function(receivedCounts, lastAttempt) {
   177     for (var r in window.violation_reports) {
   178       var exp = window.violation_reports[r].expected;
   179       var exp_ro = window.violation_reports[r].expected_ro;
   180       var rec = receivedCounts.enforced[r];
   181       var rec_ro = receivedCounts.reportonly[r];
   183       // if this test breaks, these are helpful dumps:
   184       //dump(">>> Verifying " + r + "\n");
   185       //dump("  > Expected: " + exp + " / " + exp_ro + " (ro)\n");
   186       //dump("  > Received: " + rec + " / " + rec_ro + " (ro) \n");
   188       // in all cases, we're looking for *at least* the expected number of
   189       // reports of each type (there could be more in some edge cases).
   190       // If there are not enough, we keep waiting and poll the server again
   191       // later.  If there are enough, we can successfully finish.
   193       if (exp == 0)
   194         is(rec, 0,
   195           "Expected zero enforced-policy violation " +
   196           "reports for " + r + ", got " + rec);
   197       else if (lastAttempt)
   198         ok(rec >= exp,
   199           "Received (" + rec + "/" + exp + ") " +
   200           "enforced-policy reports for " + r);
   201       else if (rec < exp)
   202         return false; // continue waiting for more
   204       if(exp_ro == 0)
   205         is(rec_ro, 0,
   206           "Expected zero report-only-policy violation " +
   207           "reports for " + r + ", got " + rec_ro);
   208       else if (lastAttempt)
   209         ok(rec_ro >= exp_ro,
   210           "Received (" + rec_ro + "/" + exp_ro + ") " +
   211           "report-only-policy reports for " + r);
   212       else if (rec_ro < exp_ro)
   213         return false; // continue waiting for more
   214     }
   216     // if we complete the loop, we've found all of the violation
   217     // reports we expect.
   218     if (lastAttempt) return true;
   220     // Repeat successful tests once more to record successes via ok()
   221     return resultPoller.verifyReports(receivedCounts, true);
   222   }
   223 };
   225 window.testResult = function(testname, result, msg) {
   226   // otherwise, make sure the allowed ones are expected and blocked ones are not.
   227   if (window.loads[testname].expected) {
   228     is(result, 'allowed', ">> " + msg);
   229   } else {
   230     is(result, 'blocked', ">> " + msg);
   231   }
   232   window.loads[testname].verified = true;
   233 }
   236 SimpleTest.waitForExplicitFinish();
   238 SpecialPowers.pushPrefEnv(
   239   {'set':[["security.csp.speccompliant", true]]},
   240    function() {
   241     // save this for last so that our listeners are registered.
   242     // ... this loads the testbed of good and bad requests.
   243     document.getElementById('cspframe').src = 'http://mochi.test:8888' + path + 'file_bug836922_npolicies.html';
   244   });
   246 </script>
   247 </pre>
   248 </body>
   249 </html>

mercurial