зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1320201 - When an XHR is made with an expanded principal, use the expanded principal for CORS security checks; r=bzbarsky
We should only ensure that the resulting document doesn't end up inheriting the expanded principal.
This commit is contained in:
Родитель
2c794979ff
Коммит
d67534c9f0
|
@ -2500,27 +2500,6 @@ XMLHttpRequestMainThread::CreateChannel()
|
||||||
secFlags |= nsILoadInfo::SEC_COOKIES_OMIT;
|
secFlags |= nsILoadInfo::SEC_COOKIES_OMIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIExpandedPrincipal> ep = do_QueryInterface(mPrincipal);
|
|
||||||
if (ep) {
|
|
||||||
// If we have an expanded principal, instead of using that, select the
|
|
||||||
// principal in the whitelist which can load our URL, and use that instead.
|
|
||||||
nsTArray<nsCOMPtr<nsIPrincipal>>* whitelist = nullptr;
|
|
||||||
ep->GetWhiteList(&whitelist);
|
|
||||||
if (!whitelist) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
MOZ_ASSERT(!(secFlags & nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS));
|
|
||||||
bool dataInherits = (secFlags &
|
|
||||||
(nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS |
|
|
||||||
nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS)) != 0;
|
|
||||||
for (const auto& principal : *whitelist) {
|
|
||||||
if (NS_SUCCEEDED(principal->CheckMayLoad(mRequestURL, false, dataInherits))) {
|
|
||||||
mPrincipal = principal;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the responsibleDocument if we have it, except for dedicated workers
|
// Use the responsibleDocument if we have it, except for dedicated workers
|
||||||
// where it will be the parent document, which is not the one we want to use.
|
// where it will be the parent document, which is not the one we want to use.
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
|
@ -2559,6 +2538,35 @@ XMLHttpRequestMainThread::CreateChannel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Using the provided principal as the triggeringPrincipal is fine, since we
|
||||||
|
// want to be able to access any of the origins that the principal has access
|
||||||
|
// to during the security checks, but we don't want a document to inherit an
|
||||||
|
// expanded principal, so in that case we need to select the principal in the
|
||||||
|
// expanded principal's whitelist that can load our URL as principalToInherit.
|
||||||
|
nsCOMPtr<nsIPrincipal> resultingDocumentPrincipal(mPrincipal);
|
||||||
|
nsCOMPtr<nsIExpandedPrincipal> ep = do_QueryInterface(mPrincipal);
|
||||||
|
if (ep) {
|
||||||
|
nsTArray<nsCOMPtr<nsIPrincipal>>* whitelist = nullptr;
|
||||||
|
ep->GetWhiteList(&whitelist);
|
||||||
|
if (!whitelist) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
MOZ_ASSERT(!(secFlags & nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS));
|
||||||
|
bool dataInherits = (secFlags &
|
||||||
|
(nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS |
|
||||||
|
nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS)) != 0;
|
||||||
|
for (const auto& principal : *whitelist) {
|
||||||
|
if (NS_SUCCEEDED(principal->CheckMayLoad(mRequestURL, false, dataInherits))) {
|
||||||
|
resultingDocumentPrincipal = principal;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsILoadInfo> loadInfo = mChannel->GetLoadInfo();
|
||||||
|
rv = loadInfo->SetPrincipalToInherit(resultingDocumentPrincipal);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,16 @@ cu.import("resource://testing-common/httpd.js");
|
||||||
|
|
||||||
var httpserver = new HttpServer();
|
var httpserver = new HttpServer();
|
||||||
var httpserver2 = new HttpServer();
|
var httpserver2 = new HttpServer();
|
||||||
|
var httpserver3 = new HttpServer();
|
||||||
var testpath = "/simple";
|
var testpath = "/simple";
|
||||||
|
var redirectpath = "/redirect";
|
||||||
var negativetestpath = "/negative";
|
var negativetestpath = "/negative";
|
||||||
var httpbody = "<?xml version='1.0' ?><root>0123456789</root>";
|
var httpbody = "<?xml version='1.0' ?><root>0123456789</root>";
|
||||||
|
|
||||||
var sb = cu.Sandbox(["http://www.example.com",
|
var sb = cu.Sandbox(["http://www.example.com",
|
||||||
"http://localhost:4444/simple"],
|
"http://localhost:4444/redirect",
|
||||||
|
"http://localhost:4444/simple",
|
||||||
|
"http://localhost:4446/redirect"],
|
||||||
{ wantGlobalProperties: ["XMLHttpRequest"] });
|
{ wantGlobalProperties: ["XMLHttpRequest"] });
|
||||||
|
|
||||||
function createXHR(loc, async)
|
function createXHR(loc, async)
|
||||||
|
@ -35,7 +39,7 @@ function checkResults(xhr)
|
||||||
var httpServersClosed = 0;
|
var httpServersClosed = 0;
|
||||||
function finishIfDone()
|
function finishIfDone()
|
||||||
{
|
{
|
||||||
if (++httpServersClosed == 2)
|
if (++httpServersClosed == 3)
|
||||||
do_test_finished();
|
do_test_finished();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,11 +48,15 @@ function run_test()
|
||||||
do_test_pending();
|
do_test_pending();
|
||||||
|
|
||||||
httpserver.registerPathHandler(testpath, serverHandler);
|
httpserver.registerPathHandler(testpath, serverHandler);
|
||||||
|
httpserver.registerPathHandler(redirectpath, redirectHandler1);
|
||||||
httpserver.start(4444);
|
httpserver.start(4444);
|
||||||
|
|
||||||
httpserver2.registerPathHandler(negativetestpath, serverHandler);
|
httpserver2.registerPathHandler(negativetestpath, serverHandler);
|
||||||
httpserver2.start(4445);
|
httpserver2.start(4445);
|
||||||
|
|
||||||
|
httpserver3.registerPathHandler(redirectpath, redirectHandler2);
|
||||||
|
httpserver3.start(4446);
|
||||||
|
|
||||||
// Test sync XHR sending
|
// Test sync XHR sending
|
||||||
cu.evalInSandbox('var createXHR = ' + createXHR.toString(), sb);
|
cu.evalInSandbox('var createXHR = ' + createXHR.toString(), sb);
|
||||||
var res = cu.evalInSandbox('var sync = createXHR("4444/simple"); sync.send(null); sync', sb);
|
var res = cu.evalInSandbox('var sync = createXHR("4444/simple"); sync.send(null); sync', sb);
|
||||||
|
@ -68,7 +76,21 @@ function run_test()
|
||||||
do_check_true(true);
|
do_check_true(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test redirect handling.
|
||||||
|
// This request bounces to server 2 and then back to server 1. Neither of
|
||||||
|
// these servers support CORS, but if the expanded principal is used as the
|
||||||
|
// triggering principal, this should work.
|
||||||
|
cu.evalInSandbox('var createXHR = ' + createXHR.toString(), sb);
|
||||||
|
var res = cu.evalInSandbox('var sync = createXHR("4444/redirect"); sync.send(null); sync', sb);
|
||||||
|
do_check_true(checkResults(res));
|
||||||
|
|
||||||
|
var principal = res.responseXML.nodePrincipal;
|
||||||
|
do_check_true(principal.isCodebasePrincipal);
|
||||||
|
var requestURL = "http://localhost:4444/simple";
|
||||||
|
do_check_eq(principal.URI.spec, requestURL);
|
||||||
|
|
||||||
httpserver2.stop(finishIfDone);
|
httpserver2.stop(finishIfDone);
|
||||||
|
httpserver3.stop(finishIfDone);
|
||||||
|
|
||||||
// Test async XHR sending
|
// Test async XHR sending
|
||||||
sb.finish = function(){
|
sb.finish = function(){
|
||||||
|
@ -95,8 +117,20 @@ function run_test()
|
||||||
async.send(null);
|
async.send(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
function serverHandler(metadata, response)
|
function serverHandler(request, response)
|
||||||
{
|
{
|
||||||
response.setHeader("Content-Type", "text/xml", false);
|
response.setHeader("Content-Type", "text/xml", false);
|
||||||
response.bodyOutputStream.write(httpbody, httpbody.length);
|
response.bodyOutputStream.write(httpbody, httpbody.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function redirectHandler1(request, response)
|
||||||
|
{
|
||||||
|
response.setStatusLine(request.httpVersion, 302, "Found");
|
||||||
|
response.setHeader("Location", "http://localhost:4446/redirect", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function redirectHandler2(request, response)
|
||||||
|
{
|
||||||
|
response.setStatusLine(request.httpVersion, 302, "Found");
|
||||||
|
response.setHeader("Location", "http://localhost:4444/simple", false);
|
||||||
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче