Bug 536509 - Update localStorage to use common StorageAllowedForWindow logic, r=ehsan

This commit is contained in:
Michael Layzell 2015-07-15 16:44:42 -04:00
parent 0f26211a90
commit 908625d7dc
7 changed files with 76 additions and 59 deletions

View File

@ -10937,7 +10937,7 @@ nsGlobalWindow::GetLocalStorage(ErrorResult& aError)
}
if (!mLocalStorage) {
if (!DOMStorage::CanUseStorage()) {
if (!DOMStorage::CanUseStorage(this)) {
aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;
}
@ -10955,13 +10955,6 @@ nsGlobalWindow::GetLocalStorage(ErrorResult& aError)
return nullptr;
}
// If the document has the sandboxed origin flag set
// don't allow access to localStorage.
if (mDoc && (mDoc->GetSandboxFlags() & SANDBOXED_ORIGIN)) {
aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;
}
nsString documentURI;
if (mDoc) {
mDoc->GetDocumentURI(documentURI);

View File

@ -13,13 +13,14 @@
#include "nsIPermissionManager.h"
#include "nsIPrincipal.h"
#include "nsICookiePermission.h"
#include "nsICookieService.h"
#include "nsPIDOMWindow.h"
#include "mozilla/dom/StorageBinding.h"
#include "mozilla/dom/StorageEvent.h"
#include "mozilla/dom/StorageEventBinding.h"
#include "mozilla/Services.h"
#include "mozilla/Preferences.h"
#include "mozilla/EnumSet.h"
#include "nsThreadUtils.h"
#include "nsContentUtils.h"
#include "nsServiceManagerUtils.h"
@ -70,7 +71,7 @@ DOMStorage::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
uint32_t
DOMStorage::GetLength(ErrorResult& aRv)
{
if (!CanUseStorage(this)) {
if (!CanUseStorage(nullptr, this)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return 0;
}
@ -83,7 +84,7 @@ DOMStorage::GetLength(ErrorResult& aRv)
void
DOMStorage::Key(uint32_t aIndex, nsAString& aResult, ErrorResult& aRv)
{
if (!CanUseStorage(this)) {
if (!CanUseStorage(nullptr, this)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
@ -94,7 +95,7 @@ DOMStorage::Key(uint32_t aIndex, nsAString& aResult, ErrorResult& aRv)
void
DOMStorage::GetItem(const nsAString& aKey, nsAString& aResult, ErrorResult& aRv)
{
if (!CanUseStorage(this)) {
if (!CanUseStorage(nullptr, this)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
@ -106,7 +107,7 @@ void
DOMStorage::SetItem(const nsAString& aKey, const nsAString& aData,
ErrorResult& aRv)
{
if (!CanUseStorage(this)) {
if (!CanUseStorage(nullptr, this)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
@ -139,7 +140,7 @@ DOMStorage::SetItem(const nsAString& aKey, const nsAString& aData,
void
DOMStorage::RemoveItem(const nsAString& aKey, ErrorResult& aRv)
{
if (!CanUseStorage(this)) {
if (!CanUseStorage(nullptr, this)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
@ -158,7 +159,7 @@ DOMStorage::RemoveItem(const nsAString& aKey, ErrorResult& aRv)
void
DOMStorage::Clear(ErrorResult& aRv)
{
if (!CanUseStorage(this)) {
if (!CanUseStorage(nullptr, this)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
@ -236,60 +237,32 @@ static const char kCookiesLifetimePolicy[] = "network.cookie.lifetimePolicy";
// static, public
bool
DOMStorage::CanUseStorage(DOMStorage* aStorage)
DOMStorage::CanUseStorage(nsPIDOMWindow* aWindow, DOMStorage* aStorage)
{
// This method is responsible for correct setting of mIsSessionOnly.
// It doesn't work with mIsPrivate flag at all, since it is checked
// regardless mIsSessionOnly flag in DOMStorageCache code.
if (aStorage) {
aStorage->mIsSessionOnly = false;
}
if (!mozilla::Preferences::GetBool(kStorageEnabled)) {
return false;
}
// chrome can always use aStorage regardless of permission preferences
nsCOMPtr<nsIPrincipal> subjectPrincipal =
nsContentUtils::SubjectPrincipal();
if (nsContentUtils::IsSystemPrincipal(subjectPrincipal)) {
return true;
nsContentUtils::StorageAccess access = nsContentUtils::StorageAccess::eDeny;
if (aWindow) {
access = nsContentUtils::StorageAllowedForWindow(aWindow);
} else if (aStorage) {
access = nsContentUtils::StorageAllowedForPrincipal(aStorage->mPrincipal);
}
nsCOMPtr<nsIPermissionManager> permissionManager =
services::GetPermissionManager();
if (!permissionManager) {
if (access == nsContentUtils::StorageAccess::eDeny) {
return false;
}
uint32_t perm;
permissionManager->TestPermissionFromPrincipal(subjectPrincipal,
kPermissionType, &perm);
if (perm == nsIPermissionManager::DENY_ACTION) {
return false;
}
if (perm == nsICookiePermission::ACCESS_SESSION) {
if (aStorage) {
aStorage->mIsSessionOnly = true;
}
} else if (perm != nsIPermissionManager::ALLOW_ACTION) {
uint32_t cookieBehavior = Preferences::GetUint(kCookiesBehavior);
uint32_t lifetimePolicy = Preferences::GetUint(kCookiesLifetimePolicy);
// Treat "ask every time" as "reject always".
if (cookieBehavior == nsICookieService::BEHAVIOR_REJECT ||
lifetimePolicy == nsICookieService::ASK_BEFORE_ACCEPT) {
return false;
}
if (lifetimePolicy == nsICookieService::ACCEPT_SESSION && aStorage) {
aStorage->mIsSessionOnly = true;
}
}
if (aStorage) {
aStorage->mIsSessionOnly = access <= nsContentUtils::StorageAccess::eSessionScoped;
nsCOMPtr<nsIPrincipal> subjectPrincipal =
nsContentUtils::SubjectPrincipal();
return aStorage->CanAccess(subjectPrincipal);
}
@ -327,7 +300,7 @@ DOMStorage::CanAccess(nsIPrincipal* aPrincipal)
void
DOMStorage::GetSupportedNames(unsigned, nsTArray<nsString>& aKeys)
{
if (!CanUseStorage(this)) {
if (!CanUseStorage(nullptr, this)) {
// return just an empty array
aKeys.Clear();
return;

View File

@ -18,6 +18,7 @@
class nsIPrincipal;
class nsIDOMWindow;
class nsPIDOMWindow;
namespace mozilla {
namespace dom {
@ -122,7 +123,7 @@ public:
// It is an optimization since the privileges check and session only
// state determination are complex and share the code (comes hand in
// hand together).
static bool CanUseStorage(DOMStorage* aStorage = nullptr);
static bool CanUseStorage(nsPIDOMWindow* aWindow, DOMStorage* aStorage = nullptr);
bool IsPrivate() const { return mIsPrivate; }
bool IsSessionOnly() const { return mIsSessionOnly; }

View File

@ -0,0 +1,20 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>localStorage cookies settings test</title>
<script type="text/javascript" src="interOriginFrame.js"></script>
</head>
<body>
<script type="text/javascript">
try {
localStorage.setItem("contentkey", "test-value");
ok(false, "Setting localStorageItem should throw a security exception");
} catch(ex) {
is(ex.name, "SecurityError");
}
finishTest();
</script>
</body>
</html>

View File

@ -49,7 +49,9 @@ function todo(a, b, message)
function finishTest()
{
localStorage.clear();
try {
localStorage.clear();
} catch (e) {}
postMsg("done");
return false;
}

View File

@ -2,6 +2,7 @@
support-files =
frameAppIsolation.html
frameChromeSlave.html
frameLocalStorageCookieSettings.html
frameKeySync.html
frameMasterEqual.html
frameMasterNotEqual.html

View File

@ -3,8 +3,13 @@
<title>localStorage cookies settings test</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="interOriginTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<iframe></iframe>
<script type="text/javascript">
SimpleTest.waitForExplicitFinish();
@ -37,11 +42,33 @@ function test2() {
is(ex.name, "SecurityError");
}
// Set cookies behavior to "reject 3rd party"
SpecialPowers.pushPrefEnv({"set": [["network.cookie.cookieBehavior", 1]],
"clear": [["network.cookie.lifetimePolicy"]]},
test3);
}
function test3() {
try {
localStorage.setItem("contentkey", "test-value");
ok(true, "Setting localStorageItem should not throw a security exception");
}
catch(ex) {
ok(false, "Setting localStorageItem should not throw a security exception");
}
var fileTest = (location.protocol + "//example.com" + location.pathname)
.replace("test_l", "frameL");
var myframe = document.querySelector("iframe");
myframe.src = fileTest;
}
// Called by interOriginTest.js
function doNextTest() {
SimpleTest.finish();
}
</script>
</head>
<body>
</body>
</html>