1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/BasePrincipal.h"
9 #include "nsDocShell.h"
10 #include "nsIContentSecurityPolicy.h"
11 #include "nsIObjectInputStream.h"
12 #include "nsIObjectOutputStream.h"
13 #include "nsIStandardURL.h"
15 #include "ExpandedPrincipal.h"
16 #include "nsNetUtil.h"
17 #include "nsIURIWithSpecialOrigin.h"
18 #include "nsScriptSecurityManager.h"
19 #include "nsServiceManagerUtils.h"
21 #include "mozilla/ContentPrincipal.h"
22 #include "mozilla/NullPrincipal.h"
23 #include "mozilla/dom/BlobURLProtocolHandler.h"
24 #include "mozilla/dom/ChromeUtils.h"
25 #include "mozilla/dom/CSPDictionariesBinding.h"
26 #include "mozilla/dom/nsCSPContext.h"
27 #include "mozilla/dom/ToJSValue.h"
31 BasePrincipal::BasePrincipal(PrincipalKind aKind
)
32 : mKind(aKind
), mHasExplicitDomain(false), mInitialized(false) {}
34 BasePrincipal::~BasePrincipal() {}
37 BasePrincipal::GetOrigin(nsACString
& aOrigin
) {
38 MOZ_ASSERT(mInitialized
);
40 nsresult rv
= GetOriginNoSuffix(aOrigin
);
41 NS_ENSURE_SUCCESS(rv
, rv
);
44 rv
= GetOriginSuffix(suffix
);
45 NS_ENSURE_SUCCESS(rv
, rv
);
46 aOrigin
.Append(suffix
);
51 BasePrincipal::GetOriginNoSuffix(nsACString
& aOrigin
) {
52 MOZ_ASSERT(mInitialized
);
53 mOriginNoSuffix
->ToUTF8String(aOrigin
);
58 BasePrincipal::GetSiteOrigin(nsACString
& aSiteOrigin
) {
59 MOZ_ASSERT(mInitialized
);
60 return GetOrigin(aSiteOrigin
);
63 bool BasePrincipal::Subsumes(nsIPrincipal
* aOther
,
64 DocumentDomainConsideration aConsideration
) {
66 MOZ_ASSERT_IF(Kind() == eCodebasePrincipal
, mOriginSuffix
);
68 // Expanded principals handle origin attributes for each of their
69 // sub-principals individually, null principals do only simple checks for
70 // pointer equality, and system principals are immune to origin attributes
71 // checks, so only do this check for codebase principals.
72 if (Kind() == eCodebasePrincipal
&&
73 mOriginSuffix
!= Cast(aOther
)->mOriginSuffix
) {
77 return SubsumesInternal(aOther
, aConsideration
);
81 BasePrincipal::Equals(nsIPrincipal
* aOther
, bool* aResult
) {
82 NS_ENSURE_TRUE(aOther
, NS_ERROR_INVALID_ARG
);
84 *aResult
= FastEquals(aOther
);
90 BasePrincipal::EqualsConsideringDomain(nsIPrincipal
* aOther
, bool* aResult
) {
91 NS_ENSURE_TRUE(aOther
, NS_ERROR_INVALID_ARG
);
93 *aResult
= FastEqualsConsideringDomain(aOther
);
99 BasePrincipal::Subsumes(nsIPrincipal
* aOther
, bool* aResult
) {
100 NS_ENSURE_TRUE(aOther
, NS_ERROR_INVALID_ARG
);
102 *aResult
= FastSubsumes(aOther
);
108 BasePrincipal::SubsumesConsideringDomain(nsIPrincipal
* aOther
, bool* aResult
) {
109 NS_ENSURE_TRUE(aOther
, NS_ERROR_INVALID_ARG
);
111 *aResult
= FastSubsumesConsideringDomain(aOther
);
117 BasePrincipal::SubsumesConsideringDomainIgnoringFPD(nsIPrincipal
* aOther
,
119 NS_ENSURE_TRUE(aOther
, NS_ERROR_INVALID_ARG
);
121 *aResult
= FastSubsumesConsideringDomainIgnoringFPD(aOther
);
127 BasePrincipal::CheckMayLoad(nsIURI
* aURI
, bool aReport
,
128 bool aAllowIfInheritsPrincipal
) {
129 // Check the internal method first, which allows us to quickly approve loads
130 // for the System Principal.
131 if (MayLoadInternal(aURI
)) {
136 if (aAllowIfInheritsPrincipal
) {
137 // If the caller specified to allow loads of URIs that inherit
138 // our principal, allow the load if this URI inherits its principal.
139 bool doesInheritSecurityContext
;
140 rv
= NS_URIChainHasFlags(aURI
,
141 nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT
,
142 &doesInheritSecurityContext
);
143 if (NS_SUCCEEDED(rv
) && doesInheritSecurityContext
) {
148 bool fetchableByAnyone
;
149 rv
= NS_URIChainHasFlags(aURI
, nsIProtocolHandler::URI_FETCHABLE_BY_ANYONE
,
151 if (NS_SUCCEEDED(rv
) && fetchableByAnyone
) {
156 nsCOMPtr
<nsIURI
> prinURI
;
157 rv
= GetURI(getter_AddRefs(prinURI
));
158 if (NS_SUCCEEDED(rv
) && prinURI
) {
159 nsScriptSecurityManager::ReportError(
160 "CheckSameOriginError", prinURI
, aURI
,
161 mOriginAttributes
.mPrivateBrowsingId
> 0);
165 return NS_ERROR_DOM_BAD_URI
;
169 BasePrincipal::GetCsp(nsIContentSecurityPolicy
** aCsp
) {
170 NS_IF_ADDREF(*aCsp
= mCSP
);
175 BasePrincipal::SetCsp(nsIContentSecurityPolicy
* aCsp
) {
176 // Never destroy an existing CSP on the principal.
177 // This method should only be called in rare cases.
179 MOZ_ASSERT(!mCSP
, "do not destroy an existing CSP");
181 return NS_ERROR_ALREADY_INITIALIZED
;
189 BasePrincipal::EnsureCSP(dom::Document
* aDocument
,
190 nsIContentSecurityPolicy
** aCSP
) {
192 // if there is a CSP already associated with this principal
193 // then just return that - do not overwrite it!!!
194 NS_IF_ADDREF(*aCSP
= mCSP
);
199 mCSP
= do_CreateInstance("@mozilla.org/cspcontext;1", &rv
);
200 NS_ENSURE_SUCCESS(rv
, rv
);
202 // Store the request context for violation reports
203 rv
= aDocument
? mCSP
->SetRequestContext(aDocument
, nullptr)
204 : mCSP
->SetRequestContext(nullptr, this);
205 NS_ENSURE_SUCCESS(rv
, rv
);
206 NS_IF_ADDREF(*aCSP
= mCSP
);
211 BasePrincipal::GetPreloadCsp(nsIContentSecurityPolicy
** aPreloadCSP
) {
212 NS_IF_ADDREF(*aPreloadCSP
= mPreloadCSP
);
217 BasePrincipal::EnsurePreloadCSP(dom::Document
* aDocument
,
218 nsIContentSecurityPolicy
** aPreloadCSP
) {
220 // if there is a speculative CSP already associated with this principal
221 // then just return that - do not overwrite it!!!
222 NS_IF_ADDREF(*aPreloadCSP
= mPreloadCSP
);
227 mPreloadCSP
= do_CreateInstance("@mozilla.org/cspcontext;1", &rv
);
228 NS_ENSURE_SUCCESS(rv
, rv
);
230 // Store the request context for violation reports
231 rv
= aDocument
? mPreloadCSP
->SetRequestContext(aDocument
, nullptr)
232 : mPreloadCSP
->SetRequestContext(nullptr, this);
233 NS_ENSURE_SUCCESS(rv
, rv
);
234 NS_IF_ADDREF(*aPreloadCSP
= mPreloadCSP
);
239 BasePrincipal::GetCspJSON(nsAString
& outCSPinJSON
) {
240 outCSPinJSON
.Truncate();
241 dom::CSPPolicies jsonPolicies
;
244 jsonPolicies
.ToJSON(outCSPinJSON
);
247 return mCSP
->ToJSON(outCSPinJSON
);
251 BasePrincipal::GetIsNullPrincipal(bool* aResult
) {
252 *aResult
= Kind() == eNullPrincipal
;
257 BasePrincipal::GetIsCodebasePrincipal(bool* aResult
) {
258 *aResult
= Kind() == eCodebasePrincipal
;
263 BasePrincipal::GetIsExpandedPrincipal(bool* aResult
) {
264 *aResult
= Kind() == eExpandedPrincipal
;
269 BasePrincipal::GetIsSystemPrincipal(bool* aResult
) {
270 *aResult
= IsSystemPrincipal();
275 BasePrincipal::GetIsAddonOrExpandedAddonPrincipal(bool* aResult
) {
276 *aResult
= AddonPolicy() || ContentScriptAddonPolicy();
281 BasePrincipal::GetOriginAttributes(JSContext
* aCx
,
282 JS::MutableHandle
<JS::Value
> aVal
) {
283 if (NS_WARN_IF(!ToJSValue(aCx
, mOriginAttributes
, aVal
))) {
284 return NS_ERROR_FAILURE
;
290 BasePrincipal::GetOriginSuffix(nsACString
& aOriginAttributes
) {
291 MOZ_ASSERT(mOriginSuffix
);
292 mOriginSuffix
->ToUTF8String(aOriginAttributes
);
297 BasePrincipal::GetAppId(uint32_t* aAppId
) {
298 if (AppId() == nsIScriptSecurityManager::UNKNOWN_APP_ID
) {
300 *aAppId
= nsIScriptSecurityManager::NO_APP_ID
;
309 BasePrincipal::GetUserContextId(uint32_t* aUserContextId
) {
310 *aUserContextId
= UserContextId();
315 BasePrincipal::GetPrivateBrowsingId(uint32_t* aPrivateBrowsingId
) {
316 *aPrivateBrowsingId
= PrivateBrowsingId();
321 BasePrincipal::GetIsInIsolatedMozBrowserElement(
322 bool* aIsInIsolatedMozBrowserElement
) {
323 *aIsInIsolatedMozBrowserElement
= IsInIsolatedMozBrowserElement();
327 nsresult
BasePrincipal::GetAddonPolicy(nsISupports
** aResult
) {
328 RefPtr
<extensions::WebExtensionPolicy
> policy(AddonPolicy());
329 policy
.forget(aResult
);
333 extensions::WebExtensionPolicy
* BasePrincipal::AddonPolicy() {
334 if (Is
<ContentPrincipal
>()) {
335 return As
<ContentPrincipal
>()->AddonPolicy();
340 bool BasePrincipal::AddonHasPermission(const nsAtom
* aPerm
) {
341 if (auto policy
= AddonPolicy()) {
342 return policy
->HasPermission(aPerm
);
347 nsIPrincipal
* BasePrincipal::PrincipalToInherit(nsIURI
* aRequestedURI
) {
348 if (Is
<ExpandedPrincipal
>()) {
349 return As
<ExpandedPrincipal
>()->PrincipalToInherit(aRequestedURI
);
354 already_AddRefed
<BasePrincipal
> BasePrincipal::CreateCodebasePrincipal(
355 nsIURI
* aURI
, const OriginAttributes
& aAttrs
) {
358 nsAutoCString originNoSuffix
;
360 ContentPrincipal::GenerateOriginNoSuffixFromURI(aURI
, originNoSuffix
);
362 // If the generation of the origin fails, we still want to have a valid
363 // principal. Better to return a null principal here.
364 return NullPrincipal::Create(aAttrs
);
367 return CreateCodebasePrincipal(aURI
, aAttrs
, originNoSuffix
);
370 already_AddRefed
<BasePrincipal
> BasePrincipal::CreateCodebasePrincipal(
371 nsIURI
* aURI
, const OriginAttributes
& aAttrs
,
372 const nsACString
& aOriginNoSuffix
) {
374 MOZ_ASSERT(!aOriginNoSuffix
.IsEmpty());
376 // If the URI is supposed to inherit the security context of whoever loads it,
377 // we shouldn't make a codebase principal for it.
378 bool inheritsPrincipal
;
379 nsresult rv
= NS_URIChainHasFlags(
380 aURI
, nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT
,
382 if (NS_FAILED(rv
) || inheritsPrincipal
) {
383 return NullPrincipal::Create(aAttrs
);
386 // Check whether the URI knows what its principal is supposed to be.
387 #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
388 nsCOMPtr
<nsIURIWithSpecialOrigin
> uriWithSpecialOrigin
=
389 do_QueryInterface(aURI
);
390 if (uriWithSpecialOrigin
) {
391 nsCOMPtr
<nsIURI
> origin
;
392 rv
= uriWithSpecialOrigin
->GetOrigin(getter_AddRefs(origin
));
393 if (NS_WARN_IF(NS_FAILED(rv
))) {
397 OriginAttributes attrs
;
398 RefPtr
<BasePrincipal
> principal
= CreateCodebasePrincipal(origin
, attrs
);
399 return principal
.forget();
403 nsCOMPtr
<nsIPrincipal
> blobPrincipal
;
404 if (dom::BlobURLProtocolHandler::GetBlobURLPrincipal(
405 aURI
, getter_AddRefs(blobPrincipal
))) {
406 MOZ_ASSERT(blobPrincipal
);
407 RefPtr
<BasePrincipal
> principal
= Cast(blobPrincipal
);
408 return principal
.forget();
411 // Mint a codebase principal.
412 RefPtr
<ContentPrincipal
> codebase
= new ContentPrincipal();
413 rv
= codebase
->Init(aURI
, aAttrs
, aOriginNoSuffix
);
414 NS_ENSURE_SUCCESS(rv
, nullptr);
415 return codebase
.forget();
418 already_AddRefed
<BasePrincipal
> BasePrincipal::CreateCodebasePrincipal(
419 const nsACString
& aOrigin
) {
420 MOZ_ASSERT(!StringBeginsWith(aOrigin
, NS_LITERAL_CSTRING("[")),
421 "CreateCodebasePrincipal does not support System and Expanded "
424 MOZ_ASSERT(!StringBeginsWith(aOrigin
,
425 NS_LITERAL_CSTRING(NS_NULLPRINCIPAL_SCHEME
":")),
426 "CreateCodebasePrincipal does not support NullPrincipal");
428 nsAutoCString originNoSuffix
;
429 OriginAttributes attrs
;
430 if (!attrs
.PopulateFromOrigin(aOrigin
, originNoSuffix
)) {
434 nsCOMPtr
<nsIURI
> uri
;
435 nsresult rv
= NS_NewURI(getter_AddRefs(uri
), originNoSuffix
);
436 NS_ENSURE_SUCCESS(rv
, nullptr);
438 return BasePrincipal::CreateCodebasePrincipal(uri
, attrs
);
441 already_AddRefed
<BasePrincipal
>
442 BasePrincipal::CloneStrippingUserContextIdAndFirstPartyDomain() {
443 OriginAttributes attrs
= OriginAttributesRef();
444 attrs
.StripAttributes(OriginAttributes::STRIP_USER_CONTEXT_ID
|
445 OriginAttributes::STRIP_FIRST_PARTY_DOMAIN
);
447 nsAutoCString originNoSuffix
;
448 nsresult rv
= GetOriginNoSuffix(originNoSuffix
);
449 NS_ENSURE_SUCCESS(rv
, nullptr);
451 nsCOMPtr
<nsIURI
> uri
;
452 rv
= NS_NewURI(getter_AddRefs(uri
), originNoSuffix
);
453 NS_ENSURE_SUCCESS(rv
, nullptr);
455 return BasePrincipal::CreateCodebasePrincipal(uri
, attrs
);
458 extensions::WebExtensionPolicy
* BasePrincipal::ContentScriptAddonPolicy() {
459 if (!Is
<ExpandedPrincipal
>()) {
463 auto expanded
= As
<ExpandedPrincipal
>();
464 for (auto& prin
: expanded
->AllowList()) {
465 if (auto policy
= BasePrincipal::Cast(prin
)->AddonPolicy()) {
473 bool BasePrincipal::AddonAllowsLoad(nsIURI
* aURI
,
474 bool aExplicit
/* = false */) {
475 if (Is
<ExpandedPrincipal
>()) {
476 return As
<ExpandedPrincipal
>()->AddonAllowsLoad(aURI
, aExplicit
);
478 if (auto policy
= AddonPolicy()) {
479 return policy
->CanAccessURI(aURI
, aExplicit
);
484 void BasePrincipal::FinishInit(const nsACString
& aOriginNoSuffix
,
485 const OriginAttributes
& aOriginAttributes
) {
487 mOriginAttributes
= aOriginAttributes
;
489 // First compute the origin suffix since it's infallible.
490 nsAutoCString originSuffix
;
491 mOriginAttributes
.CreateSuffix(originSuffix
);
492 mOriginSuffix
= NS_Atomize(originSuffix
);
494 MOZ_ASSERT(!aOriginNoSuffix
.IsEmpty());
495 mOriginNoSuffix
= NS_Atomize(aOriginNoSuffix
);
498 void BasePrincipal::FinishInit(BasePrincipal
* aOther
,
499 const OriginAttributes
& aOriginAttributes
) {
501 mOriginAttributes
= aOriginAttributes
;
503 // First compute the origin suffix since it's infallible.
504 nsAutoCString originSuffix
;
505 mOriginAttributes
.CreateSuffix(originSuffix
);
506 mOriginSuffix
= NS_Atomize(originSuffix
);
508 mOriginNoSuffix
= aOther
->mOriginNoSuffix
;
509 mHasExplicitDomain
= aOther
->mHasExplicitDomain
;
511 if (aOther
->mPreloadCSP
) {
512 mPreloadCSP
= do_CreateInstance("@mozilla.org/cspcontext;1");
513 nsCSPContext
* preloadCSP
= static_cast<nsCSPContext
*>(mPreloadCSP
.get());
514 preloadCSP
->InitFromOther(
515 static_cast<nsCSPContext
*>(aOther
->mPreloadCSP
.get()), nullptr, this);
519 mCSP
= do_CreateInstance("@mozilla.org/cspcontext;1");
520 nsCSPContext
* csp
= static_cast<nsCSPContext
*>(mCSP
.get());
521 csp
->InitFromOther(static_cast<nsCSPContext
*>(aOther
->mCSP
.get()), nullptr,
526 bool SiteIdentifier::Equals(const SiteIdentifier
& aOther
) const {
527 MOZ_ASSERT(IsInitialized());
528 MOZ_ASSERT(aOther
.IsInitialized());
529 return mPrincipal
->FastEquals(aOther
.mPrincipal
);
532 } // namespace mozilla