Bug 1536411 - StoragePrincipal - part 6 - Cookies, r=Ehsan
authorAndrea Marchesini <amarchesini@mozilla.com>
Fri, 12 Apr 2019 05:30:43 +0000
changeset 469239 c1074e3a0d5fbc17d6763d02593203ab0cccb4e7
parent 469238 ed51986b7628c1791c384c5aaaadd5ddf5c46ab7
child 469240 9fd7d42e7f557667dc8c972b68e49b9881a4cef5
push id112776
push usershindli@mozilla.com
push dateFri, 12 Apr 2019 16:20:17 +0000
treeherdermozilla-inbound@b4501ced5619 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersEhsan
bugs1536411
milestone68.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 1536411 - StoragePrincipal - part 6 - Cookies, r=Ehsan Differential Revision: https://phabricator.services.mozilla.com/D24864
dom/html/nsHTMLDocument.cpp
netwerk/base/nsNetUtil.cpp
netwerk/base/nsNetUtil.h
netwerk/cookie/CookieServiceChild.cpp
netwerk/cookie/CookieServiceParent.cpp
netwerk/cookie/CookieServiceParent.h
netwerk/cookie/PCookieService.ipdl
netwerk/cookie/nsCookieService.cpp
toolkit/components/antitracking/StoragePrincipalHelper.cpp
toolkit/components/antitracking/StoragePrincipalHelper.h
toolkit/components/antitracking/test/browser/browser.ini
toolkit/components/antitracking/test/browser/browser_partitionedCookies.js
toolkit/components/antitracking/test/browser/cookies.sjs
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -1025,17 +1025,24 @@ void nsHTMLDocument::GetCookie(nsAString
 
   // If the document's sandboxed origin flag is set, access to read cookies
   // is prohibited.
   if (mSandboxFlags & SANDBOXED_ORIGIN) {
     rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return;
   }
 
-  if (nsContentUtils::StorageDisabledByAntiTracking(this, nullptr)) {
+  nsContentUtils::StorageAccess storageAccess =
+      nsContentUtils::StorageAllowedForDocument(this);
+  if (storageAccess == nsContentUtils::StorageAccess::eDeny) {
+    return;
+  }
+
+  if (storageAccess == nsContentUtils::StorageAccess::ePartitionedOrDeny &&
+      !StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
     return;
   }
 
   // If the document is a cookie-averse Document... return the empty string.
   if (IsCookieAverse()) {
     return;
   }
 
@@ -1078,17 +1085,24 @@ void nsHTMLDocument::SetCookie(const nsA
 
   // If the document's sandboxed origin flag is set, access to write cookies
   // is prohibited.
   if (mSandboxFlags & SANDBOXED_ORIGIN) {
     rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return;
   }
 
-  if (nsContentUtils::StorageDisabledByAntiTracking(this, nullptr)) {
+  nsContentUtils::StorageAccess storageAccess =
+      nsContentUtils::StorageAllowedForDocument(this);
+  if (storageAccess == nsContentUtils::StorageAccess::eDeny) {
+    return;
+  }
+
+  if (storageAccess == nsContentUtils::StorageAccess::ePartitionedOrDeny &&
+      !StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
     return;
   }
 
   // If the document is a cookie-averse Document... do nothing.
   if (IsCookieAverse()) {
     return;
   }
 
--- a/netwerk/base/nsNetUtil.cpp
+++ b/netwerk/base/nsNetUtil.cpp
@@ -11,16 +11,17 @@
 
 #include "mozilla/AntiTrackingCommon.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/Encoding.h"
 #include "mozilla/LoadContext.h"
 #include "mozilla/LoadInfo.h"
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/Monitor.h"
+#include "mozilla/StoragePrincipalHelper.h"
 #include "mozilla/TaskQueue.h"
 #include "mozilla/Telemetry.h"
 #include "nsCategoryCache.h"
 #include "nsContentUtils.h"
 #include "nsFileStreams.h"
 #include "nsHashKeys.h"
 #include "nsHttp.h"
 #include "nsIAsyncStreamCopier.h"
@@ -1846,38 +1847,43 @@ nsresult NS_LoadPersistentPropertiesFrom
   NS_ENSURE_SUCCESS(rv, rv);
 
   properties.swap(*outResult);
   return NS_OK;
 }
 
 bool NS_UsePrivateBrowsing(nsIChannel *channel) {
   OriginAttributes attrs;
-  bool result = NS_GetOriginAttributes(channel, attrs);
+  bool result = NS_GetOriginAttributes(channel, attrs, false);
   NS_ENSURE_TRUE(result, result);
   return attrs.mPrivateBrowsingId > 0;
 }
 
 bool NS_GetOriginAttributes(nsIChannel *aChannel,
-                            mozilla::OriginAttributes &aAttributes) {
+                            mozilla::OriginAttributes &aAttributes,
+                            bool aUsingStoragePrincipal) {
   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
   loadInfo->GetOriginAttributes(&aAttributes);
 
   bool isPrivate = false;
   nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryInterface(aChannel);
   if (pbChannel) {
     nsresult rv = pbChannel->GetIsChannelPrivate(&isPrivate);
     NS_ENSURE_SUCCESS(rv, false);
   } else {
     // Some channels may not implement nsIPrivateBrowsingChannel
     nsCOMPtr<nsILoadContext> loadContext;
     NS_QueryNotificationCallbacks(aChannel, loadContext);
     isPrivate = loadContext && loadContext->UsePrivateBrowsing();
   }
   aAttributes.SyncAttributesWithPrivateBrowsing(isPrivate);
+
+  if (aUsingStoragePrincipal) {
+    StoragePrincipalHelper::PrepareOriginAttributes(aChannel, aAttributes);
+  }
   return true;
 }
 
 bool NS_HasBeenCrossOrigin(nsIChannel *aChannel, bool aReport) {
   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
   // TYPE_DOCUMENT loads have a null LoadingPrincipal and can not be cross
   // origin.
   if (!loadInfo->LoadingPrincipal()) {
--- a/netwerk/base/nsNetUtil.h
+++ b/netwerk/base/nsNetUtil.h
@@ -605,19 +605,22 @@ inline void NS_QueryNotificationCallback
 /**
  * Returns true if channel is using Private Browsing, or false if not.
  * Returns false if channel's callbacks don't implement nsILoadContext.
  */
 bool NS_UsePrivateBrowsing(nsIChannel *channel);
 
 /**
  * Extract the OriginAttributes from the channel's triggering principal.
+ * If aUsingStoragePrincipal is set to true, the originAttributes could have
+ * first-party isolation domain set to the top-level URI.
  */
 bool NS_GetOriginAttributes(nsIChannel *aChannel,
-                            mozilla::OriginAttributes &aAttributes);
+                            mozilla::OriginAttributes &aAttributes,
+                            bool aUsingStoragePrincipal = false);
 
 /**
  * Returns true if the channel has visited any cross-origin URLs on any
  * URLs that it was redirected through.
  */
 bool NS_HasBeenCrossOrigin(nsIChannel *aChannel, bool aReport = false);
 
 /**
--- a/netwerk/cookie/CookieServiceChild.cpp
+++ b/netwerk/cookie/CookieServiceChild.cpp
@@ -8,16 +8,17 @@
 #include "mozilla/AntiTrackingCommon.h"
 #include "mozilla/LoadInfo.h"
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/ipc/URIUtils.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/SystemGroup.h"
+#include "mozilla/StoragePrincipalHelper.h"
 #include "nsCookie.h"
 #include "nsCookieService.h"
 #include "nsContentUtils.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 #include "nsIChannel.h"
 #include "nsCookiePermission.h"
 #include "nsIEffectiveTLDService.h"
@@ -170,16 +171,17 @@ void CookieServiceChild::TrackCookieLoad
     // object handy.
     if (!firstPartyStorageAccessGranted) {
       AntiTrackingCommon::NotifyBlockingDecision(
           aChannel, AntiTrackingCommon::BlockingDecision::eBlock,
           rejectedReason);
     }
   }
   mozilla::OriginAttributes attrs = loadInfo->GetOriginAttributes();
+  StoragePrincipalHelper::PrepareOriginAttributes(aChannel, attrs);
   URIParams uriParams;
   SerializeURI(uri, uriParams);
   bool isSafeTopLevelNav = NS_IsSafeTopLevelNav(aChannel);
   bool isSameSiteForeign = NS_IsSameSiteForeign(aChannel, uri);
   SendPrepareCookieList(uriParams, isForeign, isTrackingResource,
                         firstPartyStorageAccessGranted, isSafeTopLevelNav,
                         isSameSiteForeign, attrs);
 }
@@ -289,16 +291,17 @@ void CookieServiceChild::GetCookieString
   bool requireHostMatch;
   nsAutoCString baseDomain;
 
   nsCOMPtr<nsILoadInfo> loadInfo;
   mozilla::OriginAttributes attrs;
   if (aChannel) {
     loadInfo = aChannel->LoadInfo();
     attrs = loadInfo->GetOriginAttributes();
+    StoragePrincipalHelper::PrepareOriginAttributes(aChannel, attrs);
   }
 
   nsCookieService::GetBaseDomain(TLDService, aHostURI, baseDomain,
                                  requireHostMatch);
   nsCookieKey key(baseDomain, attrs);
   CookiesList *cookiesList = nullptr;
   mCookiesMap.Get(key, &cookiesList);
 
@@ -557,28 +560,29 @@ nsresult CookieServiceChild::SetCookieSt
   mozilla::OriginAttributes attrs;
   if (aChannel) {
     nsCOMPtr<nsIURI> channelURI;
     aChannel->GetURI(getter_AddRefs(channelURI));
     SerializeURI(channelURI, channelURIParams);
 
     MOZ_ASSERT(loadInfo);
     attrs = loadInfo->GetOriginAttributes();
+    StoragePrincipalHelper::PrepareOriginAttributes(aChannel, attrs);
   } else {
     SerializeURI(nullptr, channelURIParams);
   }
 
   Maybe<LoadInfoArgs> optionalLoadInfoArgs;
   LoadInfoToLoadInfoArgs(loadInfo, &optionalLoadInfoArgs);
 
   // Asynchronously call the parent.
   if (mIPCOpen) {
     SendSetCookieString(hostURIParams, channelURIParams, optionalLoadInfoArgs,
                         isForeign, isTrackingResource,
-                        firstPartyStorageAccessGranted, cookieString,
+                        firstPartyStorageAccessGranted, attrs, cookieString,
                         stringServerTime, aFromHttp);
   }
 
   bool requireHostMatch;
   nsCString baseDomain;
   nsCookieService::GetBaseDomain(mTLDService, aHostURI, baseDomain,
                                  requireHostMatch);
 
--- a/netwerk/cookie/CookieServiceParent.cpp
+++ b/netwerk/cookie/CookieServiceParent.cpp
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/net/CookieServiceParent.h"
 #include "mozilla/dom/PContentParent.h"
 #include "mozilla/net/NeckoParent.h"
 
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/ipc/URIUtils.h"
+#include "mozilla/StoragePrincipalHelper.h"
 #include "nsArrayUtils.h"
 #include "nsCookieService.h"
 #include "nsIChannel.h"
 #include "nsIEffectiveTLDService.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIPrivateBrowsingChannel.h"
 #include "nsNetCID.h"
 #include "nsPrintfCString.h"
@@ -121,16 +122,18 @@ void CookieServiceParent::TrackCookieLoa
   nsCOMPtr<nsIURI> uri;
   aChannel->GetURI(getter_AddRefs(uri));
 
   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
   mozilla::OriginAttributes attrs = loadInfo->GetOriginAttributes();
   bool isSafeTopLevelNav = NS_IsSafeTopLevelNav(aChannel);
   bool aIsSameSiteForeign = NS_IsSameSiteForeign(aChannel, uri);
 
+  StoragePrincipalHelper::PrepareOriginAttributes(aChannel, attrs);
+
   // Send matching cookies to Child.
   nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil;
   thirdPartyUtil = do_GetService(THIRDPARTYUTIL_CONTRACTID);
   bool isForeign = true;
   thirdPartyUtil->IsThirdPartyChannel(aChannel, uri, &isForeign);
 
   bool isTrackingResource = false;
   bool storageAccessGranted = false;
@@ -202,18 +205,19 @@ void CookieServiceParent::ActorDestroy(A
   // Nothing needed here. Called right before destructor since this is a
   // non-refcounted class.
 }
 
 mozilla::ipc::IPCResult CookieServiceParent::RecvSetCookieString(
     const URIParams &aHost, const Maybe<URIParams> &aChannelURI,
     const Maybe<LoadInfoArgs> &aLoadInfoArgs, const bool &aIsForeign,
     const bool &aIsTrackingResource,
-    const bool &aFirstPartyStorageAccessGranted, const nsCString &aCookieString,
-    const nsCString &aServerTime, const bool &aFromHttp) {
+    const bool &aFirstPartyStorageAccessGranted, const OriginAttributes &aAttrs,
+    const nsCString &aCookieString, const nsCString &aServerTime,
+    const bool &aFromHttp) {
   if (!mCookieService) return IPC_OK();
 
   // Deserialize URI. Having a host URI is mandatory and should always be
   // provided by the child; thus we consider failure fatal.
   nsCOMPtr<nsIURI> hostURI = DeserializeURI(aHost);
   if (!hostURI) return IPC_FAIL_NO_REASON(this);
 
   nsCOMPtr<nsIURI> channelURI = DeserializeURI(aChannelURI);
@@ -235,25 +239,20 @@ mozilla::ipc::IPCResult CookieServicePar
   if (NS_WARN_IF(NS_FAILED(rv))) {
     // No reason to kill the content process.
     return IPC_OK();
   }
 
   // NB: dummyChannel could be null if something failed in CreateDummyChannel.
   nsDependentCString cookieString(aCookieString, 0);
 
-  OriginAttributes attrs;
-  if (loadInfo) {
-    attrs = loadInfo->GetOriginAttributes();
-  }
-
   // We set this to true while processing this cookie update, to make sure
   // we don't send it back to the same content process.
   mProcessingCookie = true;
   mCookieService->SetCookieStringInternal(
       hostURI, aIsForeign, aIsTrackingResource, aFirstPartyStorageAccessGranted,
-      cookieString, aServerTime, aFromHttp, attrs, dummyChannel);
+      cookieString, aServerTime, aFromHttp, aAttrs, dummyChannel);
   mProcessingCookie = false;
   return IPC_OK();
 }
 
 }  // namespace net
 }  // namespace mozilla
--- a/netwerk/cookie/CookieServiceParent.h
+++ b/netwerk/cookie/CookieServiceParent.h
@@ -44,18 +44,18 @@ class CookieServiceParent : public PCook
  protected:
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
 
   mozilla::ipc::IPCResult RecvSetCookieString(
       const URIParams &aHost, const Maybe<URIParams> &aChannelURI,
       const Maybe<LoadInfoArgs> &aLoadInfoArgs, const bool &aIsForeign,
       const bool &aIsTrackingResource,
       const bool &aFirstPartyStorageAccessGranted,
-      const nsCString &aCookieString, const nsCString &aServerTime,
-      const bool &aFromHttp);
+      const OriginAttributes &aAttrs, const nsCString &aCookieString,
+      const nsCString &aServerTime, const bool &aFromHttp);
 
   mozilla::ipc::IPCResult RecvPrepareCookieList(
       const URIParams &aHost, const bool &aIsForeign,
       const bool &aIsTrackingResource,
       const bool &aFirstPartyStorageAccessGranted,
       const bool &aIsSafeTopLevelNav, const bool &aIsSameSiteForeign,
       const OriginAttributes &aAttrs);
 
--- a/netwerk/cookie/PCookieService.ipdl
+++ b/netwerk/cookie/PCookieService.ipdl
@@ -70,16 +70,17 @@ parent:
    * @see mozIThirdPartyUtil.isThirdPartyChannel
    */
   nested(inside_cpow) async SetCookieString(URIParams host,
                                             URIParams? channelURI,
                                             LoadInfoArgs? loadInfoArgs,
                                             bool isForeign,
                                             bool isTrackingResource,
                                             bool firstPartyStorageAccessGranted,
+                                            OriginAttributes aStoragePrincipalAttrs,
                                             nsCString cookieString,
                                             nsCString serverTime,
                                             bool aFromHttp);
 
   async PrepareCookieList(URIParams host,
                           bool isForeign,
                           bool isTrackingResource,
                           bool firstPartyStorageAccessGranted,
--- a/netwerk/cookie/nsCookieService.cpp
+++ b/netwerk/cookie/nsCookieService.cpp
@@ -1985,17 +1985,18 @@ nsresult nsCookieService::GetCookieStrin
     if (AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(
             httpChannel, aHostURI, nullptr)) {
       firstPartyStorageAccessGranted = true;
     }
   }
 
   OriginAttributes attrs;
   if (aChannel) {
-    NS_GetOriginAttributes(aChannel, attrs);
+    NS_GetOriginAttributes(aChannel, attrs,
+                           true /* considering storage principal */);
   }
 
   bool isSafeTopLevelNav = NS_IsSafeTopLevelNav(aChannel);
   bool isSameSiteForeign = NS_IsSameSiteForeign(aChannel, aHostURI);
   nsAutoCString result;
   GetCookieStringInternal(aHostURI, aChannel, isForeign, isTrackingResource,
                           firstPartyStorageAccessGranted, isSafeTopLevelNav,
                           isSameSiteForeign, aHttpBound, attrs, result);
@@ -2104,17 +2105,18 @@ nsresult nsCookieService::SetCookieStrin
     if (AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(
             httpChannel, aHostURI, nullptr)) {
       firstPartyStorageAccessGranted = true;
     }
   }
 
   OriginAttributes attrs;
   if (aChannel) {
-    NS_GetOriginAttributes(aChannel, attrs);
+    NS_GetOriginAttributes(aChannel, attrs,
+                           true /* considering storage principal */);
   }
 
   nsDependentCString cookieString(aCookieHeader);
   nsDependentCString serverTime(aServerTime ? aServerTime : "");
   SetCookieStringInternal(aHostURI, isForeign, isTrackingResource,
                           firstPartyStorageAccessGranted, cookieString,
                           serverTime, aFromHttp, attrs, aChannel);
   return NS_OK;
@@ -4035,16 +4037,22 @@ CookieStatus nsCookieService::CheckPrefs
   }
 
   // No cookies allowed if this request comes from a tracker, in a 3rd party
   // context, when anti-tracking protection is enabled and when we don't have
   // access to the first-party cookie jar.
   if (aIsForeign && aIsTrackingResource && !aFirstPartyStorageAccessGranted &&
       aCookieSettings->GetCookieBehavior() ==
           nsICookieService::BEHAVIOR_REJECT_TRACKER) {
+    if (StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
+      MOZ_ASSERT(!aOriginAttrs.mFirstPartyDomain.IsEmpty(),
+                 "We must have a StoragePrincipal here!");
+      return STATUS_ACCEPTED;
+    }
+
     COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI,
                       aCookieHeader, "cookies are disabled in trackers");
     *aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER;
     return STATUS_REJECTED;
   }
 
   // check default prefs.
   // Check aFirstPartyStorageAccessGranted when checking aCookieBehavior
--- a/toolkit/components/antitracking/StoragePrincipalHelper.cpp
+++ b/toolkit/components/antitracking/StoragePrincipalHelper.cpp
@@ -8,63 +8,93 @@
 
 #include "mozilla/ScopeExit.h"
 #include "mozilla/StaticPrefs.h"
 #include "nsContentUtils.h"
 #include "nsIHttpChannel.h"
 
 namespace mozilla {
 
+namespace {
+
+already_AddRefed<nsIURI> MaybeGetFirstPartyURI(nsIChannel* aChannel) {
+  MOZ_ASSERT(aChannel);
+
+  if (!StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
+    return nullptr;
+  }
+
+  // Let's use the storage principal only if we need to partition the cookie
+  // jar.
+  nsContentUtils::StorageAccess access =
+      nsContentUtils::StorageAllowedForChannel(aChannel);
+  if (access != nsContentUtils::StorageAccess::ePartitionedOrDeny) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
+  if (!httpChannel) {
+    return nullptr;
+  }
+
+  MOZ_ASSERT(httpChannel->IsThirdPartyTrackingResource());
+
+  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
+  nsCOMPtr<nsIPrincipal> toplevelPrincipal = loadInfo->GetTopLevelPrincipal();
+  if (!toplevelPrincipal) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIURI> principalURI;
+  nsresult rv = toplevelPrincipal->GetURI(getter_AddRefs(principalURI));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return nullptr;
+  }
+
+  return principalURI.forget();
+}
+
+}  // namespace
+
 // static
 nsresult StoragePrincipalHelper::Create(nsIChannel* aChannel,
                                         nsIPrincipal* aPrincipal,
                                         nsIPrincipal** aStoragePrincipal) {
   MOZ_ASSERT(aChannel);
   MOZ_ASSERT(aPrincipal);
   MOZ_ASSERT(aStoragePrincipal);
 
   auto scopeExit = MakeScopeExit([&] {
     nsCOMPtr<nsIPrincipal> storagePrincipal = aPrincipal;
     storagePrincipal.forget(aStoragePrincipal);
   });
 
-  if (!StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
-    return NS_OK;
-  }
-
-  // Let's use the storage principal only if we need to partition the cookie
-  // jar.
-  nsContentUtils::StorageAccess access =
-      nsContentUtils::StorageAllowedForChannel(aChannel);
-  if (access != nsContentUtils::StorageAccess::ePartitionedOrDeny) {
-    return NS_OK;
-  }
-
-  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
-  if (!httpChannel) {
+  nsCOMPtr<nsIURI> principalURI = MaybeGetFirstPartyURI(aChannel);
+  if (!principalURI) {
     return NS_OK;
   }
 
-  MOZ_ASSERT(httpChannel->IsThirdPartyTrackingResource());
-
-  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
-  nsCOMPtr<nsIPrincipal> toplevelPrincipal = loadInfo->GetTopLevelPrincipal();
-  if (!toplevelPrincipal) {
-    return NS_OK;
-  }
-
-  nsCOMPtr<nsIURI> principalURI;
-  nsresult rv = toplevelPrincipal->GetURI(getter_AddRefs(principalURI));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
   scopeExit.release();
 
   nsCOMPtr<nsIPrincipal> storagePrincipal =
       BasePrincipal::Cast(aPrincipal)
           ->CloneForcingFirstPartyDomain(principalURI);
 
   storagePrincipal.forget(aStoragePrincipal);
   return NS_OK;
 }
 
+// static
+nsresult StoragePrincipalHelper::PrepareOriginAttributes(
+    nsIChannel* aChannel, OriginAttributes& aOriginAttributes) {
+  MOZ_ASSERT(aChannel);
+
+  nsCOMPtr<nsIURI> principalURI = MaybeGetFirstPartyURI(aChannel);
+  if (!principalURI) {
+    return NS_OK;
+  }
+
+  aOriginAttributes.SetFirstPartyDomain(false, principalURI,
+                                        true /* aForced */);
+  return NS_OK;
+}
+
 }  // namespace mozilla
--- a/toolkit/components/antitracking/StoragePrincipalHelper.h
+++ b/toolkit/components/antitracking/StoragePrincipalHelper.h
@@ -7,17 +7,22 @@
 #ifndef mozilla_StoragePrincipalHelper_h
 #define mozilla_StoragePrincipalHelper_h
 
 class nsIChannel;
 class nsIPrincipal;
 
 namespace mozilla {
 
+class OriginAttributes;
+
 class StoragePrincipalHelper final {
  public:
   static nsresult Create(nsIChannel* aChannel, nsIPrincipal* aPrincipal,
                          nsIPrincipal** aStoragePrincipal);
+
+  static nsresult PrepareOriginAttributes(nsIChannel* aChannel,
+                                          OriginAttributes& aOriginAttributes);
 };
 
 }  // namespace mozilla
 
 #endif  // mozilla_StoragePrincipalHelper_h
--- a/toolkit/components/antitracking/test/browser/browser.ini
+++ b/toolkit/components/antitracking/test/browser/browser.ini
@@ -88,8 +88,10 @@ support-files = localStorage.html
 [browser_partitionedLocalStorage.js]
 [browser_partitionedLocalStorage_events.js]
 support-files = localStorageEvents.html
 [browser_workerPropagation.js]
 support-files = workerIframe.html
 [browser_cookieBetweenTabs.js]
 [browser_partitionedMessaging.js]
 [browser_partitionedIndexedDB.js]
+[browser_partitionedCookies.js]
+support-files = cookies.sjs
new file mode 100644
--- /dev/null
+++ b/toolkit/components/antitracking/test/browser/browser_partitionedCookies.js
@@ -0,0 +1,49 @@
+/* import-globals-from storageprincipal_head.js */
+
+StoragePrincipalHelper.runTest("HTTP Cookies",
+  async (win3rdParty, win1stParty, allowed) => {
+    await win3rdParty.fetch("cookies.sjs?3rd").then(r => r.text());
+    await win3rdParty.fetch("cookies.sjs").then(r => r.text()).then(text => {
+      is(text, "cookie:foopy=3rd", "3rd party cookie set");
+    });
+
+    await win1stParty.fetch("cookies.sjs?first").then(r => r.text());
+    await win1stParty.fetch("cookies.sjs").then(r => r.text()).then(text => {
+      is(text, "cookie:foopy=first", "First party cookie set");
+    });
+
+    await win3rdParty.fetch("cookies.sjs").then(r => r.text()).then(text => {
+      if (allowed) {
+        is(text, "cookie:foopy=first", "3rd party has the first party cookie set");
+      } else {
+        is(text, "cookie:foopy=3rd", "3rd party has not the first party cookie set");
+      }
+    });
+  },
+
+  async _ => {
+    await new Promise(resolve => {
+      Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => resolve());
+    });
+  });
+
+StoragePrincipalHelper.runTest("DOM Cookies",
+  async (win3rdParty, win1stParty, allowed) => {
+    win3rdParty.document.cookie = "foo=3rd";
+    is(win3rdParty.document.cookie, "foo=3rd", "3rd party cookie set");
+
+    win1stParty.document.cookie = "foo=first";
+    is(win1stParty.document.cookie, "foo=first", "First party cookie set");
+
+    if (allowed) {
+      is(win3rdParty.document.cookie, "foo=first", "3rd party has the first party cookie set");
+    } else {
+      is(win3rdParty.document.cookie, "foo=3rd", "3rd party has not the first party cookie set");
+    }
+  },
+
+  async _ => {
+    await new Promise(resolve => {
+      Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => resolve());
+    });
+  });
new file mode 100644
--- /dev/null
+++ b/toolkit/components/antitracking/test/browser/cookies.sjs
@@ -0,0 +1,12 @@
+function handleRequest(aRequest, aResponse) {
+  aResponse.setStatusLine(aRequest.httpVersion, 200);
+  let cookie = "";
+  if (aRequest.hasHeader("Cookie")) {
+    cookie = aRequest.getHeader("Cookie");
+  }
+  aResponse.write("cookie:" + cookie);
+
+  if (aRequest.queryString) {
+    aResponse.setHeader("Set-Cookie", "foopy=" + aRequest.queryString);
+  }
+}