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 321992 fe91fde5ba7a7ad83b307b5f5a247d861aa76947
parent 321991 bf2c61e0283e5a55988b6ee2524c809d97a98e59
child 321993 10205a882c3c11cb74065e86d6727a0920276b35
push id21
push usermaklebus@msu.edu
push dateThu, 01 Dec 2016 06:22:08 +0000
reviewerssmaug
bugs1313627
milestone52.0a1
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) {