Bug 1631444 - Cookies should follow the CookieJarSettings, r=dimi

Differential Revision: https://phabricator.services.mozilla.com/D71594
This commit is contained in:
Andrea Marchesini
2020-04-21 08:53:33 +00:00
parent c0c0334b10
commit dcae496bc9
9 changed files with 106 additions and 184 deletions

View File

@@ -6,7 +6,10 @@
#include "Cookie.h"
#include "CookieCommons.h"
#include "mozilla/ContentBlockingNotifier.h"
#include "nsICookiePermission.h"
#include "nsICookieService.h"
#include "nsIEffectiveTLDService.h"
#include "nsScriptSecurityManager.h"
namespace mozilla {
namespace net {
@@ -179,5 +182,80 @@ bool CookieCommons::CheckHttpValue(const CookieStruct& aCookieData) {
return aCookieData.value().FindCharInSet(illegalCharacters, 0) == -1;
}
// static
bool CookieCommons::CheckCookiePermission(nsIChannel* aChannel,
CookieStruct& aCookieData) {
if (!aChannel) {
// No channel, let's assume this is a system-principal request.
return true;
}
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
nsresult rv =
loadInfo->GetCookieJarSettings(getter_AddRefs(cookieJarSettings));
if (NS_WARN_IF(NS_FAILED(rv))) {
return true;
}
nsIScriptSecurityManager* ssm =
nsScriptSecurityManager::GetScriptSecurityManager();
MOZ_ASSERT(ssm);
nsCOMPtr<nsIPrincipal> channelPrincipal;
rv = ssm->GetChannelURIPrincipal(aChannel, getter_AddRefs(channelPrincipal));
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
if (!channelPrincipal->GetIsContentPrincipal()) {
return true;
}
uint32_t cookiePermission = nsICookiePermission::ACCESS_DEFAULT;
rv = cookieJarSettings->CookiePermission(channelPrincipal, &cookiePermission);
if (NS_WARN_IF(NS_FAILED(rv))) {
return true;
}
if (cookiePermission == nsICookiePermission::ACCESS_ALLOW) {
return true;
}
if (cookiePermission == nsICookiePermission::ACCESS_SESSION) {
aCookieData.isSession() = true;
return true;
}
if (cookiePermission == nsICookiePermission::ACCESS_DENY) {
return false;
}
// Here we can have any legacy permission value.
// now we need to figure out what type of accept policy we're dealing with
// if we accept cookies normally, just bail and return
if (StaticPrefs::network_cookie_lifetimePolicy() ==
nsICookieService::ACCEPT_NORMALLY) {
return true;
}
// declare this here since it'll be used in all of the remaining cases
int64_t currentTime = PR_Now() / PR_USEC_PER_SEC;
int64_t delta = aCookieData.expiry() - currentTime;
// We are accepting the cookie, but,
// if it's not a session cookie, we may have to limit its lifetime.
if (!aCookieData.isSession() && delta > 0) {
if (StaticPrefs::network_cookie_lifetimePolicy() ==
nsICookieService::ACCEPT_SESSION) {
// limit lifetime to session
aCookieData.isSession() = true;
}
}
return true;
}
} // namespace net
} // namespace mozilla

View File

@@ -64,6 +64,9 @@ class CookieCommons final {
static bool CheckName(const CookieStruct& aCookieData);
static bool CheckHttpValue(const CookieStruct& aCookieData);
static bool CheckCookiePermission(nsIChannel* aChannel,
CookieStruct& aCookieData);
};
} // namespace net

View File

@@ -5,23 +5,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/net/CookiePermission.h"
#include "Cookie.h"
#include "mozilla/StaticPrefs_network.h"
#include "nsICookie.h"
#include "nsICookieService.h"
#include "nsNetUtil.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIURI.h"
#include "nsIChannel.h"
#include "nsString.h"
#include "nsCRT.h"
#include "nsIScriptObjectPrincipal.h"
#include "nsNetCID.h"
#include "prtime.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/ClearOnShutdown.h"
#include "nsContentUtils.h"
/****************************************************************
************************ CookiePermission **********************
@@ -30,8 +15,6 @@
namespace mozilla {
namespace net {
static const bool kDefaultPolicy = true;
namespace {
StaticRefPtr<CookiePermission> gSingleton;
} // namespace
@@ -47,73 +30,7 @@ already_AddRefed<nsICookiePermission> CookiePermission::GetOrCreate() {
return do_AddRef(gSingleton);
}
bool CookiePermission::Init() {
// Initialize PermissionManager and fetch relevant prefs. This is only
// required for some methods on nsICookiePermission, so it should be done
// lazily.
mPermMgr = PermissionManager::GetInstance();
return mPermMgr != nullptr;
}
NS_IMETHODIMP
CookiePermission::CanSetCookie(nsIURI* aURI, nsIChannel* /*aChannel*/,
nsICookie* aCookie, bool* aIsSession,
int64_t* aExpiry, bool* aResult) {
NS_ASSERTION(aURI, "null uri");
*aResult = kDefaultPolicy;
// Lazily initialize ourselves
if (!EnsureInitialized()) {
return NS_ERROR_UNEXPECTED;
}
auto* cookie = static_cast<Cookie*>(aCookie);
uint32_t perm;
mPermMgr->LegacyTestPermissionFromURI(aURI, &cookie->OriginAttributesRef(),
NS_LITERAL_CSTRING("cookie"), &perm);
switch (perm) {
case nsICookiePermission::ACCESS_SESSION:
*aIsSession = true;
[[fallthrough]];
case nsICookiePermission::ACCESS_ALLOW:
*aResult = true;
break;
case nsICookiePermission::ACCESS_DENY:
*aResult = false;
break;
default:
// Here we can have any legacy permission value.
// now we need to figure out what type of accept policy we're dealing with
// if we accept cookies normally, just bail and return
if (StaticPrefs::network_cookie_lifetimePolicy() ==
nsICookieService::ACCEPT_NORMALLY) {
*aResult = true;
return NS_OK;
}
// declare this here since it'll be used in all of the remaining cases
int64_t currentTime = PR_Now() / PR_USEC_PER_SEC;
int64_t delta = *aExpiry - currentTime;
// We are accepting the cookie, but,
// if it's not a session cookie, we may have to limit its lifetime.
if (!*aIsSession && delta > 0) {
if (StaticPrefs::network_cookie_lifetimePolicy() ==
nsICookieService::ACCEPT_SESSION) {
// limit lifetime to session
*aIsSession = true;
}
}
}
return NS_OK;
}
bool CookiePermission::Init() { return true; }
} // namespace net
} // namespace mozilla

View File

@@ -6,7 +6,6 @@
#define mozilla_net_CookiePermission_h
#include "nsICookiePermission.h"
#include "mozilla/PermissionManager.h"
namespace mozilla {
namespace net {
@@ -23,10 +22,6 @@ class CookiePermission final : public nsICookiePermission {
private:
~CookiePermission() = default;
bool EnsureInitialized() { return (mPermMgr != nullptr) || Init(); };
RefPtr<mozilla::PermissionManager> mPermMgr;
};
} // namespace net

View File

@@ -177,8 +177,6 @@ nsresult CookieService::Init() {
os->AddObserver(this, "profile-do-change", true);
os->AddObserver(this, "last-pb-context-exited", true);
mPermissionService = CookiePermission::GetOrCreate();
return NS_OK;
}
@@ -1065,27 +1063,8 @@ bool CookieService::SetCookieInternal(CookieStorage* aStorage, nsIURI* aHostURI,
return newCookie;
}
int64_t currentTimeInUsec = PR_Now();
// create a new Cookie and copy attributes
RefPtr<Cookie> cookie = Cookie::Create(
cookieData.name(), cookieData.value(), cookieData.host(),
cookieData.path(), cookieData.expiry(), currentTimeInUsec,
Cookie::GenerateUniqueCreationTime(currentTimeInUsec),
cookieData.isSession(), cookieData.isSecure(), cookieData.isHttpOnly(),
aOriginAttributes, cookieData.sameSite(), cookieData.rawSameSite());
if (!cookie) {
return newCookie;
}
// check permissions from site permission list, or ask the user,
// to determine if we can set the cookie
if (mPermissionService) {
bool permission;
mPermissionService->CanSetCookie(
aHostURI, aChannel,
static_cast<nsICookie*>(static_cast<Cookie*>(cookie)),
&cookieData.isSession(), &cookieData.expiry(), &permission);
if (!permission) {
// check permissions from site permission list.
if (!CookieCommons::CheckCookiePermission(aChannel, cookieData)) {
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader,
"cookie rejected by permission manager");
CookieCommons::NotifyRejected(
@@ -1095,10 +1074,15 @@ bool CookieService::SetCookieInternal(CookieStorage* aStorage, nsIURI* aHostURI,
return newCookie;
}
// update isSession and expiry attributes, in case they changed
cookie->SetIsSession(cookieData.isSession());
cookie->SetExpiry(cookieData.expiry());
}
int64_t currentTimeInUsec = PR_Now();
// create a new Cookie and copy attributes
RefPtr<Cookie> cookie = Cookie::Create(
cookieData.name(), cookieData.value(), cookieData.host(),
cookieData.path(), cookieData.expiry(), currentTimeInUsec,
Cookie::GenerateUniqueCreationTime(currentTimeInUsec),
cookieData.isSession(), cookieData.isSecure(), cookieData.isHttpOnly(),
aOriginAttributes, cookieData.sameSite(), cookieData.rawSameSite());
MOZ_ASSERT(cookie);
// add the cookie to the list. AddCookie() takes care of logging.
// we get the current time again here, since it may have changed during

View File

@@ -8,7 +8,6 @@
#include "nsICookieService.h"
#include "nsICookieManager.h"
#include "nsICookiePermission.h"
#include "nsIObserver.h"
#include "nsWeakReference.h"
@@ -185,7 +184,6 @@ class CookieService final : public nsICookieService,
const nsTArray<nsString>& aParams);
// cached members.
nsCOMPtr<nsICookiePermission> mPermissionService;
nsCOMPtr<mozIThirdPartyUtil> mThirdPartyUtil;
nsCOMPtr<nsIEffectiveTLDService> mTLDService;
nsCOMPtr<nsIIDNService> mIDNService;

View File

@@ -79,8 +79,6 @@ CookieServiceChild::CookieServiceChild() {
mTLDService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
NS_ASSERTION(mTLDService, "couldn't get TLDService");
mPermissionService = CookiePermission::GetOrCreate();
// Init our prefs and observer.
nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
NS_WARNING_ASSERTION(prefBranch, "no prefservice");
@@ -413,21 +411,8 @@ nsresult CookieServiceChild::SetCookieStringInternal(
continue;
}
RefPtr<Cookie> cookie = Cookie::Create(
cookieData.name(), cookieData.value(), cookieData.host(),
cookieData.path(), cookieData.expiry(), currentTimeInUsec,
Cookie::GenerateUniqueCreationTime(currentTimeInUsec),
cookieData.isSession(), cookieData.isSecure(), cookieData.isHttpOnly(),
attrs, cookieData.sameSite(), cookieData.rawSameSite());
// check permissions from site permission list, or ask the user,
// to determine if we can set the cookie
if (mPermissionService) {
bool permission;
mPermissionService->CanSetCookie(aHostURI, aChannel, cookie,
&cookieData.isSession(),
&cookieData.expiry(), &permission);
if (!permission) {
// check permissions from site permission list.
if (!CookieCommons::CheckCookiePermission(aChannel, cookieData)) {
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieString,
"cookie rejected by permission manager");
CookieCommons::NotifyRejected(
@@ -437,10 +422,13 @@ nsresult CookieServiceChild::SetCookieStringInternal(
continue;
}
// update isSession and expiry attributes, in case they changed
cookie->SetIsSession(cookieData.isSession());
cookie->SetExpiry(cookieData.expiry());
}
RefPtr<Cookie> cookie = Cookie::Create(
cookieData.name(), cookieData.value(), cookieData.host(),
cookieData.path(), cookieData.expiry(), currentTimeInUsec,
Cookie::GenerateUniqueCreationTime(currentTimeInUsec),
cookieData.isSession(), cookieData.isSecure(), cookieData.isHttpOnly(),
attrs, cookieData.sameSite(), cookieData.rawSameSite());
MOZ_ASSERT(cookie);
RecordDocumentCookie(cookie, attrs);
cookiesToSend.AppendElement(cookieData);

View File

@@ -16,7 +16,6 @@
#include "nsWeakReference.h"
#include "nsThreadUtils.h"
class nsICookiePermission;
class nsIEffectiveTLDService;
class nsILoadInfo;
@@ -82,7 +81,6 @@ class CookieServiceChild final : public PCookieServiceChild,
CookiesMap mCookiesMap;
nsCOMPtr<nsITimer> mCookieTimer;
nsCOMPtr<nsICookiePermission> mPermissionService;
nsCOMPtr<mozIThirdPartyUtil> mThirdPartyUtil;
nsCOMPtr<nsIEffectiveTLDService> mTLDService;
};

View File

@@ -4,11 +4,6 @@
#include "nsISupports.idl"
interface nsICookie;
interface nsIURI;
interface nsIChannel;
interface nsIPrincipal;
typedef long nsCookieAccess;
/**
@@ -37,38 +32,4 @@ interface nsICookiePermission : nsISupports
* and ACCESS_LIMIT_THIRD_PARTY, now removed, but maybe still stored in some
* ancient user profiles.
*/
/**
* canSetCookie
*
* this method is called to test whether or not the given URI/channel may
* set a specific cookie. this method is always preceded by a call to
* canAccess. it may modify the isSession and expiry attributes of the
* cookie via the aIsSession and aExpiry parameters, in order to limit
* or extend the lifetime of the cookie. this is useful, for instance, to
* downgrade a cookie to session-only if it fails to meet certain criteria.
*
* @param aURI
* the URI trying to set the cookie
* @param aChannel
* the channel corresponding to aURI
* @param aCookie
* the cookie being added to the cookie database
* @param aIsSession
* when canSetCookie is invoked, this is the current isSession attribute
* of the cookie. canSetCookie may leave this value unchanged to
* preserve this attribute of the cookie.
* @param aExpiry
* when canSetCookie is invoked, this is the current expiry time of
* the cookie. canSetCookie may leave this value unchanged to
* preserve this attribute of the cookie.
*
* @return true if the cookie can be set.
*/
boolean canSetCookie(in nsIURI aURI,
in nsIChannel aChannel,
in nsICookie aCookie,
inout boolean aIsSession,
inout int64_t aExpiry);
};