зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1401350 fix proxy auth for system requests, r=kmag
MozReview-Commit-ID: CAh89djQobI --HG-- extra : rebase_source : c85ff5148d4ac1df4e21622d2d615040ba9e09d7
This commit is contained in:
Родитель
a1b0fe8ef7
Коммит
86d45aba67
|
@ -17,9 +17,17 @@ function WebRequestEventManager(context, eventName) {
|
||||||
let name = `webRequest.${eventName}`;
|
let name = `webRequest.${eventName}`;
|
||||||
let register = (fire, filter, info) => {
|
let register = (fire, filter, info) => {
|
||||||
let listener = data => {
|
let listener = data => {
|
||||||
|
// data.isProxy is only set from the WebRequest AuthRequestor handler,
|
||||||
|
// in which case we know that this is onAuthRequired. If this is proxy
|
||||||
|
// authorization, we allow without any additional matching/filtering.
|
||||||
|
let isProxyAuth = data.isProxy && context.extension.hasPermission("proxy");
|
||||||
|
|
||||||
// Prevent listening in on requests originating from system principal to
|
// Prevent listening in on requests originating from system principal to
|
||||||
// prevent tinkering with OCSP, app and addon updates, etc.
|
// prevent tinkering with OCSP, app and addon updates, etc. However,
|
||||||
if (data.isSystemPrincipal) {
|
// proxy addons need to be able to provide auth for any request so we
|
||||||
|
// allow those through. The exception is for proxy extensions handling
|
||||||
|
// proxy authentication.
|
||||||
|
if (data.isSystemPrincipal && !isProxyAuth) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +39,7 @@ function WebRequestEventManager(context, eventName) {
|
||||||
// and the origin that is loading the resource.
|
// and the origin that is loading the resource.
|
||||||
const origin = data.documentUrl;
|
const origin = data.documentUrl;
|
||||||
const own = origin && origin.startsWith(context.extension.getURL());
|
const own = origin && origin.startsWith(context.extension.getURL());
|
||||||
if (origin && !own && !hosts.matches(data.documentURI)) {
|
if (origin && !own && !isProxyAuth && !hosts.matches(data.documentURI)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
const XMLHttpRequest = Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1", "nsIXMLHttpRequest");
|
||||||
|
|
||||||
const proxy = createHttpServer();
|
const proxy = createHttpServer();
|
||||||
|
|
||||||
// accept proxy connections for mozilla.org
|
// accept proxy connections for mozilla.org
|
||||||
|
@ -8,14 +10,35 @@ proxy.identity.add("http", "mozilla.org", 80);
|
||||||
proxy.registerPathHandler("/", (request, response) => {
|
proxy.registerPathHandler("/", (request, response) => {
|
||||||
if (request.hasHeader("Proxy-Authorization")) {
|
if (request.hasHeader("Proxy-Authorization")) {
|
||||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||||
response.write("ok");
|
response.setHeader("Content-Type", "text/plain", false);
|
||||||
|
response.write("ok, got proxy auth");
|
||||||
} else {
|
} else {
|
||||||
response.setStatusLine(request.httpVersion, 407, "Proxy authentication required");
|
response.setStatusLine(request.httpVersion, 407, "Proxy authentication required");
|
||||||
|
response.setHeader("Content-Type", "text/plain", false);
|
||||||
response.setHeader("Proxy-Authenticate", 'Basic realm="foobar"', false);
|
response.setHeader("Proxy-Authenticate", 'Basic realm="foobar"', false);
|
||||||
response.write("ok");
|
response.write("auth required");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function getExtension(background) {
|
||||||
|
return ExtensionTestUtils.loadExtension({
|
||||||
|
manifest: {
|
||||||
|
permissions: [
|
||||||
|
"proxy",
|
||||||
|
"webRequest",
|
||||||
|
"webRequestBlocking",
|
||||||
|
"<all_urls>",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
background: `(${background})(${proxy.identity.primaryPort})`,
|
||||||
|
files: {
|
||||||
|
"proxy.js": `
|
||||||
|
function FindProxyForURL(url, host) {
|
||||||
|
return "PROXY localhost:${proxy.identity.primaryPort}; DIRECT";
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
add_task(async function test_webRequest_auth_proxy() {
|
add_task(async function test_webRequest_auth_proxy() {
|
||||||
async function background(port) {
|
async function background(port) {
|
||||||
browser.webRequest.onBeforeRequest.addListener(details => {
|
browser.webRequest.onBeforeRequest.addListener(details => {
|
||||||
|
@ -48,23 +71,7 @@ add_task(async function test_webRequest_auth_proxy() {
|
||||||
browser.test.sendMessage("pac-ready");
|
browser.test.sendMessage("pac-ready");
|
||||||
}
|
}
|
||||||
|
|
||||||
let handlingExt = ExtensionTestUtils.loadExtension({
|
let handlingExt = getExtension(background);
|
||||||
manifest: {
|
|
||||||
permissions: [
|
|
||||||
"proxy",
|
|
||||||
"webRequest",
|
|
||||||
"webRequestBlocking",
|
|
||||||
"<all_urls>",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
background: `(${background})(${proxy.identity.primaryPort})`,
|
|
||||||
files: {
|
|
||||||
"proxy.js": `
|
|
||||||
function FindProxyForURL(url, host) {
|
|
||||||
return "PROXY localhost:${proxy.identity.primaryPort}; DIRECT";
|
|
||||||
}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
await handlingExt.startup();
|
await handlingExt.startup();
|
||||||
await handlingExt.awaitMessage("pac-ready");
|
await handlingExt.awaitMessage("pac-ready");
|
||||||
|
@ -75,3 +82,47 @@ add_task(async function test_webRequest_auth_proxy() {
|
||||||
await contentPage.close();
|
await contentPage.close();
|
||||||
await handlingExt.unload();
|
await handlingExt.unload();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
add_task(async function test_webRequest_auth_proxy_system() {
|
||||||
|
async function background(port) {
|
||||||
|
browser.webRequest.onBeforeRequest.addListener(details => {
|
||||||
|
browser.test.fail("onBeforeRequest");
|
||||||
|
}, {urls: ["<all_urls>"]});
|
||||||
|
browser.webRequest.onAuthRequired.addListener(details => {
|
||||||
|
browser.test.sendMessage("onAuthRequired");
|
||||||
|
// cancel is silently ignored, if it were not (e.g someone messes up in
|
||||||
|
// WebRequest.jsm and allows cancel) this test would fail.
|
||||||
|
return {
|
||||||
|
cancel: true,
|
||||||
|
authCredentials: {username: "puser", password: "ppass"},
|
||||||
|
};
|
||||||
|
}, {urls: ["<all_urls>"]}, ["blocking"]);
|
||||||
|
|
||||||
|
await browser.proxy.register("proxy.js");
|
||||||
|
browser.test.sendMessage("pac-ready");
|
||||||
|
}
|
||||||
|
|
||||||
|
let handlingExt = getExtension(background);
|
||||||
|
|
||||||
|
await handlingExt.startup();
|
||||||
|
await handlingExt.awaitMessage("pac-ready");
|
||||||
|
|
||||||
|
function fetch(url) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let xhr = new XMLHttpRequest();
|
||||||
|
xhr.mozBackgroundRequest = true;
|
||||||
|
xhr.open("GET", url);
|
||||||
|
xhr.onload = () => { resolve(xhr.responseText); };
|
||||||
|
xhr.onerror = () => { reject(xhr.status); };
|
||||||
|
// use a different contextId to avoid auth cache.
|
||||||
|
xhr.setOriginAttributes({userContextId: 1});
|
||||||
|
xhr.send();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
handlingExt.awaitMessage("onAuthRequired"),
|
||||||
|
fetch("http://mozilla.org"),
|
||||||
|
]);
|
||||||
|
await handlingExt.unload();
|
||||||
|
});
|
||||||
|
|
|
@ -833,7 +833,9 @@ HttpObserverManager = {
|
||||||
try {
|
try {
|
||||||
let result = callback(data);
|
let result = callback(data);
|
||||||
|
|
||||||
if (channel.canModify && result && typeof result === "object" && opts.blocking) {
|
// isProxy is set during onAuth if the auth request is for a proxy.
|
||||||
|
// We allow handling proxy auth regardless of canModify.
|
||||||
|
if ((channel.canModify || data.isProxy) && typeof result === "object" && opts.blocking) {
|
||||||
handlerResults.push({opts, result});
|
handlerResults.push({opts, result});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -865,6 +867,16 @@ HttpObserverManager = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (kind === "authRequired" && result.authCredentials && channel.authPromptCallback) {
|
||||||
|
channel.authPromptCallback(result.authCredentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We allow proxy auth to cancel or handle authCredentials regardless of
|
||||||
|
// canModify, but ensure we do nothing else.
|
||||||
|
if (!channel.canModify) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (result.cancel) {
|
if (result.cancel) {
|
||||||
channel.suspended = false;
|
channel.suspended = false;
|
||||||
channel.cancel(Cr.NS_ERROR_ABORT);
|
channel.cancel(Cr.NS_ERROR_ABORT);
|
||||||
|
@ -890,11 +902,8 @@ HttpObserverManager = {
|
||||||
if (opts.responseHeaders && result.responseHeaders && responseHeaders) {
|
if (opts.responseHeaders && result.responseHeaders && responseHeaders) {
|
||||||
responseHeaders.applyChanges(result.responseHeaders);
|
responseHeaders.applyChanges(result.responseHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kind === "authRequired" && result.authCredentials && channel.authPromptCallback) {
|
|
||||||
channel.authPromptCallback(result.authCredentials);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a listener did not cancel the request or provide credentials, we
|
// If a listener did not cancel the request or provide credentials, we
|
||||||
// forward the auth request to the base handler.
|
// forward the auth request to the base handler.
|
||||||
if (kind === "authRequired" && channel.authPromptForward) {
|
if (kind === "authRequired" && channel.authPromptForward) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче