From cbfe84ef7403b2b5d76ac8da7fefd8d2131a4f79 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Fri, 15 May 2015 13:43:11 -0700 Subject: [PATCH] Bug 1165162 - Rework the nsIScriptSecurityManager principal-minting API to be originAttributes-centric. r=gabor,r=bholley,sr=sicking --- caps/BasePrincipal.cpp | 42 +++++++- caps/BasePrincipal.h | 57 +++++------ caps/nsIScriptSecurityManager.idl | 22 ++++- caps/nsNullPrincipal.h | 4 +- caps/nsPrincipal.h | 2 +- caps/nsScriptSecurityManager.cpp | 137 +++++++++++---------------- caps/nsScriptSecurityManager.h | 13 +-- dom/webidl/SystemDictionaries.webidl | 6 +- 8 files changed, 154 insertions(+), 129 deletions(-) diff --git a/caps/BasePrincipal.cpp b/caps/BasePrincipal.cpp index 6518546929f..0647d09d94b 100644 --- a/caps/BasePrincipal.cpp +++ b/caps/BasePrincipal.cpp @@ -8,6 +8,10 @@ #include "nsIObjectInputStream.h" #include "nsIObjectOutputStream.h" + +#include "nsPrincipal.h" +#include "nsNetUtil.h" +#include "nsNullPrincipal.h" #include "nsScriptSecurityManager.h" #include "mozilla/dom/ToJSValue.h" @@ -15,7 +19,7 @@ namespace mozilla { void -BasePrincipal::OriginAttributes::CreateSuffix(nsACString& aStr) +OriginAttributes::CreateSuffix(nsACString& aStr) { aStr.Truncate(); MOZ_RELEASE_ASSERT(mAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID); @@ -32,14 +36,14 @@ BasePrincipal::OriginAttributes::CreateSuffix(nsACString& aStr) } void -BasePrincipal::OriginAttributes::Serialize(nsIObjectOutputStream* aStream) const +OriginAttributes::Serialize(nsIObjectOutputStream* aStream) const { aStream->Write32(mAppId); aStream->WriteBoolean(mInBrowser); } nsresult -BasePrincipal::OriginAttributes::Deserialize(nsIObjectInputStream* aStream) +OriginAttributes::Deserialize(nsIObjectInputStream* aStream) { nsresult rv = aStream->Read32(&mAppId); NS_ENSURE_SUCCESS(rv, rv); @@ -179,4 +183,36 @@ BasePrincipal::GetUnknownAppId(bool* aUnknownAppId) return NS_OK; } +already_AddRefed +BasePrincipal::CreateCodebasePrincipal(nsIURI* aURI, OriginAttributes& aAttrs) +{ + // If the URI is supposed to inherit the security context of whoever loads it, + // we shouldn't make a codebase principal for it. + bool inheritsPrincipal; + nsresult rv = NS_URIChainHasFlags(aURI, nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT, + &inheritsPrincipal); + nsCOMPtr principal; + if (NS_FAILED(rv) || inheritsPrincipal) { + return nsNullPrincipal::Create(); + } + + // Check whether the URI knows what its principal is supposed to be. + nsCOMPtr uriPrinc = do_QueryInterface(aURI); + if (uriPrinc) { + nsCOMPtr principal; + uriPrinc->GetPrincipal(getter_AddRefs(principal)); + if (!principal) { + return nsNullPrincipal::Create(); + } + nsRefPtr concrete = Cast(principal); + return concrete.forget(); + } + + // Mint a codebase principal. + nsRefPtr codebase = new nsPrincipal(); + rv = codebase->Init(aURI, aAttrs); + NS_ENSURE_SUCCESS(rv, nullptr); + return codebase.forget(); +} + } // namespace mozilla diff --git a/caps/BasePrincipal.h b/caps/BasePrincipal.h index 4a9866b9f7d..a4329d930bc 100644 --- a/caps/BasePrincipal.h +++ b/caps/BasePrincipal.h @@ -18,6 +18,35 @@ class nsIObjectInputStream; namespace mozilla { +class OriginAttributes : public dom::OriginAttributesDictionary +{ +public: + OriginAttributes() {} + OriginAttributes(uint32_t aAppId, bool aInBrowser) + { + mAppId = aAppId; + mInBrowser = aInBrowser; + } + + bool operator==(const OriginAttributes& aOther) const + { + return mAppId == aOther.mAppId && + mInBrowser == aOther.mInBrowser; + } + bool operator!=(const OriginAttributes& aOther) const + { + return !(*this == aOther); + } + + // Serializes non-default values into the suffix format, i.e. + // |!key1=value1&key2=value2|. If there are no non-default attributes, this + // returns an empty string. + void CreateSuffix(nsACString& aStr); + + void Serialize(nsIObjectOutputStream* aStream) const; + nsresult Deserialize(nsIObjectInputStream* aStream); +}; + /* * Base class from which all nsIPrincipal implementations inherit. Use this for * default implementations and other commonalities between principal @@ -51,33 +80,7 @@ public: virtual bool IsOnCSSUnprefixingWhitelist() override { return false; } static BasePrincipal* Cast(nsIPrincipal* aPrin) { return static_cast(aPrin); } - - struct OriginAttributes : public dom::OriginAttributesDictionary { - OriginAttributes() {} - OriginAttributes(uint32_t aAppId, bool aInBrowser) - { - mAppId = aAppId; - mInBrowser = aInBrowser; - } - - bool operator==(const OriginAttributes& aOther) const - { - return mAppId == aOther.mAppId && - mInBrowser == aOther.mInBrowser; - } - bool operator!=(const OriginAttributes& aOther) const - { - return !(*this == aOther); - } - - // Serializes non-default values into the suffix format, i.e. - // |!key1=value1&key2=value2|. If there are no non-default attributes, this - // returns an empty string. - void CreateSuffix(nsACString& aStr); - - void Serialize(nsIObjectOutputStream* aStream) const; - nsresult Deserialize(nsIObjectInputStream* aStream); - }; + static already_AddRefed CreateCodebasePrincipal(nsIURI* aURI, OriginAttributes& aAttrs); const OriginAttributes& OriginAttributesRef() { return mOriginAttributes; } uint32_t AppId() const { return mOriginAttributes.mAppId; } diff --git a/caps/nsIScriptSecurityManager.idl b/caps/nsIScriptSecurityManager.idl index 76465abc70e..099f5d5dc0a 100644 --- a/caps/nsIScriptSecurityManager.idl +++ b/caps/nsIScriptSecurityManager.idl @@ -26,7 +26,7 @@ class DomainPolicyClone; [ptr] native JSObjectPtr(JSObject); [ptr] native DomainPolicyClonePtr(mozilla::dom::DomainPolicyClone); -[scriptable, uuid(ba602ca6-dc7a-457e-a57a-ee5b343fd863)] +[scriptable, uuid(f4c578b8-5bac-4ba1-9582-f1140e09a3b4)] interface nsIScriptSecurityManager : nsISupports { /** @@ -179,12 +179,28 @@ interface nsIScriptSecurityManager : nsISupports nsIPrincipal getNoAppCodebasePrincipal(in nsIURI uri); /** - * Legacy name for getNoAppCodebasePrincipal. + * Legacy method for getting a principal with no origin attributes. * - * @deprecated use getNoAppCodebasePrincipal instead. + * @deprecated use createCodebasePrincipal instead. */ [deprecated] nsIPrincipal getCodebasePrincipal(in nsIURI uri); + /** + * Returns a principal whose origin is composed of |uri| and |originAttributes|. + * See nsIPrincipal.h for a description of origin attributes, and + * SystemDictionaries.webidl for a list of origin attributes and their defaults. + */ + [implicit_jscontext] + nsIPrincipal createCodebasePrincipal(in nsIURI uri, in jsval originAttributes); + + /** + * Returns a unique nonce principal with |originAttributes|. + * See nsIPrincipal.h for a description of origin attributes, and + * SystemDictionaries.webidl for a list of origin attributes and their defaults. + */ + [implicit_jscontext] + nsIPrincipal createNullPrincipal(in jsval originAttributes); + /** * Returns OK if aSourceURI and target have the same "origin" * (scheme, host, and port). diff --git a/caps/nsNullPrincipal.h b/caps/nsNullPrincipal.h index 4ad6296da96..95668432190 100644 --- a/caps/nsNullPrincipal.h +++ b/caps/nsNullPrincipal.h @@ -54,9 +54,9 @@ public: // Returns null on failure. static already_AddRefed - Create(const OriginAttributes& aOriginAttributes = OriginAttributes()); + Create(const mozilla::OriginAttributes& aOriginAttributes = mozilla::OriginAttributes()); - nsresult Init(const OriginAttributes& aOriginAttributes = OriginAttributes()); + nsresult Init(const mozilla::OriginAttributes& aOriginAttributes = mozilla::OriginAttributes()); virtual void GetScriptLocation(nsACString &aStr) override; diff --git a/caps/nsPrincipal.h b/caps/nsPrincipal.h index be491ffa2d4..31897204fae 100644 --- a/caps/nsPrincipal.h +++ b/caps/nsPrincipal.h @@ -34,7 +34,7 @@ public: nsPrincipal(); // Init() must be called before the principal is in a usable state. - nsresult Init(nsIURI* aCodebase, const OriginAttributes& aOriginAttributes); + nsresult Init(nsIURI* aCodebase, const mozilla::OriginAttributes& aOriginAttributes); virtual void GetScriptLocation(nsACString& aStr) override; void SetURI(nsIURI* aURI); diff --git a/caps/nsScriptSecurityManager.cpp b/caps/nsScriptSecurityManager.cpp index 703262310fb..c34fdeaa4f8 100644 --- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -19,6 +19,7 @@ #include "nsINestedURI.h" #include "nspr.h" #include "nsJSPrincipals.h" +#include "mozilla/BasePrincipal.h" #include "nsSystemPrincipal.h" #include "nsPrincipal.h" #include "nsNullPrincipal.h" @@ -378,8 +379,10 @@ nsScriptSecurityManager::GetChannelURIPrincipal(nsIChannel* aChannel, return GetLoadContextCodebasePrincipal(uri, loadContext, aPrincipal); } - return GetCodebasePrincipalInternal(uri, UNKNOWN_APP_ID, - /* isInBrowserElement */ false, aPrincipal); + OriginAttributes attrs(UNKNOWN_APP_ID, false); + nsCOMPtr prin = BasePrincipal::CreateCodebasePrincipal(uri, attrs); + prin.forget(aPrincipal); + return *aPrincipal ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP @@ -979,55 +982,24 @@ nsScriptSecurityManager::GetSystemPrincipal(nsIPrincipal **result) return NS_OK; } -nsresult -nsScriptSecurityManager::CreateCodebasePrincipal(nsIURI* aURI, uint32_t aAppId, - bool aInMozBrowser, - nsIPrincipal **result) -{ - // I _think_ it's safe to not create null principals here based on aURI. - // At least all the callers would do the right thing in those cases, as far - // as I can tell. --bz - - nsCOMPtr uriPrinc = do_QueryInterface(aURI); - if (uriPrinc) { - nsCOMPtr principal; - uriPrinc->GetPrincipal(getter_AddRefs(principal)); - if (!principal) { - principal = nsNullPrincipal::Create(); - NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE); - } - - principal.forget(result); - - return NS_OK; - } - - BasePrincipal::OriginAttributes attrs(aAppId, aInMozBrowser); - nsRefPtr codebase = new nsPrincipal(); - nsresult rv = codebase->Init(aURI, attrs); - if (NS_FAILED(rv)) - return rv; - - NS_ADDREF(*result = codebase); - - return NS_OK; -} - NS_IMETHODIMP nsScriptSecurityManager::GetSimpleCodebasePrincipal(nsIURI* aURI, nsIPrincipal** aPrincipal) { - return GetCodebasePrincipalInternal(aURI, - nsIScriptSecurityManager::UNKNOWN_APP_ID, - false, aPrincipal); + OriginAttributes attrs(UNKNOWN_APP_ID, false); + nsCOMPtr prin = BasePrincipal::CreateCodebasePrincipal(aURI, attrs); + prin.forget(aPrincipal); + return *aPrincipal ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP nsScriptSecurityManager::GetNoAppCodebasePrincipal(nsIURI* aURI, nsIPrincipal** aPrincipal) { - return GetCodebasePrincipalInternal(aURI, nsIScriptSecurityManager::NO_APP_ID, - false, aPrincipal); + OriginAttributes attrs(NO_APP_ID, false); + nsCOMPtr prin = BasePrincipal::CreateCodebasePrincipal(aURI, attrs); + prin.forget(aPrincipal); + return *aPrincipal ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP @@ -1037,6 +1009,33 @@ nsScriptSecurityManager::GetCodebasePrincipal(nsIURI* aURI, return GetNoAppCodebasePrincipal(aURI, aPrincipal); } +NS_IMETHODIMP +nsScriptSecurityManager::CreateCodebasePrincipal(nsIURI* aURI, JS::Handle aOriginAttributes, + JSContext* aCx, nsIPrincipal** aPrincipal) +{ + OriginAttributes attrs; + if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) { + return NS_ERROR_INVALID_ARG; + } + nsCOMPtr prin = BasePrincipal::CreateCodebasePrincipal(aURI, attrs); + prin.forget(aPrincipal); + return *aPrincipal ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsScriptSecurityManager::CreateNullPrincipal(JS::Handle aOriginAttributes, + JSContext* aCx, nsIPrincipal** aPrincipal) +{ + OriginAttributes attrs; + if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) { + return NS_ERROR_INVALID_ARG; + } + nsCOMPtr prin = nsNullPrincipal::Create(attrs); + NS_ENSURE_TRUE(prin, NS_ERROR_FAILURE); + prin.forget(aPrincipal); + return NS_OK; +} + NS_IMETHODIMP nsScriptSecurityManager::GetAppCodebasePrincipal(nsIURI* aURI, uint32_t aAppId, @@ -1046,7 +1045,10 @@ nsScriptSecurityManager::GetAppCodebasePrincipal(nsIURI* aURI, NS_ENSURE_TRUE(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID, NS_ERROR_INVALID_ARG); - return GetCodebasePrincipalInternal(aURI, aAppId, aInMozBrowser, aPrincipal); + OriginAttributes attrs(aAppId, aInMozBrowser); + nsCOMPtr prin = BasePrincipal::CreateCodebasePrincipal(aURI, attrs); + prin.forget(aPrincipal); + return *aPrincipal ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP @@ -1055,14 +1057,13 @@ nsScriptSecurityManager:: nsILoadContext* aLoadContext, nsIPrincipal** aPrincipal) { - uint32_t appId; - aLoadContext->GetAppId(&appId); - bool isInBrowserElement; - aLoadContext->GetIsInBrowserElement(&isInBrowserElement); - return GetCodebasePrincipalInternal(aURI, - appId, - isInBrowserElement, - aPrincipal); + // XXXbholley - Make this more general in bug 1165466. + OriginAttributes attrs; + aLoadContext->GetAppId(&attrs.mAppId); + aLoadContext->GetIsInBrowserElement(&attrs.mInBrowser); + nsCOMPtr prin = BasePrincipal::CreateCodebasePrincipal(aURI, attrs); + prin.forget(aPrincipal); + return *aPrincipal ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP @@ -1070,37 +1071,11 @@ nsScriptSecurityManager::GetDocShellCodebasePrincipal(nsIURI* aURI, nsIDocShell* aDocShell, nsIPrincipal** aPrincipal) { - return GetCodebasePrincipalInternal(aURI, - aDocShell->GetAppId(), - aDocShell->GetIsInBrowserElement(), - aPrincipal); -} - -nsresult -nsScriptSecurityManager::GetCodebasePrincipalInternal(nsIURI *aURI, - uint32_t aAppId, - bool aInMozBrowser, - nsIPrincipal **result) -{ - NS_ENSURE_ARG(aURI); - - bool inheritsPrincipal; - nsresult rv = - NS_URIChainHasFlags(aURI, - nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT, - &inheritsPrincipal); - nsCOMPtr principal; - if (NS_FAILED(rv) || inheritsPrincipal) { - principal = nsNullPrincipal::Create(); - NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE); - } else { - rv = CreateCodebasePrincipal(aURI, aAppId, aInMozBrowser, - getter_AddRefs(principal)); - NS_ENSURE_SUCCESS(rv, rv); - } - principal.forget(result); - - return NS_OK; + // XXXbholley - Make this more general in bug 1165466. + OriginAttributes attrs(aDocShell->GetAppId(), aDocShell->GetIsInBrowserElement()); + nsCOMPtr prin = BasePrincipal::CreateCodebasePrincipal(aURI, attrs); + prin.forget(aPrincipal); + return *aPrincipal ? NS_OK : NS_ERROR_FAILURE; } // static diff --git a/caps/nsScriptSecurityManager.h b/caps/nsScriptSecurityManager.h index edd5e1dd843..342e9b84aca 100644 --- a/caps/nsScriptSecurityManager.h +++ b/caps/nsScriptSecurityManager.h @@ -22,6 +22,10 @@ class nsIIOService; class nsIStringBundle; class nsSystemPrincipal; +namespace mozilla { +class OriginAttributes; +} + ///////////////////////////// // nsScriptSecurityManager // ///////////////////////////// @@ -99,15 +103,6 @@ private: // should error out at that point. static nsIPrincipal* doGetObjectPrincipal(JSObject* obj); - nsresult - GetCodebasePrincipalInternal(nsIURI* aURI, uint32_t aAppId, - bool aInMozBrowser, - nsIPrincipal** result); - - nsresult - CreateCodebasePrincipal(nsIURI* aURI, uint32_t aAppId, bool aInMozBrowser, - nsIPrincipal** result); - nsresult Init(); diff --git a/dom/webidl/SystemDictionaries.webidl b/dom/webidl/SystemDictionaries.webidl index 44a53fba6f6..4205aae5ca0 100644 --- a/dom/webidl/SystemDictionaries.webidl +++ b/dom/webidl/SystemDictionaries.webidl @@ -12,9 +12,9 @@ * attributes. * * IMPORTANT: If you add any members here, you need to update the - * CreateSuffix, Serialize, and Deserialize implementations in BasePrincipal, - * and bump the CIDs of all the principal implementations that invoke those - * methods. + * methods on mozilla::OriginAttributes, and bump the CIDs of all + * the principal implementations that use OriginAttributes in their + * nsISerializable implementations. */ dictionary OriginAttributesDictionary { unsigned long appId = 0;