Bug 1641905 - ThirdPartyUtil::IsThirdPartyWindow for fission - webExtension, r=robwu,ckerschb
authorAndrea Marchesini <amarchesini@mozilla.com>
Tue, 23 Jun 2020 11:52:57 +0000
changeset 536881 3ffee99572221e5541d694cf762c427395fd391a
parent 536880 7a7f2357ab7532e418d9bff935c2a2c1176b159e
child 536882 afddfb994fcfaa50f3643cad8e5be42c396a253c
push id37533
push userdluca@mozilla.com
push dateTue, 23 Jun 2020 21:38:40 +0000
treeherdermozilla-central@d48aa0f0aa0b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrobwu, ckerschb
bugs1641905
milestone79.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 1641905 - ThirdPartyUtil::IsThirdPartyWindow for fission - webExtension, r=robwu,ckerschb Differential Revision: https://phabricator.services.mozilla.com/D80035
caps/BasePrincipal.cpp
caps/ExpandedPrincipal.cpp
dom/base/ThirdPartyUtil.cpp
toolkit/components/extensions/test/xpcshell/test_ext_cookies_firstParty.js
--- a/caps/BasePrincipal.cpp
+++ b/caps/BasePrincipal.cpp
@@ -551,16 +551,21 @@ nsresult BasePrincipal::CheckMayLoadHelp
     }
   }
 
   return NS_ERROR_DOM_BAD_URI;
 }
 
 NS_IMETHODIMP
 BasePrincipal::IsThirdPartyURI(nsIURI* aURI, bool* aRes) {
+  if (AddonPolicy() && AddonAllowsLoad(aURI)) {
+    *aRes = false;
+    return NS_OK;
+  }
+
   *aRes = true;
   // If we do not have a URI its always 3rd party.
   nsCOMPtr<nsIURI> prinURI;
   nsresult rv = GetURI(getter_AddRefs(prinURI));
   if (NS_FAILED(rv) || !prinURI) {
     return NS_OK;
   }
   ThirdPartyUtil* thirdPartyUtil = ThirdPartyUtil::GetInstance();
--- a/caps/ExpandedPrincipal.cpp
+++ b/caps/ExpandedPrincipal.cpp
@@ -363,19 +363,26 @@ already_AddRefed<BasePrincipal> Expanded
   RefPtr<ExpandedPrincipal> expandedPrincipal =
       ExpandedPrincipal::Create(allowList, attrs);
 
   return expandedPrincipal.forget();
 }
 
 NS_IMETHODIMP
 ExpandedPrincipal::IsThirdPartyURI(nsIURI* aURI, bool* aRes) {
-  nsresult rv;
+  // ExpandedPrincipal for extension content scripts consist of two principals,
+  // the document's principal and the extension's principal.
+  // To make sure that the third-party check behaves like the web page on which
+  // the content script is running, ignore the extension's principal.
+
   for (const auto& principal : mPrincipals) {
-    rv = Cast(principal)->IsThirdPartyURI(aURI, aRes);
-    if (NS_WARN_IF(NS_FAILED(rv)) || !*aRes) {
-      return rv;
+    if (!Cast(principal)->AddonPolicy()) {
+      return Cast(principal)->IsThirdPartyURI(aURI, aRes);
     }
   }
 
-  *aRes = true;
-  return NS_OK;
+  if (mPrincipals.IsEmpty()) {
+    *aRes = true;
+    return NS_OK;
+  }
+
+  return Cast(mPrincipals[0])->IsThirdPartyURI(aURI, aRes);
 }
--- a/dom/base/ThirdPartyUtil.cpp
+++ b/dom/base/ThirdPartyUtil.cpp
@@ -283,26 +283,22 @@ ThirdPartyUtil::IsThirdPartyChannel(nsIC
 
   nsAutoCString channelDomain;
   rv = GetBaseDomain(channelURI, channelDomain);
   if (NS_FAILED(rv)) return rv;
 
   if (!doForce) {
     nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
     parentIsThird = loadInfo->GetIsInThirdPartyContext();
-    BasePrincipal* loadingPrincipal =
-        BasePrincipal::Cast(loadInfo->GetLoadingPrincipal());
-    if (!parentIsThird &&
-        loadInfo->GetExternalContentPolicyType() !=
-            nsIContentPolicy::TYPE_DOCUMENT &&
-        (!loadingPrincipal->AddonPolicy() ||
-         !loadingPrincipal->AddonAllowsLoad(channelURI))) {
+    if (!parentIsThird && loadInfo->GetExternalContentPolicyType() !=
+                              nsIContentPolicy::TYPE_DOCUMENT) {
       // Check if the channel itself is third-party to its own requestor.
       // Unforunately, we have to go through the loading principal.
-
+      BasePrincipal* loadingPrincipal =
+          BasePrincipal::Cast(loadInfo->GetLoadingPrincipal());
       rv = loadingPrincipal->IsThirdPartyURI(channelURI, &parentIsThird);
       if (NS_FAILED(rv)) {
         return rv;
       }
     }
   }
 
   // If we're not comparing to a URI, we have our answer. Otherwise, if
--- a/toolkit/components/extensions/test/xpcshell/test_ext_cookies_firstParty.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_cookies_firstParty.js
@@ -41,16 +41,32 @@ function promiseLoadedCookies() {
     });
 
     server.registerPathHandler("/fetch", (request, response) => {
       response.setStatusLine(request.httpVersion, 200, "OK");
       response.setHeader("Content-Type", "text/html; charset=utf-8", false);
       response.write("<html><script>fetch('/checkCookies');</script></html>");
     });
 
+    server.registerPathHandler("/nestedfetch", (request, response) => {
+      response.setStatusLine(request.httpVersion, 200, "OK");
+      response.setHeader("Content-Type", "text/html; charset=utf-8", false);
+      response.write(
+        "<html><iframe src='http://example.net/nestedfetch2'></iframe></html>"
+      );
+    });
+
+    server.registerPathHandler("/nestedfetch2", (request, response) => {
+      response.setStatusLine(request.httpVersion, 200, "OK");
+      response.setHeader("Content-Type", "text/html; charset=utf-8", false);
+      response.write(
+        "<html><iframe src='http://example.org/fetch'></iframe></html>"
+      );
+    });
+
     server.registerPathHandler("/ready", (request, response) => {
       response.setStatusLine(request.httpVersion, 200, "OK");
       response.setHeader("Content-Type", "text/html; charset=utf-8", false);
       response.write("<html></html>");
 
       resolve(cookies);
     });
   });
@@ -118,19 +134,43 @@ add_task(async function test_cookies_fir
 
   // Let's run a fetch()
   cookiesPromise = promiseLoadedCookies();
   contentPage = await ExtensionTestUtils.loadContentPage(url + "?fetch", {
     extension,
   });
 
   // Let's check the cookies received during the last loading.
+  Assert.equal(await cookiesPromise, "none=a; lax=b; strict=c");
+  await contentPage.close();
+
+  // Let's run a fetch() from a nested iframe (extension -> example.net ->
+  // example.org -> fetch)
+  cookiesPromise = promiseLoadedCookies();
+  contentPage = await ExtensionTestUtils.loadContentPage(url + "?nestedfetch", {
+    extension,
+  });
+
+  // Let's check the cookies received during the last loading.
   Assert.equal(await cookiesPromise, "none=a");
   await contentPage.close();
 
+  // Let's run a fetch() from a nested iframe (extension -> example.org -> fetch)
+  cookiesPromise = promiseLoadedCookies();
+  contentPage = await ExtensionTestUtils.loadContentPage(
+    url + "?nestedfetch2",
+    {
+      extension,
+    }
+  );
+
+  // Let's check the cookies received during the last loading.
+  Assert.equal(await cookiesPromise, "none=a; lax=b; strict=c");
+  await contentPage.close();
+
   await extension.unload();
 });
 
 add_task(async function test_cookies_iframes() {
   server.registerPathHandler("/echocookies", (request, response) => {
     response.setStatusLine(request.httpVersion, 200, "OK");
     response.setHeader("Content-Type", "text/html; charset=utf-8", false);
     response.write(