content/base/test/csp/test_csp_bug768029.html

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/base/test/csp/test_csp_bug768029.html	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,223 @@
     1.4 +<!DOCTYPE HTML>
     1.5 +<html>
     1.6 +<!--
     1.7 +  https://bugzilla.mozilla.org/show_bug.cgi?id=768029
     1.8 +-->
     1.9 +<head>
    1.10 +  <meta charset="utf-8">
    1.11 +  <title>Test for CSP on trusted/certified apps -- bug 768029</title>
    1.12 +  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
    1.13 +  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
    1.14 +</head>
    1.15 +<body>
    1.16 +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=768029">Mozilla Bug 768029</a>
    1.17 +<p id="display"></p>
    1.18 +<div id="content">
    1.19 +
    1.20 +</div>
    1.21 +<pre id="test">
    1.22 +<script type="application/javascript;version=1.7">
    1.23 +
    1.24 +Components.utils.import("resource://gre/modules/Services.jsm");
    1.25 +
    1.26 +/** Test for Bug 768029 **/
    1.27 +
    1.28 +// Note: we don't have to inspect all the different operations of CSP,
    1.29 +// we're just looking for specific differences in behavior that indicate
    1.30 +// a default CSP got applied.
    1.31 +const DEFAULT_CSP_PRIV = "default-src *; script-src 'self'; style-src 'self' 'unsafe-inline'; object-src 'none'";
    1.32 +const DEFAULT_CSP_CERT = "default-src *; script-src 'self'; style-src 'self'; object-src 'none'";
    1.33 +
    1.34 +SimpleTest.waitForExplicitFinish();
    1.35 +
    1.36 +var gData = [
    1.37 +  {
    1.38 +    app: "https://example.com/manifest.webapp",
    1.39 +    appStatus: Components.interfaces.nsIPrincipal.APP_STATUS_INSTALLED,
    1.40 +    origin: "https://example.com",
    1.41 +    uri: "https://example.com/tests/content/base/test/csp/file_csp_bug768029.html",
    1.42 +    statusString: "installed app",
    1.43 +    expectedTestResults: {
    1.44 +      max_tests: 7, /* number of bools below plus one for the status check */
    1.45 +      cross_origin: { img: true,  script: true,  style: true },
    1.46 +      same_origin:  { img: true,  script: true,  style: true  },
    1.47 +    },
    1.48 +  },
    1.49 +
    1.50 +  {
    1.51 +    app: "https://example.com/manifest_priv.webapp",
    1.52 +    appStatus: Components.interfaces.nsIPrincipal.APP_STATUS_PRIVILEGED,
    1.53 +    origin: "https://example.com",
    1.54 +    uri: "https://example.com/tests/content/base/test/csp/file_csp_bug768029.html",
    1.55 +    statusString: "privileged app",
    1.56 +    expectedTestResults: {
    1.57 +      max_tests: 7, /* number of bools below plus one for the status check */
    1.58 +      cross_origin: { img: true,  script: false, style: false },
    1.59 +      same_origin:  { img: true,  script: true,  style: true  },
    1.60 +    },
    1.61 +  },
    1.62 +
    1.63 +  {
    1.64 +    app: "https://example.com/manifest_cert.webapp",
    1.65 +    appStatus: Components.interfaces.nsIPrincipal.APP_STATUS_CERTIFIED,
    1.66 +    origin: "https://example.com",
    1.67 +    uri: "https://example.com/tests/content/base/test/csp/file_csp_bug768029.html",
    1.68 +    statusString: "certified app",
    1.69 +    expectedTestResults: {
    1.70 +      max_tests: 7, /* number of bools below plus one for the status check */
    1.71 +      cross_origin: { img: true,  script: false, style: false },
    1.72 +      same_origin:  { img: true,  script: true,  style: true  },
    1.73 +    },
    1.74 +  },
    1.75 +];
    1.76 +
    1.77 +// Observer for watching allowed loads and blocked attempts
    1.78 +function ThingyListener(app, iframe) {
    1.79 +  Services.obs.addObserver(this, "csp-on-violate-policy", false);
    1.80 +  Services.obs.addObserver(this, "http-on-modify-request", false);
    1.81 +  dump("added observers\n");
    1.82 +  // keep track of which app ID this test is monitoring.
    1.83 +  this._testData = app;
    1.84 +  this._expectedResults = app.expectedTestResults;
    1.85 +  this._resultsRecorded = { cross_origin: {}, same_origin: {}};
    1.86 +  this._iframe = iframe;
    1.87 +  this._countedTests = 0;
    1.88 +}
    1.89 +ThingyListener.prototype = {
    1.90 +
    1.91 +  observe: function(subject, topic, data) {
    1.92 +    // make sure to only observe app-generated calls to the helper for this test.
    1.93 +    var testpat = new RegExp("file_csp_bug768029\\.sjs");
    1.94 +
    1.95 +    // used to extract which kind of load this is (img, script, etc).
    1.96 +    var typepat = new RegExp("type=([\\_a-z0-9]+)");
    1.97 +
    1.98 +    // used to identify whether it's cross-origin or same-origin loads
    1.99 +    // (the applied CSP allows same-origin loads).
   1.100 +    var originpat = new RegExp("origin=([\\_a-z0-9]+)");
   1.101 +
   1.102 +    if (topic === "http-on-modify-request") {
   1.103 +      // Matching requests on this topic were allowed by the csp
   1.104 +      var chan = subject.QueryInterface(Components.interfaces.nsIHttpChannel);
   1.105 +      var uri = chan.URI;
   1.106 +      // ignore irrelevent URIs
   1.107 +      if (!testpat.test(uri.asciiSpec)) return;
   1.108 +
   1.109 +      var loadType = typepat.exec(uri.asciiSpec)[1];
   1.110 +      var originType = originpat.exec(uri.asciiSpec)[1];
   1.111 +
   1.112 +      // skip duplicate hits to this topic (potentially document loads
   1.113 +      // may generate duplicate loads.
   1.114 +      if (this._resultsRecorded[originType] &&
   1.115 +          this._resultsRecorded[originType][loadType]) {
   1.116 +        return;
   1.117 +      }
   1.118 +      var message = originType + " : " + loadType + " should be " +
   1.119 +                    (this._expectedResults[originType][loadType] ? "allowed" : "blocked");
   1.120 +      ok(this._expectedResults[originType][loadType] == true, message);
   1.121 +      this._resultsRecorded[originType][loadType] = true;
   1.122 +      this._countedTests++;
   1.123 +    }
   1.124 +    else if (topic === "csp-on-violate-policy") {
   1.125 +      // Matching hits on this topic were blocked by the csp
   1.126 +      var uri = subject.QueryInterface(Components.interfaces.nsIURI);
   1.127 +      // ignore irrelevent URIs
   1.128 +      if (!testpat.test(uri.asciiSpec)) return;
   1.129 +
   1.130 +      var loadType = typepat.exec(uri.asciiSpec)[1];
   1.131 +      var originType = originpat.exec(uri.asciiSpec)[1];
   1.132 +
   1.133 +      // skip duplicate hits to this topic (potentially document loads
   1.134 +      // may generate duplicate loads.
   1.135 +      if (this._resultsRecorded[originType] &&
   1.136 +          this._resultsRecorded[originType][loadType]) {
   1.137 +        return;
   1.138 +      }
   1.139 +
   1.140 +      var message = originType + " : " + loadType + " should be " +
   1.141 +                    (this._expectedResults[originType][loadType] ? "allowed" : "blocked");
   1.142 +      ok(this._expectedResults[originType][loadType] == false, message);
   1.143 +      this._resultsRecorded[originType][loadType] = true;
   1.144 +      this._countedTests++;
   1.145 +    }
   1.146 +    else {
   1.147 +      // wrong topic!  Nothing to do.
   1.148 +      return;
   1.149 +    }
   1.150 +
   1.151 +    this._checkForFinish();
   1.152 +  },
   1.153 +
   1.154 +  _checkForFinish: function() {
   1.155 +    // check to see if there are load tests still pending.
   1.156 +    // (All requests triggered by the app should hit one of the
   1.157 +    // two observer topics.)
   1.158 +    if (this._countedTests == this._expectedResults.max_tests) {
   1.159 +      Services.obs.removeObserver(this, "csp-on-violate-policy");
   1.160 +      Services.obs.removeObserver(this, "http-on-modify-request");
   1.161 +      dump("removed observers\n");
   1.162 +      checkedCount++;
   1.163 +      if (checkedCount == checksTodo) {
   1.164 +        SpecialPowers.removePermission("browser", "https://example.com");
   1.165 +        SimpleTest.finish();
   1.166 +      } else {
   1.167 +        gTestRunner.next();
   1.168 +      }
   1.169 +    }
   1.170 +  },
   1.171 +
   1.172 +  // verify the status of the app
   1.173 +  checkAppStatus: function() {
   1.174 +    var principal = this._iframe.contentDocument.nodePrincipal;
   1.175 +    if (this._testData.app) {
   1.176 +      is(principal.appStatus, this._testData.appStatus,
   1.177 +         "iframe principal's app status doesn't match the expected app status.");
   1.178 +      this._countedTests++;
   1.179 +      this._checkForFinish();
   1.180 +    }
   1.181 +  }
   1.182 +}
   1.183 +
   1.184 +var content = document.getElementById('content');
   1.185 +var checkedCount = 0; // number of apps checked
   1.186 +var checksTodo = gData.length;
   1.187 +
   1.188 +// quick check to make sure we can test apps:
   1.189 +is('appStatus' in document.nodePrincipal, true,
   1.190 +   'appStatus should be present in nsIPrincipal, if not the rest of this test will fail');
   1.191 +
   1.192 +function runTest() {
   1.193 +  for (var i = 0; i < gData.length; i++) {
   1.194 +    let data = gData[i];
   1.195 +    var iframe = document.createElement('iframe');
   1.196 +
   1.197 +    // watch for successes and failures
   1.198 +    var examiner = new ThingyListener(data, iframe);
   1.199 +
   1.200 +    iframe.setAttribute('mozapp', data.app);
   1.201 +    iframe.setAttribute('mozbrowser', 'true');
   1.202 +    iframe.addEventListener('load', examiner.checkAppStatus.bind(examiner));
   1.203 +    iframe.src = data.uri;
   1.204 +
   1.205 +    content.appendChild(iframe);
   1.206 +
   1.207 +    yield undefined;
   1.208 +  }
   1.209 +}
   1.210 +
   1.211 +var gTestRunner = runTest();
   1.212 +
   1.213 +// load the default CSP and pref it on
   1.214 +SpecialPowers.addPermission("browser", true, "https://example.com");
   1.215 +SpecialPowers.pushPrefEnv({'set': [["dom.mozBrowserFramesEnabled", true],
   1.216 +                                   ["security.apps.privileged.CSP.default", DEFAULT_CSP_PRIV],
   1.217 +                                   ["security.apps.certified.CSP.default", DEFAULT_CSP_CERT],
   1.218 +                                   ["security.mixed_content.block_active_content", false],
   1.219 +                                   ["security.mixed_content.block_display_content", false]]},
   1.220 +                          function() {  gTestRunner.next(); });
   1.221 +
   1.222 +
   1.223 +</script>
   1.224 +</pre>
   1.225 +</body>
   1.226 +</html>

mercurial