Bug 1485177 - Add |siteOrigin| information to nsIPrincipal r=Ehsan
authorNika Layzell <nika@thelayzells.com>
Wed, 05 Sep 2018 03:22:16 +0000
changeset 434723 434d6bf22d1dd69f1f70dca9bc59c357593d8c1a
parent 434722 d7b738242b7ba029c546ee92d9c11d41f896fd31
child 434724 0f6244fb0d66654c0d5469c906e9c9343e18c6bf
push id34576
push userebalazs@mozilla.com
push dateWed, 05 Sep 2018 09:43:04 +0000
treeherdermozilla-central@46e6b719f5bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersEhsan
bugs1485177
milestone64.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 1485177 - Add |siteOrigin| information to nsIPrincipal r=Ehsan Differential Revision: https://phabricator.services.mozilla.com/D4140
caps/BasePrincipal.cpp
caps/BasePrincipal.h
caps/ContentPrincipal.cpp
caps/ContentPrincipal.h
caps/nsIPrincipal.idl
--- a/caps/BasePrincipal.cpp
+++ b/caps/BasePrincipal.cpp
@@ -54,16 +54,23 @@ BasePrincipal::GetOrigin(nsACString& aOr
 NS_IMETHODIMP
 BasePrincipal::GetOriginNoSuffix(nsACString& aOrigin)
 {
   MOZ_ASSERT(mInitialized);
   mOriginNoSuffix->ToUTF8String(aOrigin);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+BasePrincipal::GetSiteOrigin(nsACString& aSiteOrigin)
+{
+  MOZ_ASSERT(mInitialized);
+  return GetOrigin(aSiteOrigin);
+}
+
 bool
 BasePrincipal::Subsumes(nsIPrincipal* aOther, DocumentDomainConsideration aConsideration)
 {
   MOZ_ASSERT(aOther);
   MOZ_ASSERT_IF(Kind() == eCodebasePrincipal, mOriginSuffix);
 
   // Expanded principals handle origin attributes for each of their
   // sub-principals individually, null principals do only simple checks for
--- a/caps/BasePrincipal.h
+++ b/caps/BasePrincipal.h
@@ -81,16 +81,17 @@ public:
   NS_IMETHOD GetIsSystemPrincipal(bool* aResult) override;
   NS_IMETHOD GetIsAddonOrExpandedAddonPrincipal(bool* aResult) override;
   NS_IMETHOD GetOriginAttributes(JSContext* aCx, JS::MutableHandle<JS::Value> aVal) final;
   NS_IMETHOD GetOriginSuffix(nsACString& aOriginSuffix) final;
   NS_IMETHOD GetAppId(uint32_t* aAppId) final;
   NS_IMETHOD GetIsInIsolatedMozBrowserElement(bool* aIsInIsolatedMozBrowserElement) final;
   NS_IMETHOD GetUserContextId(uint32_t* aUserContextId) final;
   NS_IMETHOD GetPrivateBrowsingId(uint32_t* aPrivateBrowsingId) final;
+  NS_IMETHOD GetSiteOrigin(nsACString& aOrigin) override;
 
   virtual bool AddonHasPermission(const nsAtom* aPerm);
 
   virtual bool IsCodebasePrincipal() const { return false; };
 
   static BasePrincipal* Cast(nsIPrincipal* aPrin) { return static_cast<BasePrincipal*>(aPrin); }
 
   static already_AddRefed<BasePrincipal>
--- a/caps/ContentPrincipal.cpp
+++ b/caps/ContentPrincipal.cpp
@@ -12,16 +12,17 @@
 #include "nsScriptSecurityManager.h"
 #include "nsString.h"
 #include "nsReadableUtils.h"
 #include "pratom.h"
 #include "nsIURI.h"
 #include "nsIURL.h"
 #include "nsIStandardURL.h"
 #include "nsIURIWithSpecialOrigin.h"
+#include "nsIURIMutator.h"
 #include "nsJSPrincipals.h"
 #include "nsIEffectiveTLDService.h"
 #include "nsIClassInfoImpl.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 #include "nsIProtocolHandler.h"
 #include "nsError.h"
 #include "nsIContentSecurityPolicy.h"
@@ -242,17 +243,28 @@ ContentPrincipal::SubsumesInternal(nsIPr
     // Get .domain on each principal.
     nsCOMPtr<nsIURI> thisDomain, otherDomain;
     GetDomain(getter_AddRefs(thisDomain));
     aOther->GetDomain(getter_AddRefs(otherDomain));
 
     // If either has .domain set, we have equality i.f.f. the domains match.
     // Otherwise, we fall through to the non-document-domain-considering case.
     if (thisDomain || otherDomain) {
-      return nsScriptSecurityManager::SecurityCompareURIs(thisDomain, otherDomain);
+      bool isMatch =
+        nsScriptSecurityManager::SecurityCompareURIs(thisDomain, otherDomain);
+#ifdef DEBUG
+      if (isMatch) {
+        nsAutoCString thisSiteOrigin, otherSiteOrigin;
+        MOZ_ALWAYS_SUCCEEDS(GetSiteOrigin(thisSiteOrigin));
+        MOZ_ALWAYS_SUCCEEDS(aOther->GetSiteOrigin(otherSiteOrigin));
+        MOZ_ASSERT(thisSiteOrigin == otherSiteOrigin,
+          "SubsumesConsideringDomain passed with mismatched siteOrigin!");
+      }
+#endif
+      return isMatch;
     }
   }
 
   nsCOMPtr<nsIURI> otherURI;
   rv = aOther->GetURI(getter_AddRefs(otherURI));
   NS_ENSURE_SUCCESS(rv, false);
 
   // Compare codebases.
@@ -386,16 +398,63 @@ ContentPrincipal::GetBaseDomain(nsACStri
     do_GetService(THIRDPARTYUTIL_CONTRACTID);
   if (thirdPartyUtil) {
     return thirdPartyUtil->GetBaseDomain(mCodebase, aBaseDomain);
   }
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+ContentPrincipal::GetSiteOrigin(nsACString& aSiteOrigin)
+{
+  // Get the eTLDService & determine our base domain. If we don't have a valid
+  // BaseDomain, we can fall-back to GetOrigin.
+  nsCOMPtr<nsIEffectiveTLDService> tldService =
+    do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
+  if (NS_WARN_IF(!tldService)) {
+    return GetOrigin(aSiteOrigin);
+  }
+
+  nsAutoCString baseDomain;
+  nsresult rv = tldService->GetBaseDomain(mCodebase, 0, baseDomain);
+  if (NS_FAILED(rv)) {
+    return GetOrigin(aSiteOrigin);
+  }
+
+  // NOTE: Calling `SetHostPort` with a portless domain is insufficient to clear
+  // the port, so an extra `SetPort` call has to be made.
+  nsCOMPtr<nsIURI> siteUri;
+  rv = NS_MutateURI(mCodebase)
+    .SetUserPass(EmptyCString())
+    .SetPort(-1)
+    .SetHostPort(baseDomain)
+    .Finalize(siteUri);
+  MOZ_ASSERT(NS_SUCCEEDED(rv), "failed to create siteUri");
+  if (NS_FAILED(rv)) {
+    return GetOrigin(aSiteOrigin);
+  }
+
+  rv = GenerateOriginNoSuffixFromURI(siteUri, aSiteOrigin);
+  MOZ_ASSERT(NS_SUCCEEDED(rv), "failed to create siteOriginNoSuffix");
+  if (NS_FAILED(rv)) {
+    return GetOrigin(aSiteOrigin);
+  }
+
+  nsAutoCString suffix;
+  rv = GetOriginSuffix(suffix);
+  MOZ_ASSERT(NS_SUCCEEDED(rv), "failed to create suffix");
+  if (NS_FAILED(rv)) {
+    return GetOrigin(aSiteOrigin);
+  }
+
+  aSiteOrigin.Append(suffix);
+  return NS_OK;
+}
+
 WebExtensionPolicy*
 ContentPrincipal::AddonPolicy()
 {
   if (!mAddon.isSome()) {
     NS_ENSURE_TRUE(mCodebase, nullptr);
 
     bool isMozExt;
     if (NS_SUCCEEDED(mCodebase->SchemeIs("moz-extension", &isMozExt)) && isMozExt) {
--- a/caps/ContentPrincipal.h
+++ b/caps/ContentPrincipal.h
@@ -24,16 +24,17 @@ public:
   NS_DECL_NSISERIALIZABLE
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
   NS_IMETHOD GetHashValue(uint32_t* aHashValue) override;
   NS_IMETHOD GetURI(nsIURI** aURI) override;
   NS_IMETHOD GetDomain(nsIURI** aDomain) override;
   NS_IMETHOD SetDomain(nsIURI* aDomain) override;
   NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain) override;
   NS_IMETHOD GetAddonId(nsAString& aAddonId) override;
+  NS_IMETHOD GetSiteOrigin(nsACString& aSiteOrigin) override;
   bool IsCodebasePrincipal() const override { return true; }
 
   ContentPrincipal();
 
   static PrincipalKind Kind() { return eCodebasePrincipal; }
 
   // Init() must be called before the principal is in a usable state.
   nsresult Init(nsIURI* aCodebase,
--- a/caps/nsIPrincipal.idl
+++ b/caps/nsIPrincipal.idl
@@ -241,16 +241,30 @@ interface nsIPrincipal : nsISerializable
      *
      * The value of .originSuffix is automatically serialized into .origin, so any
      * consumers using that are automatically origin-attribute-aware. Consumers with
      * special requirements must inspect and compare .originSuffix manually.
      */
     readonly attribute AUTF8String originSuffix;
 
     /**
+     * A canonical representation of the site-origin for this principal.
+     * This string has the same format as |origin| (see above). Two principals
+     * with differing |siteOrigin| values will never compare equal, even when
+     * considering domain mutations.
+     *
+     * For most principals, |siteOrigin| matches |origin| precisely. Only
+     * principals which allow mutating |domain|, such as ContentPrincipal,
+     * override the default implementation in BasePrincipal.
+     *
+     * TODO(nika): Use this in DocGroup.
+     */
+    readonly attribute ACString siteOrigin;
+
+    /**
      * The base domain of the codebase URI to which this principal pertains
      * (generally the document URI), handling null principals and
      * non-hierarchical schemes correctly.
      */
     readonly attribute ACString baseDomain;
 
     /**
      * Gets the id of the app this principal is inside.  If this principal is