content/base/test/csp/test_csp_bug773891.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_bug773891.html	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,228 @@
     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 and installed apps -- bug 773891</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=773891">Mozilla Bug 773891</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 773891 **/
    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 *; style-src 'self' 'unsafe-inline'; object-src 'none'";
    1.32 +const DEFAULT_CSP_CERT = "default-src *; script-src *; style-src 'self'; object-src 'none'";
    1.33 +
    1.34 +const MANIFEST_CSP_PRIV = "default-src *; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline'";
    1.35 +const MANIFEST_CSP_INST = "default-src *; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline'";
    1.36 +const MANIFEST_CSP_CERT = "default-src *; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline'";
    1.37 +
    1.38 +SimpleTest.waitForExplicitFinish();
    1.39 +
    1.40 +var gData = [
    1.41 +
    1.42 +  {
    1.43 +    app: "https://example.com/manifest_csp_inst.webapp",
    1.44 +    appStatus: Components.interfaces.nsIPrincipal.APP_STATUS_INSTALLED,
    1.45 +    csp: MANIFEST_CSP_INST,
    1.46 +    origin: "https://example.com",
    1.47 +    uri: "https://example.com/tests/content/base/test/csp/file_csp_bug773891.html",
    1.48 +    statusString: "installed app",
    1.49 +    expectedTestResults: {
    1.50 +      max_tests: 7, /* number of bools below plus one for the status check */
    1.51 +      cross_origin: { img: true,  script: false, style: false },
    1.52 +      same_origin:  { img: true,  script: true,  style: true  },
    1.53 +    },
    1.54 +  },
    1.55 +  {
    1.56 +    app: "https://example.com/manifest_csp_cert.webapp",
    1.57 +    appStatus: Components.interfaces.nsIPrincipal.APP_STATUS_CERTIFIED,
    1.58 +    csp: MANIFEST_CSP_CERT,
    1.59 +    origin: "https://example.com",
    1.60 +    uri: "https://example.com/tests/content/base/test/csp/file_csp_bug773891.html",
    1.61 +    statusString: "certified app",
    1.62 +    expectedTestResults: {
    1.63 +      max_tests: 7, /* number of bools below plus one for the status check */
    1.64 +      cross_origin: { img: true,  script: false, style: false },
    1.65 +      same_origin:  { img: true,  script: true,  style: true  },
    1.66 +    },
    1.67 +  },
    1.68 +  {
    1.69 +    app: "https://example.com/manifest_csp_priv.webapp",
    1.70 +    appStatus: Components.interfaces.nsIPrincipal.APP_STATUS_PRIVILEGED,
    1.71 +    csp: MANIFEST_CSP_PRIV,
    1.72 +    origin: "https://example.com",
    1.73 +    uri: "https://example.com/tests/content/base/test/csp/file_csp_bug773891.html",
    1.74 +    statusString: "privileged app",
    1.75 +    expectedTestResults: {
    1.76 +      max_tests: 7, /* number of bools below plus one for the status check */
    1.77 +      cross_origin: { img: true,  script: false, style: false },
    1.78 +      same_origin:  { img: true,  script: true,  style: true  },
    1.79 +    },
    1.80 +  },
    1.81 +];
    1.82 +
    1.83 +// Observer for watching allowed loads and blocked attempts
    1.84 +function ThingyListener(app, iframe) {
    1.85 +  Services.obs.addObserver(this, "csp-on-violate-policy", false);
    1.86 +  Services.obs.addObserver(this, "http-on-modify-request", false);
    1.87 +  dump("added observers\n");
    1.88 +  // keep track of which app ID this test is monitoring.
    1.89 +  this._testData = app;
    1.90 +  this._expectedResults = app.expectedTestResults;
    1.91 +  this._resultsRecorded = { cross_origin: {}, same_origin: {}};
    1.92 +  this._iframe = iframe;
    1.93 +  this._countedTests = 0;
    1.94 +}
    1.95 +ThingyListener.prototype = {
    1.96 +
    1.97 +  observe: function(subject, topic, data) {
    1.98 +    // make sure to only observe app-generated calls to the helper for this test.
    1.99 +    var testpat = new RegExp("file_csp_bug773891\\.sjs");
   1.100 +
   1.101 +    // used to extract which kind of load this is (img, script, etc).
   1.102 +    var typepat = new RegExp("type=([\\_a-z0-9]+)");
   1.103 +
   1.104 +    // used to identify whether it's cross-origin or same-origin loads
   1.105 +    // (the applied CSP allows same-origin loads).
   1.106 +    var originpat = new RegExp("origin=([\\_a-z0-9]+)");
   1.107 +
   1.108 +    if (topic === "http-on-modify-request") {
   1.109 +      // Matching requests on this topic were allowed by the csp
   1.110 +      var chan = subject.QueryInterface(Components.interfaces.nsIHttpChannel);
   1.111 +      var uri = chan.URI;
   1.112 +      // ignore irrelevent URIs
   1.113 +      if (!testpat.test(uri.asciiSpec)) return;
   1.114 +
   1.115 +      var loadType = typepat.exec(uri.asciiSpec)[1];
   1.116 +      var originType = originpat.exec(uri.asciiSpec)[1];
   1.117 +
   1.118 +      // skip duplicate hits to this topic (potentially document loads
   1.119 +      // may generate duplicate loads.
   1.120 +      if (this._resultsRecorded[originType] &&
   1.121 +          this._resultsRecorded[originType][loadType]) {
   1.122 +        return;
   1.123 +      }
   1.124 +      var message = originType + " : " + loadType + " should be " +
   1.125 +                    (this._expectedResults[originType][loadType] ? "allowed" : "blocked");
   1.126 +      ok(this._expectedResults[originType][loadType] == true, message);
   1.127 +      this._resultsRecorded[originType][loadType] = true;
   1.128 +      this._countedTests++;
   1.129 +    }
   1.130 +    else if (topic === "csp-on-violate-policy") {
   1.131 +      // Matching hits on this topic were blocked by the csp
   1.132 +      var uri = subject.QueryInterface(Components.interfaces.nsIURI);
   1.133 +      // ignore irrelevent URIs
   1.134 +      if (!testpat.test(uri.asciiSpec)) return;
   1.135 +
   1.136 +      var loadType = typepat.exec(uri.asciiSpec)[1];
   1.137 +      var originType = originpat.exec(uri.asciiSpec)[1];
   1.138 +
   1.139 +      // skip duplicate hits to this topic (potentially document loads
   1.140 +      // may generate duplicate loads.
   1.141 +      if (this._resultsRecorded[originType] &&
   1.142 +          this._resultsRecorded[originType][loadType]) {
   1.143 +        return;
   1.144 +      }
   1.145 +
   1.146 +      var message = originType + " : " + loadType + " should be " +
   1.147 +                    (this._expectedResults[originType][loadType] ? "allowed" : "blocked");
   1.148 +      ok(this._expectedResults[originType][loadType] == false, message);
   1.149 +      this._resultsRecorded[originType][loadType] = true;
   1.150 +      this._countedTests++;
   1.151 +    }
   1.152 +    else {
   1.153 +      // wrong topic!  Nothing to do.
   1.154 +      return;
   1.155 +    }
   1.156 +
   1.157 +    this._checkForFinish();
   1.158 +  },
   1.159 +
   1.160 +  _checkForFinish: function() {
   1.161 +    // check to see if there are load tests still pending.
   1.162 +    // (All requests triggered by the app should hit one of the
   1.163 +    // two observer topics.)
   1.164 +    if (this._countedTests == this._expectedResults.max_tests) {
   1.165 +      Services.obs.removeObserver(this, "csp-on-violate-policy");
   1.166 +      Services.obs.removeObserver(this, "http-on-modify-request");
   1.167 +      dump("removed observers\n");
   1.168 +      checkedCount++;
   1.169 +      if (checkedCount == checksTodo) {
   1.170 +        SpecialPowers.removePermission("browser", "https://example.com");
   1.171 +        SimpleTest.finish();
   1.172 +      } else {
   1.173 +        gTestRunner.next();
   1.174 +      }
   1.175 +    }
   1.176 +  },
   1.177 +
   1.178 +  // verify the status of the app
   1.179 +  checkAppStatus: function() {
   1.180 +    var principal = this._iframe.contentDocument.nodePrincipal;
   1.181 +    if (this._testData.app) {
   1.182 +      is(principal.appStatus, this._testData.appStatus,
   1.183 +         "iframe principal's app status doesn't match the expected app status.");
   1.184 +      this._countedTests++;
   1.185 +      this._checkForFinish();
   1.186 +    }
   1.187 +  }
   1.188 +}
   1.189 +
   1.190 +var content = document.getElementById('content');
   1.191 +var checkedCount = 0; // number of apps checked
   1.192 +var checksTodo = gData.length;
   1.193 +
   1.194 +// quick check to make sure we can test apps:
   1.195 +is('appStatus' in document.nodePrincipal, true,
   1.196 +   'appStatus should be present in nsIPrincipal, if not the rest of this test will fail');
   1.197 +
   1.198 +function runTest() {
   1.199 +  for (var i = 0; i < gData.length; i++) {
   1.200 +    let data = gData[i];
   1.201 +    var iframe = document.createElement('iframe');
   1.202 +
   1.203 +    // watch for successes and failures
   1.204 +    var examiner = new ThingyListener(data, iframe);
   1.205 +
   1.206 +    iframe.setAttribute('mozapp', data.app);
   1.207 +    iframe.setAttribute('mozbrowser', 'true');
   1.208 +    iframe.addEventListener('load', examiner.checkAppStatus.bind(examiner));
   1.209 +    iframe.src = data.uri;
   1.210 +
   1.211 +    content.appendChild(iframe);
   1.212 +
   1.213 +    yield undefined;
   1.214 +  }
   1.215 +}
   1.216 +
   1.217 +var gTestRunner = runTest();
   1.218 +
   1.219 +// load the default CSP and pref it on
   1.220 +SpecialPowers.addPermission("browser", true, "https://example.com");
   1.221 +
   1.222 +SpecialPowers.pushPrefEnv({'set': [["dom.mozBrowserFramesEnabled", true],
   1.223 +                                   ["security.apps.privileged.CSP.default", DEFAULT_CSP_PRIV],
   1.224 +                                   ["security.apps.certified.CSP.default", DEFAULT_CSP_CERT]]},
   1.225 +                          function() {  gTestRunner.next(); });
   1.226 +
   1.227 +
   1.228 +</script>
   1.229 +</pre>
   1.230 +</body>
   1.231 +</html>

mercurial