Bug 1313627 - Get the firstPartyDomain from the nodePrincipal of the document in nsDocShell::CanAccessItem() if the first party isolation is on. r=smaug
authorTim Huang <tihuang@mozilla.com>
Thu, 10 Nov 2016 14:20:38 +0800
changeset 321896 fe91fde5ba7a7ad83b307b5f5a247d861aa76947
parent 321895 bf2c61e0283e5a55988b6ee2524c809d97a98e59
child 321897 10205a882c3c11cb74065e86d6727a0920276b35
push id83714
push userhchang@mozilla.com
push dateThu, 10 Nov 2016 06:20:07 +0000
treeherdermozilla-inbound@fe91fde5ba7a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1313627
milestone52.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 1313627 - Get the firstPartyDomain from the nodePrincipal of the document in nsDocShell::CanAccessItem() if the first party isolation is on. r=smaug
caps/BasePrincipal.cpp
caps/BasePrincipal.h
docshell/base/nsDocShell.cpp
--- a/caps/BasePrincipal.cpp
+++ b/caps/BasePrincipal.cpp
@@ -319,16 +319,17 @@ OriginAttributes::SetFromGenericAttribut
   mAppId = aAttrs.mAppId;
   mInIsolatedMozBrowser = aAttrs.mInIsolatedMozBrowser;
   mAddonId = aAttrs.mAddonId;
   mUserContextId = aAttrs.mUserContextId;
   mPrivateBrowsingId = aAttrs.mPrivateBrowsingId;
   mFirstPartyDomain = aAttrs.mFirstPartyDomain;
 }
 
+/* static */
 bool
 OriginAttributes::IsFirstPartyEnabled()
 {
   // Cache the privacy.firstparty.isolate pref.
   static bool sFirstPartyIsolation = false;
   static bool sCachedFirstPartyPref = false;
   if (!sCachedFirstPartyPref) {
     sCachedFirstPartyPref = true;
--- a/caps/BasePrincipal.h
+++ b/caps/BasePrincipal.h
@@ -56,23 +56,23 @@ public:
                           nsACString& aOriginNoSuffix);
 
   // Helper function to match mIsPrivateBrowsing to existing private browsing
   // flags. Once all other flags are removed, this can be removed too.
   void SyncAttributesWithPrivateBrowsing(bool aInPrivateBrowsing);
 
   void SetFromGenericAttributes(const GenericOriginAttributes& aAttrs);
 
+  // check if "privacy.firstparty.isolate" is enabled.
+  static bool IsFirstPartyEnabled();
+
 protected:
   OriginAttributes() {}
   explicit OriginAttributes(const OriginAttributesDictionary& aOther)
     : OriginAttributesDictionary(aOther) {}
-
-  // check if "privacy.firstparty.isolate" is enabled.
-  bool IsFirstPartyEnabled();
 };
 
 class PrincipalOriginAttributes;
 class DocShellOriginAttributes;
 class NeckoOriginAttributes;
 
 // Various classes in Gecko contain OriginAttributes members, and those
 // OriginAttributes get propagated to other classes according to certain rules.
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -3568,31 +3568,73 @@ nsDocShell::CanAccessItem(nsIDocShellTre
   }
 
   if (targetDS->GetIsInIsolatedMozBrowserElement() !=
         accessingDS->GetIsInIsolatedMozBrowserElement() ||
       targetDS->GetAppId() != accessingDS->GetAppId()) {
     return false;
   }
 
-  if (static_cast<nsDocShell*>(targetDS.get())->GetOriginAttributes() !=
-      static_cast<nsDocShell*>(accessingDS.get())->GetOriginAttributes()) {
+  nsCOMPtr<nsIDocShellTreeItem> accessingRoot;
+  aAccessingItem->GetSameTypeRootTreeItem(getter_AddRefs(accessingRoot));
+  nsCOMPtr<nsIDocShell> accessingRootDS = do_QueryInterface(accessingRoot);
+
+  nsCOMPtr<nsIDocShellTreeItem> targetRoot;
+  aTargetItem->GetSameTypeRootTreeItem(getter_AddRefs(targetRoot));
+  nsCOMPtr<nsIDocShell> targetRootDS = do_QueryInterface(targetRoot);
+
+  DocShellOriginAttributes targetOA =
+    static_cast<nsDocShell*>(targetDS.get())->GetOriginAttributes();
+  DocShellOriginAttributes accessingOA =
+    static_cast<nsDocShell*>(accessingDS.get())->GetOriginAttributes();
+
+  // When the first party isolation is on, the top-level docShell may not have
+  // the firstPartyDomain in its originAttributes, but its document will have
+  // it. So we get the firstPartyDomain from the nodePrincipal of the document
+  // before we compare the originAttributes.
+  if (OriginAttributes::IsFirstPartyEnabled()) {
+    if (accessingDS == accessingRootDS &&
+        aAccessingItem->ItemType() == nsIDocShellTreeItem::typeContent &&
+        !accessingDS->GetIsMozBrowserOrApp()) {
+
+      nsCOMPtr<nsIDocument> accessingDoc = aAccessingItem->GetDocument();
+
+      if (accessingDoc) {
+        nsCOMPtr<nsIPrincipal> accessingPrincipal = accessingDoc->NodePrincipal();
+
+        accessingOA.mFirstPartyDomain =
+          BasePrincipal::Cast(accessingPrincipal)->OriginAttributesRef().mFirstPartyDomain;
+      }
+    }
+
+    if (targetDS == targetRootDS &&
+        aTargetItem->ItemType() == nsIDocShellTreeItem::typeContent &&
+        !targetDS->GetIsMozBrowserOrApp()) {
+
+      nsCOMPtr<nsIDocument> targetDoc = aAccessingItem->GetDocument();
+
+      if (targetDoc) {
+        nsCOMPtr<nsIPrincipal> targetPrincipal = targetDoc->NodePrincipal();
+
+        targetOA.mFirstPartyDomain =
+          BasePrincipal::Cast(targetPrincipal)->OriginAttributesRef().mFirstPartyDomain;
+      }
+    }
+  }
+
+  if (targetOA != accessingOA) {
     return false;
   }
 
   // A private document can't access a non-private one, and vice versa.
   if (static_cast<nsDocShell*>(targetDS.get())->UsePrivateBrowsing() !=
       static_cast<nsDocShell*>(accessingDS.get())->UsePrivateBrowsing()) {
     return false;
   }
 
-
-  nsCOMPtr<nsIDocShellTreeItem> accessingRoot;
-  aAccessingItem->GetSameTypeRootTreeItem(getter_AddRefs(accessingRoot));
-
   if (aTargetItem == accessingRoot) {
     // A frame can navigate its root.
     return true;
   }
 
   // Check if aAccessingItem can navigate one of aTargetItem's ancestors.
   nsCOMPtr<nsIDocShellTreeItem> target = aTargetItem;
   do {
@@ -3600,19 +3642,16 @@ nsDocShell::CanAccessItem(nsIDocShellTre
       return true;
     }
 
     nsCOMPtr<nsIDocShellTreeItem> parent;
     target->GetSameTypeParent(getter_AddRefs(parent));
     parent.swap(target);
   } while (target);
 
-  nsCOMPtr<nsIDocShellTreeItem> targetRoot;
-  aTargetItem->GetSameTypeRootTreeItem(getter_AddRefs(targetRoot));
-
   if (aTargetItem != targetRoot) {
     // target is a subframe, not in accessor's frame hierarchy, and all its
     // ancestors have origins different from that of the accessor. Don't
     // allow access.
     return false;
   }
 
   if (!aConsiderOpener) {