Skip to content
This repository has been archived by the owner on Aug 4, 2022. It is now read-only.

Commit

Permalink
Bug 1345573 - Part 1: Key http, https, and ftp URIs on origin instead…
Browse files Browse the repository at this point in the history
… of eTLD+1, r=baku

MozReview-Commit-ID: Gihc4QFf11R
  • Loading branch information
mystor committed Mar 21, 2017
1 parent c9d0e86 commit 5eef733
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 61 deletions.
9 changes: 6 additions & 3 deletions dom/ipc/ContentParent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5096,9 +5096,12 @@ ContentParent::TransmitPermissionsFor(nsIChannel* aChannel)
NS_ENSURE_SUCCESS(rv, rv);

// Create the key, and send it down to the content process.
nsAutoCString key;
nsPermissionManager::GetKeyForPrincipal(principal, key);
EnsurePermissionsByKey(key);
nsTArray<nsCString> keys =
nsPermissionManager::GetAllKeysForPrincipal(principal);
MOZ_ASSERT(keys.Length() >= 1);
for (auto& key : keys) {
EnsurePermissionsByKey(key);
}
#endif

return NS_OK;
Expand Down
148 changes: 90 additions & 58 deletions extensions/cookie/nsPermissionManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,54 @@ GetNextSubDomainForHost(const nsACString& aHost)
return subDomain;
}

// This function produces a nsIPrincipal which is identical to the current
// nsIPrincipal, except that it has one less subdomain segment. It returns
// `nullptr` if there are no more segments to remove.
already_AddRefed<nsIPrincipal>
GetNextSubDomainPrincipal(nsIPrincipal* aPrincipal)
{
nsCOMPtr<nsIURI> uri;
nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri));
if (NS_FAILED(rv) || !uri) {
return nullptr;
}

nsAutoCString host;
rv = uri->GetHost(host);
if (NS_FAILED(rv)) {
return nullptr;
}

nsCString domain = GetNextSubDomainForHost(host);
if (domain.IsEmpty()) {
return nullptr;
}

// Create a new principal which is identical to the current one, but with the new host
nsCOMPtr<nsIURI> newURI;
rv = uri->Clone(getter_AddRefs(newURI));
if (NS_FAILED(rv)) {
return nullptr;
}

rv = newURI->SetHost(domain);
if (NS_FAILED(rv)) {
return nullptr;
}

// Copy the attributes over
mozilla::OriginAttributes attrs = aPrincipal->OriginAttributesRef();

// Disable userContext and firstParty isolation for permissions.
attrs.StripAttributes(mozilla::OriginAttributes::STRIP_USER_CONTEXT_ID |
mozilla::OriginAttributes::STRIP_FIRST_PARTY_DOMAIN);

nsCOMPtr<nsIPrincipal> principal =
mozilla::BasePrincipal::CreateCodebasePrincipal(newURI, attrs);

return principal.forget();
}

class ClearOriginDataObserver final : public nsIObserver {
~ClearOriginDataObserver() {}

Expand Down Expand Up @@ -2185,46 +2233,11 @@ nsPermissionManager::GetPermissionHashKey(nsIPrincipal* aPrincipal,

// If aExactHostMatch wasn't true, we can check if the base domain has a permission entry.
if (!aExactHostMatch) {
nsCOMPtr<nsIURI> uri;
nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri));
if (NS_FAILED(rv)) {
return nullptr;
}

nsAutoCString host;
rv = uri->GetHost(host);
if (NS_FAILED(rv)) {
return nullptr;
}

nsCString domain = GetNextSubDomainForHost(host);
if (domain.IsEmpty()) {
return nullptr;
}

// Create a new principal which is identical to the current one, but with the new host
nsCOMPtr<nsIURI> newURI;
rv = uri->Clone(getter_AddRefs(newURI));
if (NS_FAILED(rv)) {
return nullptr;
}

rv = newURI->SetHost(domain);
if (NS_FAILED(rv)) {
return nullptr;
}

// Copy the attributes over
mozilla::OriginAttributes attrs = aPrincipal->OriginAttributesRef();

// Disable userContext and firstParty isolation for permissions.
attrs.StripAttributes(mozilla::OriginAttributes::STRIP_USER_CONTEXT_ID |
mozilla::OriginAttributes::STRIP_FIRST_PARTY_DOMAIN);

nsCOMPtr<nsIPrincipal> principal =
mozilla::BasePrincipal::CreateCodebasePrincipal(newURI, attrs);

return GetPermissionHashKey(principal, aType, aExactHostMatch);
GetNextSubDomainPrincipal(aPrincipal);
if (principal) {
return GetPermissionHashKey(principal, aType, aExactHostMatch);
}
}

// No entry, really...
Expand Down Expand Up @@ -3014,7 +3027,6 @@ nsPermissionManager::SetPermissionsWithKey(const nsACString& aPermissionKey,
return NS_OK;
}

// XXX: Support file URIs here as well!
/* static */ void
nsPermissionManager::GetKeyForPrincipal(nsIPrincipal* aPrincipal, nsACString& aKey)
{
Expand All @@ -3027,31 +3039,51 @@ nsPermissionManager::GetKeyForPrincipal(nsIPrincipal* aPrincipal, nsACString& aK
// NOTE: We don't propagate the error here, instead we produce the default
// "" permission key. This means that we can assign every principal a key,
// even if the GetURI operation on that principal is not meaningful.
aKey.Truncate();
return;
}

// If the URI isn't of one of the supported schemes, it has the "" permission
// key. We can do an early return in that case.
nsAutoCString scheme;
uri->GetScheme(scheme);
if (!scheme.EqualsLiteral("http") &&
!scheme.EqualsLiteral("https") &&
!scheme.EqualsLiteral("ftp")) {
rv = uri->GetScheme(scheme);
if (NS_WARN_IF(NS_FAILED(rv))) {
// NOTE: Produce the default "" key as a fallback.
aKey.Truncate();
return;
}

// We key sets of permissions to be sent over IPC based on their eTLD+1, or in
// the case where that isn't meaningful, on their IP address or spec.
nsCOMPtr<nsIEffectiveTLDService> etldService =
do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
rv = etldService->GetBaseDomain(uri, 0, aKey);
if (NS_FAILED(rv)) {
rv = uri->GetHost(aKey);
}
if (NS_FAILED(rv)) {
rv = uri->GetSpec(aKey);
// URIs which have schemes other than http, https and ftp share the ""
// permission key.
if (scheme.EqualsLiteral("http") ||
scheme.EqualsLiteral("https") ||
scheme.EqualsLiteral("ftp")) {
rv = GetOriginFromPrincipal(aPrincipal, aKey);
if (NS_SUCCEEDED(rv)) {
return;
}
}
if (NS_FAILED(rv)) {
aKey.Truncate();

// NOTE: Produce the default "" key as a fallback.
aKey.Truncate();
return;
}

/* static */ nsTArray<nsCString>
nsPermissionManager::GetAllKeysForPrincipal(nsIPrincipal* aPrincipal)
{
MOZ_ASSERT(aPrincipal);

nsTArray<nsCString> keys;
nsCOMPtr<nsIPrincipal> prin = aPrincipal;
while (prin) {
// Add the key to the list
nsCString* key = keys.AppendElement();
GetKeyForPrincipal(prin, *key);

// Get the next subdomain principal and loop back around.
prin = GetNextSubDomainPrincipal(prin);
}

MOZ_ASSERT(keys.Length() >= 1,
"Every principal should have at least one key.");
return keys;
}
17 changes: 17 additions & 0 deletions extensions/cookie/nsPermissionManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,23 @@ class nsPermissionManager final : public nsIPermissionManager,
*/
static void GetKeyForPrincipal(nsIPrincipal* aPrincipal, nsACString& aPermissionKey);

/**
* See `nsIPermissionManager::GetPermissionsWithKey` for more info on
* permission keys.
*
* Get all permissions keys which could correspond to the given principal.
* This method, like GetKeyForPrincipal, is infallible and should always
* produce at least one key.
*
* Unlike GetKeyForPrincipal, this method also gets the keys for base domains
* of the given principal. All keys returned by this method must be avaliable
* in the content process for a given URL to successfully have its permissions
* checked in the `aExactHostMatch = false` situation.
*
* @param aPrincipal The Principal which the key is to be extracted from.
*/
static nsTArray<nsCString> GetAllKeysForPrincipal(nsIPrincipal* aPrincipal);

private:
virtual ~nsPermissionManager();

Expand Down

0 comments on commit 5eef733

Please sign in to comment.