forked from mirrors/gecko-dev
		
	 7cdbab4b1e
			
		
	
	
		7cdbab4b1e
		
	
	
	
	
		
			
			The logic for choosing the principal here was originally written before loadInfo had a separate principalToInherit field, and we needed to specify it via the triggeringPrincipal instead. At that point, we had to choose a component principal with permission to load the URI at the start of the request. However, now that we have a separate field for the principal to inherit, it's only needed after access checks have passed and we know that we have a URI which inherits a principal. In that case, the current logic causes us to always inherit the first principal in the whitelist (which is the page principal) for URIs (such as data: URIs) that always inherit, where we really want to inherit the last (which is the extension principal). MozReview-Commit-ID: EPoUNuOCwrH --HG-- extra : rebase_source : 535083e3dd4598ac4e8ea187d27d61ac2ac48476
		
			
				
	
	
		
			285 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			285 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #ifndef mozilla_BasePrincipal_h
 | |
| #define mozilla_BasePrincipal_h
 | |
| 
 | |
| #include "nsJSPrincipals.h"
 | |
| 
 | |
| #include "mozilla/Attributes.h"
 | |
| #include "mozilla/OriginAttributes.h"
 | |
| 
 | |
| class nsAtom;
 | |
| class nsIContentSecurityPolicy;
 | |
| class nsIObjectOutputStream;
 | |
| class nsIObjectInputStream;
 | |
| class nsIURI;
 | |
| 
 | |
| class ExpandedPrincipal;
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace extensions {
 | |
|   class WebExtensionPolicy;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Base class from which all nsIPrincipal implementations inherit. Use this for
 | |
|  * default implementations and other commonalities between principal
 | |
|  * implementations.
 | |
|  *
 | |
|  * We should merge nsJSPrincipals into this class at some point.
 | |
|  */
 | |
| class BasePrincipal : public nsJSPrincipals
 | |
| {
 | |
| public:
 | |
|   enum PrincipalKind {
 | |
|     eNullPrincipal,
 | |
|     eCodebasePrincipal,
 | |
|     eExpandedPrincipal,
 | |
|     eSystemPrincipal
 | |
|   };
 | |
| 
 | |
|   explicit BasePrincipal(PrincipalKind aKind);
 | |
| 
 | |
|   template<typename T>
 | |
|   bool Is() const
 | |
|   {
 | |
|     return mKind == T::Kind();
 | |
|   }
 | |
| 
 | |
|   template<typename T>
 | |
|   T* As()
 | |
|   {
 | |
|     MOZ_ASSERT(Is<T>());
 | |
|     return static_cast<T*>(this);
 | |
|   }
 | |
| 
 | |
|   enum DocumentDomainConsideration { DontConsiderDocumentDomain, ConsiderDocumentDomain};
 | |
|   bool Subsumes(nsIPrincipal* aOther, DocumentDomainConsideration aConsideration);
 | |
| 
 | |
|   NS_IMETHOD GetOrigin(nsACString& aOrigin) final;
 | |
|   NS_IMETHOD GetOriginNoSuffix(nsACString& aOrigin) final;
 | |
|   NS_IMETHOD Equals(nsIPrincipal* other, bool* _retval) final;
 | |
|   NS_IMETHOD EqualsConsideringDomain(nsIPrincipal* other, bool* _retval) final;
 | |
|   NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval) final;
 | |
|   NS_IMETHOD SubsumesConsideringDomain(nsIPrincipal* other, bool* _retval) final;
 | |
|   NS_IMETHOD SubsumesConsideringDomainIgnoringFPD(nsIPrincipal* other, bool* _retval) final;
 | |
|   NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report, bool allowIfInheritsPrincipal) final;
 | |
|   NS_IMETHOD GetAddonPolicy(nsISupports** aResult) final;
 | |
|   NS_IMETHOD GetCsp(nsIContentSecurityPolicy** aCsp) override;
 | |
|   NS_IMETHOD SetCsp(nsIContentSecurityPolicy* aCsp) override;
 | |
|   NS_IMETHOD EnsureCSP(nsIDOMDocument* aDocument, nsIContentSecurityPolicy** aCSP) override;
 | |
|   NS_IMETHOD GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP) override;
 | |
|   NS_IMETHOD EnsurePreloadCSP(nsIDOMDocument* aDocument, nsIContentSecurityPolicy** aCSP) override;
 | |
|   NS_IMETHOD GetCspJSON(nsAString& outCSPinJSON) override;
 | |
|   NS_IMETHOD GetIsNullPrincipal(bool* aResult) override;
 | |
|   NS_IMETHOD GetIsCodebasePrincipal(bool* aResult) override;
 | |
|   NS_IMETHOD GetIsExpandedPrincipal(bool* aResult) override;
 | |
|   NS_IMETHOD GetIsSystemPrincipal(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;
 | |
| 
 | |
|   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>
 | |
|   CreateCodebasePrincipal(const nsACString& aOrigin);
 | |
| 
 | |
|   // These following method may not create a codebase principal in case it's
 | |
|   // not possible to generate a correct origin from the passed URI. If this
 | |
|   // happens, a NullPrincipal is returned.
 | |
| 
 | |
|   static already_AddRefed<BasePrincipal>
 | |
|   CreateCodebasePrincipal(nsIURI* aURI, const OriginAttributes& aAttrs);
 | |
| 
 | |
|   const OriginAttributes& OriginAttributesRef() final { return mOriginAttributes; }
 | |
|   uint32_t AppId() const { return mOriginAttributes.mAppId; }
 | |
|   extensions::WebExtensionPolicy* AddonPolicy();
 | |
|   uint32_t UserContextId() const { return mOriginAttributes.mUserContextId; }
 | |
|   uint32_t PrivateBrowsingId() const { return mOriginAttributes.mPrivateBrowsingId; }
 | |
|   bool IsInIsolatedMozBrowserElement() const { return mOriginAttributes.mInIsolatedMozBrowser; }
 | |
| 
 | |
|   PrincipalKind Kind() const { return mKind; }
 | |
| 
 | |
|   already_AddRefed<BasePrincipal> CloneStrippingUserContextIdAndFirstPartyDomain();
 | |
| 
 | |
|   // Helper to check whether this principal is associated with an addon that
 | |
|   // allows unprivileged code to load aURI.  aExplicit == true will prevent
 | |
|   // use of all_urls permission, requiring the domain in its permissions.
 | |
|   bool AddonAllowsLoad(nsIURI* aURI, bool aExplicit = false);
 | |
| 
 | |
|   // Call these to avoid the cost of virtual dispatch.
 | |
|   inline bool FastEquals(nsIPrincipal* aOther);
 | |
|   inline bool FastEqualsConsideringDomain(nsIPrincipal* aOther);
 | |
|   inline bool FastSubsumes(nsIPrincipal* aOther);
 | |
|   inline bool FastSubsumesConsideringDomain(nsIPrincipal* aOther);
 | |
|   inline bool FastSubsumesConsideringDomainIgnoringFPD(nsIPrincipal* aOther);
 | |
| 
 | |
|   // Returns the principal to inherit when a caller with this principal loads
 | |
|   // the given URI.
 | |
|   //
 | |
|   // For most principal types, this returns the principal itself. For expanded
 | |
|   // principals, it returns the first sub-principal which subsumes the given URI
 | |
|   // (or, if no URI is given, the last whitelist principal).
 | |
|   nsIPrincipal* PrincipalToInherit(nsIURI* aRequestedURI = nullptr);
 | |
| 
 | |
|   /**
 | |
|    * Returns true if this principal's CSP should override a document's CSP for
 | |
|    * loads that it triggers. Currently true only for expanded principals which
 | |
|    * subsume the document principal, and add-on codebase principals regardless
 | |
|    * of whether they subsume the document principal.
 | |
|    */
 | |
|   bool OverridesCSP(nsIPrincipal* aDocumentPrincipal)
 | |
|   {
 | |
|     // Expanded principals override CSP if and only if they subsume the document
 | |
|     // principal.
 | |
|     if (mKind == eExpandedPrincipal) {
 | |
|       return FastSubsumes(aDocumentPrincipal);
 | |
|     }
 | |
|     // Extension principals always override the CSP non-extension principals.
 | |
|     // This is primarily for the sake of their stylesheets, which are usually
 | |
|     // loaded from channels and cannot have expanded principals.
 | |
|     return (AddonPolicy() &&
 | |
|             !BasePrincipal::Cast(aDocumentPrincipal)->AddonPolicy());
 | |
|   }
 | |
| 
 | |
| protected:
 | |
|   virtual ~BasePrincipal();
 | |
| 
 | |
|   // Note that this does not check OriginAttributes. Callers that depend on
 | |
|   // those must call Subsumes instead.
 | |
|   virtual bool SubsumesInternal(nsIPrincipal* aOther, DocumentDomainConsideration aConsider) = 0;
 | |
| 
 | |
|   // Internal, side-effect-free check to determine whether the concrete
 | |
|   // principal would allow the load ignoring any common behavior implemented in
 | |
|   // BasePrincipal::CheckMayLoad.
 | |
|   virtual bool MayLoadInternal(nsIURI* aURI) = 0;
 | |
|   friend class ::ExpandedPrincipal;
 | |
| 
 | |
|   void
 | |
|   SetHasExplicitDomain()
 | |
|   {
 | |
|     mHasExplicitDomain = true;
 | |
|   }
 | |
| 
 | |
|   // This function should be called as the last step of the initialization of the
 | |
|   // principal objects.  It's typically called as the last step from the Init()
 | |
|   // method of the child classes.
 | |
|   void FinishInit(const nsACString& aOriginNoSuffix,
 | |
|                   const OriginAttributes& aOriginAttributes);
 | |
| 
 | |
|   nsCOMPtr<nsIContentSecurityPolicy> mCSP;
 | |
|   nsCOMPtr<nsIContentSecurityPolicy> mPreloadCSP;
 | |
| 
 | |
| private:
 | |
|   static already_AddRefed<BasePrincipal>
 | |
|   CreateCodebasePrincipal(nsIURI* aURI, const OriginAttributes& aAttrs,
 | |
|                           const nsACString& aOriginNoSuffix);
 | |
| 
 | |
|   RefPtr<nsAtom> mOriginNoSuffix;
 | |
|   RefPtr<nsAtom> mOriginSuffix;
 | |
| 
 | |
|   OriginAttributes mOriginAttributes;
 | |
|   PrincipalKind mKind;
 | |
|   bool mHasExplicitDomain;
 | |
|   bool mInitialized;
 | |
| };
 | |
| 
 | |
| inline bool
 | |
| BasePrincipal::FastEquals(nsIPrincipal* aOther)
 | |
| {
 | |
|   auto other = Cast(aOther);
 | |
|   if (Kind() != other->Kind()) {
 | |
|     // Principals of different kinds can't be equal.
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   // Two principals are considered to be equal if their origins are the same.
 | |
|   // If the two principals are codebase principals, their origin attributes
 | |
|   // (aka the origin suffix) must also match.
 | |
|   // If the two principals are null principals, they're only equal if they're
 | |
|   // the same object.
 | |
|   if (Kind() == eNullPrincipal || Kind() == eSystemPrincipal) {
 | |
|     return this == other;
 | |
|   }
 | |
| 
 | |
|   if (Kind() == eCodebasePrincipal) {
 | |
|     return mOriginNoSuffix == other->mOriginNoSuffix &&
 | |
|            mOriginSuffix == other->mOriginSuffix;
 | |
|   }
 | |
| 
 | |
|   MOZ_ASSERT(Kind() == eExpandedPrincipal);
 | |
|   return mOriginNoSuffix == other->mOriginNoSuffix;
 | |
| }
 | |
| 
 | |
| inline bool
 | |
| BasePrincipal::FastEqualsConsideringDomain(nsIPrincipal* aOther)
 | |
| {
 | |
|   // If neither of the principals have document.domain set, we use the fast path
 | |
|   // in Equals().  Otherwise, we fall back to the slow path below.
 | |
|   auto other = Cast(aOther);
 | |
|   if (!mHasExplicitDomain && !other->mHasExplicitDomain) {
 | |
|     return FastEquals(aOther);
 | |
|   }
 | |
| 
 | |
|   return Subsumes(aOther, ConsiderDocumentDomain) &&
 | |
|          other->Subsumes(this, ConsiderDocumentDomain);
 | |
| }
 | |
| 
 | |
| inline bool
 | |
| BasePrincipal::FastSubsumes(nsIPrincipal* aOther)
 | |
| {
 | |
|   // If two principals are equal, then they both subsume each other.
 | |
|   // We deal with two special cases first:
 | |
|   // Null principals only subsume each other if they are equal, and are only
 | |
|   // equal if they're the same object.
 | |
|   auto other = Cast(aOther);
 | |
|   if (Kind() == eNullPrincipal && other->Kind() == eNullPrincipal) {
 | |
|     return this == other;
 | |
|   }
 | |
|   if (FastEquals(aOther)) {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   // Otherwise, fall back to the slow path.
 | |
|   return Subsumes(aOther, DontConsiderDocumentDomain);
 | |
| }
 | |
| 
 | |
| inline bool
 | |
| BasePrincipal::FastSubsumesConsideringDomain(nsIPrincipal* aOther)
 | |
| {
 | |
|   // If neither of the principals have document.domain set, we hand off to
 | |
|   // FastSubsumes() which has fast paths for some special cases. Otherwise, we fall
 | |
|   // back to the slow path below.
 | |
|   if (!mHasExplicitDomain && !Cast(aOther)->mHasExplicitDomain) {
 | |
|     return FastSubsumes(aOther);
 | |
|   }
 | |
| 
 | |
|   return Subsumes(aOther, ConsiderDocumentDomain);
 | |
| }
 | |
| 
 | |
| inline bool
 | |
| BasePrincipal::FastSubsumesConsideringDomainIgnoringFPD(nsIPrincipal* aOther)
 | |
| {
 | |
|   if (Kind() == eCodebasePrincipal &&
 | |
|       !dom::ChromeUtils::IsOriginAttributesEqualIgnoringFPD(
 | |
|             mOriginAttributes, Cast(aOther)->mOriginAttributes)) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|  return SubsumesInternal(aOther, ConsiderDocumentDomain);
 | |
| }
 | |
| 
 | |
| } // namespace mozilla
 | |
| 
 | |
| #endif /* mozilla_BasePrincipal_h */
 |