content/base/test/csp/test_csp_bug773891.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 <!--
     4   https://bugzilla.mozilla.org/show_bug.cgi?id=768029
     5 -->
     6 <head>
     7   <meta charset="utf-8">
     8   <title>Test for CSP on trusted/certified and installed apps -- bug 773891</title>
     9   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
    10   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
    11 </head>
    12 <body>
    13 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=773891">Mozilla Bug 773891</a>
    14 <p id="display"></p>
    15 <div id="content">
    17 </div>
    18 <pre id="test">
    19 <script type="application/javascript;version=1.7">
    21 Components.utils.import("resource://gre/modules/Services.jsm");
    23 /** Test for Bug 773891 **/
    25 // Note: we don't have to inspect all the different operations of CSP,
    26 // we're just looking for specific differences in behavior that indicate
    27 // a default CSP got applied.
    28 const DEFAULT_CSP_PRIV = "default-src *; script-src *; style-src 'self' 'unsafe-inline'; object-src 'none'";
    29 const DEFAULT_CSP_CERT = "default-src *; script-src *; style-src 'self'; object-src 'none'";
    31 const MANIFEST_CSP_PRIV = "default-src *; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline'";
    32 const MANIFEST_CSP_INST = "default-src *; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline'";
    33 const MANIFEST_CSP_CERT = "default-src *; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline'";
    35 SimpleTest.waitForExplicitFinish();
    37 var gData = [
    39   {
    40     app: "https://example.com/manifest_csp_inst.webapp",
    41     appStatus: Components.interfaces.nsIPrincipal.APP_STATUS_INSTALLED,
    42     csp: MANIFEST_CSP_INST,
    43     origin: "https://example.com",
    44     uri: "https://example.com/tests/content/base/test/csp/file_csp_bug773891.html",
    45     statusString: "installed app",
    46     expectedTestResults: {
    47       max_tests: 7, /* number of bools below plus one for the status check */
    48       cross_origin: { img: true,  script: false, style: false },
    49       same_origin:  { img: true,  script: true,  style: true  },
    50     },
    51   },
    52   {
    53     app: "https://example.com/manifest_csp_cert.webapp",
    54     appStatus: Components.interfaces.nsIPrincipal.APP_STATUS_CERTIFIED,
    55     csp: MANIFEST_CSP_CERT,
    56     origin: "https://example.com",
    57     uri: "https://example.com/tests/content/base/test/csp/file_csp_bug773891.html",
    58     statusString: "certified app",
    59     expectedTestResults: {
    60       max_tests: 7, /* number of bools below plus one for the status check */
    61       cross_origin: { img: true,  script: false, style: false },
    62       same_origin:  { img: true,  script: true,  style: true  },
    63     },
    64   },
    65   {
    66     app: "https://example.com/manifest_csp_priv.webapp",
    67     appStatus: Components.interfaces.nsIPrincipal.APP_STATUS_PRIVILEGED,
    68     csp: MANIFEST_CSP_PRIV,
    69     origin: "https://example.com",
    70     uri: "https://example.com/tests/content/base/test/csp/file_csp_bug773891.html",
    71     statusString: "privileged app",
    72     expectedTestResults: {
    73       max_tests: 7, /* number of bools below plus one for the status check */
    74       cross_origin: { img: true,  script: false, style: false },
    75       same_origin:  { img: true,  script: true,  style: true  },
    76     },
    77   },
    78 ];
    80 // Observer for watching allowed loads and blocked attempts
    81 function ThingyListener(app, iframe) {
    82   Services.obs.addObserver(this, "csp-on-violate-policy", false);
    83   Services.obs.addObserver(this, "http-on-modify-request", false);
    84   dump("added observers\n");
    85   // keep track of which app ID this test is monitoring.
    86   this._testData = app;
    87   this._expectedResults = app.expectedTestResults;
    88   this._resultsRecorded = { cross_origin: {}, same_origin: {}};
    89   this._iframe = iframe;
    90   this._countedTests = 0;
    91 }
    92 ThingyListener.prototype = {
    94   observe: function(subject, topic, data) {
    95     // make sure to only observe app-generated calls to the helper for this test.
    96     var testpat = new RegExp("file_csp_bug773891\\.sjs");
    98     // used to extract which kind of load this is (img, script, etc).
    99     var typepat = new RegExp("type=([\\_a-z0-9]+)");
   101     // used to identify whether it's cross-origin or same-origin loads
   102     // (the applied CSP allows same-origin loads).
   103     var originpat = new RegExp("origin=([\\_a-z0-9]+)");
   105     if (topic === "http-on-modify-request") {
   106       // Matching requests on this topic were allowed by the csp
   107       var chan = subject.QueryInterface(Components.interfaces.nsIHttpChannel);
   108       var uri = chan.URI;
   109       // ignore irrelevent URIs
   110       if (!testpat.test(uri.asciiSpec)) return;
   112       var loadType = typepat.exec(uri.asciiSpec)[1];
   113       var originType = originpat.exec(uri.asciiSpec)[1];
   115       // skip duplicate hits to this topic (potentially document loads
   116       // may generate duplicate loads.
   117       if (this._resultsRecorded[originType] &&
   118           this._resultsRecorded[originType][loadType]) {
   119         return;
   120       }
   121       var message = originType + " : " + loadType + " should be " +
   122                     (this._expectedResults[originType][loadType] ? "allowed" : "blocked");
   123       ok(this._expectedResults[originType][loadType] == true, message);
   124       this._resultsRecorded[originType][loadType] = true;
   125       this._countedTests++;
   126     }
   127     else if (topic === "csp-on-violate-policy") {
   128       // Matching hits on this topic were blocked by the csp
   129       var uri = subject.QueryInterface(Components.interfaces.nsIURI);
   130       // ignore irrelevent URIs
   131       if (!testpat.test(uri.asciiSpec)) return;
   133       var loadType = typepat.exec(uri.asciiSpec)[1];
   134       var originType = originpat.exec(uri.asciiSpec)[1];
   136       // skip duplicate hits to this topic (potentially document loads
   137       // may generate duplicate loads.
   138       if (this._resultsRecorded[originType] &&
   139           this._resultsRecorded[originType][loadType]) {
   140         return;
   141       }
   143       var message = originType + " : " + loadType + " should be " +
   144                     (this._expectedResults[originType][loadType] ? "allowed" : "blocked");
   145       ok(this._expectedResults[originType][loadType] == false, message);
   146       this._resultsRecorded[originType][loadType] = true;
   147       this._countedTests++;
   148     }
   149     else {
   150       // wrong topic!  Nothing to do.
   151       return;
   152     }
   154     this._checkForFinish();
   155   },
   157   _checkForFinish: function() {
   158     // check to see if there are load tests still pending.
   159     // (All requests triggered by the app should hit one of the
   160     // two observer topics.)
   161     if (this._countedTests == this._expectedResults.max_tests) {
   162       Services.obs.removeObserver(this, "csp-on-violate-policy");
   163       Services.obs.removeObserver(this, "http-on-modify-request");
   164       dump("removed observers\n");
   165       checkedCount++;
   166       if (checkedCount == checksTodo) {
   167         SpecialPowers.removePermission("browser", "https://example.com");
   168         SimpleTest.finish();
   169       } else {
   170         gTestRunner.next();
   171       }
   172     }
   173   },
   175   // verify the status of the app
   176   checkAppStatus: function() {
   177     var principal = this._iframe.contentDocument.nodePrincipal;
   178     if (this._testData.app) {
   179       is(principal.appStatus, this._testData.appStatus,
   180          "iframe principal's app status doesn't match the expected app status.");
   181       this._countedTests++;
   182       this._checkForFinish();
   183     }
   184   }
   185 }
   187 var content = document.getElementById('content');
   188 var checkedCount = 0; // number of apps checked
   189 var checksTodo = gData.length;
   191 // quick check to make sure we can test apps:
   192 is('appStatus' in document.nodePrincipal, true,
   193    'appStatus should be present in nsIPrincipal, if not the rest of this test will fail');
   195 function runTest() {
   196   for (var i = 0; i < gData.length; i++) {
   197     let data = gData[i];
   198     var iframe = document.createElement('iframe');
   200     // watch for successes and failures
   201     var examiner = new ThingyListener(data, iframe);
   203     iframe.setAttribute('mozapp', data.app);
   204     iframe.setAttribute('mozbrowser', 'true');
   205     iframe.addEventListener('load', examiner.checkAppStatus.bind(examiner));
   206     iframe.src = data.uri;
   208     content.appendChild(iframe);
   210     yield undefined;
   211   }
   212 }
   214 var gTestRunner = runTest();
   216 // load the default CSP and pref it on
   217 SpecialPowers.addPermission("browser", true, "https://example.com");
   219 SpecialPowers.pushPrefEnv({'set': [["dom.mozBrowserFramesEnabled", true],
   220                                    ["security.apps.privileged.CSP.default", DEFAULT_CSP_PRIV],
   221                                    ["security.apps.certified.CSP.default", DEFAULT_CSP_CERT]]},
   222                           function() {  gTestRunner.next(); });
   225 </script>
   226 </pre>
   227 </body>
   228 </html>

mercurial