Bug 1647829 - Fixed HTTPS-Only Mode not working when privacy.firstparty.isolate is enabled r=timhuang
authorjulianwels <julianwels@mozilla.com>
Thu, 01 Oct 2020 00:17:14 +0000
changeset 551034 814e24c867dbc75b9b47c20826181239be43915a
parent 551033 73e78c935dea32ebc5e97b893f5d14838e910c80
child 551035 233bb74616ffef2f48e59b61f2652ff3f4f8b06a
push id127627
push userbtara@mozilla.com
push dateThu, 01 Oct 2020 09:03:00 +0000
treeherderautoland@814e24c867db [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstimhuang
bugs1647829
milestone83.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1647829 - Fixed HTTPS-Only Mode not working when privacy.firstparty.isolate is enabled r=timhuang Differential Revision: https://phabricator.services.mozilla.com/D91761
toolkit/actors/AboutHttpsOnlyErrorParent.jsm
toolkit/components/httpsonlyerror/tests/browser/browser_exception.js
--- a/toolkit/actors/AboutHttpsOnlyErrorParent.jsm
+++ b/toolkit/actors/AboutHttpsOnlyErrorParent.jsm
@@ -74,19 +74,30 @@ class AboutHttpsOnlyErrorParent extends 
     // user wants to unbreak the whole page.
     let newURI = aIsIFrame
       ? innerURI
       : innerURI
           .mutate()
           .setScheme("http")
           .finalize();
 
+    const oldOriginAttributes = aBrowser.contentPrincipal.originAttributes;
+    const hasFpiAttribute = !!oldOriginAttributes.firstPartyDomain.length;
+
+    // Create new content principal for the permission. If first-party isolation
+    // is enabled, we have to replace the about-page first-party domain with the
+    // one from the exempt website.
     let principal = Services.scriptSecurityManager.createContentPrincipal(
       newURI,
-      aBrowser.contentPrincipal.originAttributes
+      {
+        ...oldOriginAttributes,
+        firstPartyDomain: hasFpiAttribute
+          ? Services.eTLD.getBaseDomain(newURI)
+          : "",
+      }
     );
 
     // Create exception for this website that expires with the session.
     Services.perms.addFromPrincipal(
       principal,
       "https-only-load-insecure",
       Ci.nsIHttpsOnlyModePermission.LOAD_INSECURE_ALLOW_SESSION,
       Ci.nsIPermissionManager.EXPIRE_SESSION
--- a/toolkit/components/httpsonlyerror/tests/browser/browser_exception.js
+++ b/toolkit/components/httpsonlyerror/tests/browser/browser_exception.js
@@ -36,38 +36,42 @@ const INSECURE_ROOT_PATH = ROOT_PATH.rep
 // |               -> http://file_upgrade_insecure_server.sjs?xhr
 // |               -> http://file_upgrade_insecure_server.sjs?iframe
 // |               -> etc.
 // |
 // +--->[RESPONSE] List of all recorded requests and whether they were loaded
 //                 with HTTP or not (eg.: img-ok, xhr-ok, iframe-error, ...)
 
 add_task(async function() {
-  const openPrivateTab = [false, true];
-  for (let i = 0; i < openPrivateTab.length; i++) {
+  const testCases = ["default", "private", "firstpartyisolation"];
+  for (let i = 0; i < testCases.length; i++) {
     // Call sjs-file with setup query-string and store promise
     let expectedQueries = new Set([
       "content",
       "img",
       "iframe",
       "xhr",
       "nestedimg",
     ]);
 
     const filesLoaded = setupFileServer();
     // Since we don't know when the server has saved all it's variables,
     // let's wait a bit before reloading the page.
     await new Promise(resolve => executeSoon(resolve));
 
     // Create a new private window but reuse the normal one.
     let privateWindow = false;
-    if (openPrivateTab[i]) {
+    if (testCases[i] === "private") {
       privateWindow = await BrowserTestUtils.openNewBrowserWindow({
         private: true,
       });
+    } else if (testCases[i] === "firstpartyisolation") {
+      await SpecialPowers.pushPrefEnv({
+        set: [["privacy.firstparty.isolate", true]],
+      });
     }
 
     // Create new tab with sjs-file requesting content.
     // "supports-insecure.expired.example.com" responds to http and https but
     // with an expired certificate
     let tab = await openErrorPage(
       `${EXPIRED_ROOT_PATH}file_upgrade_insecure_server.sjs?content`,
       false,
@@ -110,19 +114,23 @@ add_task(async function() {
       if (expectedQueries.has(key)) {
         expectedQueries.delete(key);
         is(result, "ok", `Request '${key}' should be loaded with HTTP.'`);
       } else {
         ok(false, `Unexpected response from server (${response})`);
       }
     }
 
-    // Clean up permissions and tab
+    // Clean up permissions, tab and potentially preferences
     Services.perms.removeAll();
 
+    if (testCases[i] === "firstpartyisolation") {
+      await SpecialPowers.popPrefEnv();
+    }
+
     if (privateWindow) {
       await BrowserTestUtils.closeWindow(privateWindow);
     } else {
       gBrowser.removeCurrentTab();
     }
   }
 });