diff options
Diffstat (limited to 'toolkit/components/extensions/test/mochitest/test_ext_webrequest_auth.html')
-rw-r--r-- | toolkit/components/extensions/test/mochitest/test_ext_webrequest_auth.html | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/toolkit/components/extensions/test/mochitest/test_ext_webrequest_auth.html b/toolkit/components/extensions/test/mochitest/test_ext_webrequest_auth.html new file mode 100644 index 0000000000..f260f040a1 --- /dev/null +++ b/toolkit/components/extensions/test/mochitest/test_ext_webrequest_auth.html @@ -0,0 +1,181 @@ +<!DOCTYPE HTML> + +<html> +<head> +<meta charset="utf-8"> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/ExtensionTestUtils.js"></script> + <script type="text/javascript" src="head_webrequest.js"></script> + <script type="text/javascript" src="head.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +<script> +"use strict"; + +// This file defines content scripts. + +let baseUrl = "http://mochi.test:8888/tests/toolkit/components/passwordmgr/test/mochitest/authenticate.sjs"; +function testXHR(url) { + return new Promise((resolve, reject) => { + let xhr = new XMLHttpRequest(); + xhr.open("GET", url); + xhr.onload = resolve; + xhr.onabort = reject; + xhr.onerror = reject; + xhr.send(); + }); +} + +function getAuthHandler(result, blocking = true) { + function background(result) { + browser.webRequest.onAuthRequired.addListener((details) => { + browser.test.succeed(`authHandler.onAuthRequired called with ${details.requestId} ${details.url} result ${JSON.stringify(result)}`); + browser.test.sendMessage("onAuthRequired"); + return result; + }, {urls: ["*://mochi.test/*"]}, ["blocking"]); + browser.webRequest.onCompleted.addListener((details) => { + browser.test.succeed(`authHandler.onCompleted called with ${details.requestId} ${details.url}`); + browser.test.sendMessage("onCompleted"); + }, {urls: ["*://mochi.test/*"]}); + browser.webRequest.onErrorOccurred.addListener((details) => { + browser.test.succeed(`authHandler.onErrorOccurred called with ${details.requestId} ${details.url}`); + browser.test.sendMessage("onErrorOccurred"); + }, {urls: ["*://mochi.test/*"]}); + } + + let permissions = [ + "webRequest", + "*://mochi.test/*", + ]; + if (blocking) { + permissions.push("webRequestBlocking"); + } + return ExtensionTestUtils.loadExtension({ + manifest: { + permissions, + }, + background: `(${background})(${JSON.stringify(result)})`, + }); +} + +add_task(async function test_webRequest_auth_nonblocking_forwardAuthProvider() { + // The chrome script sets up a default auth handler on the channel, the + // extension does not return anything in the authRequred call. We should + // get the call in the extension first, then in the chrome code where we + // cancel the request to avoid dealing with the prompt dialog here. The test + // is to ensure that WebRequest calls the previous notificationCallbacks + // if the authorization is not handled by the onAuthRequired handler. + + let chromeScript = SpecialPowers.loadChromeScript(() => { + /* eslint-env mozilla/chrome-script */ + let observer = channel => { + if (!(channel instanceof Ci.nsIHttpChannel && channel.URI.host === "mochi.test" && + channel.URI.spec.includes("authenticate.sjs"))) { + return; + } + Services.obs.removeObserver(observer, "http-on-modify-request"); + channel.notificationCallbacks = { + QueryInterface: ChromeUtils.generateQI(["nsIInterfaceRequestor", + "nsIAuthPromptProvider", + "nsIAuthPrompt2"]), + getInterface: ChromeUtils.generateQI(["nsIAuthPromptProvider", + "nsIAuthPrompt2"]), + promptAuth(channel, level, authInfo) { + throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE); + }, + getAuthPrompt(reason, iid) { + return this; + }, + asyncPromptAuth(channel, callback, context, level, authInfo) { + // We just cancel here, we're only ensuring that non-webrequest + // notificationcallbacks get called if webrequest doesn't handle it. + Promise.resolve().then(() => { + callback.onAuthCancelled(context, false); + channel.cancel(Cr.NS_BINDING_ABORTED); + sendAsyncMessage("callback-complete"); + }); + }, + }; + }; + Services.obs.addObserver(observer, "http-on-modify-request"); + sendAsyncMessage("chrome-ready"); + }); + await chromeScript.promiseOneMessage("chrome-ready"); + let callbackComplete = chromeScript.promiseOneMessage("callback-complete"); + + let handlingExt = getAuthHandler(); + await handlingExt.startup(); + + await Assert.rejects(testXHR(`${baseUrl}?realm=auth_nonblocking_forwardAuth&user=auth_nonblocking_forwardAuth&pass=auth_nonblocking_forwardAuth`), + ProgressEvent, + "caught rejected xhr"); + + await callbackComplete; + await handlingExt.awaitMessage("onAuthRequired"); + // We expect onErrorOccurred because the "default" authprompt above cancelled + // the auth request to avoid a dialog. + await handlingExt.awaitMessage("onErrorOccurred"); + await handlingExt.unload(); + chromeScript.destroy(); +}); + +add_task(async function test_webRequest_auth_nonblocking_forwardAuthPrompt2() { + // The chrome script sets up a default auth handler on the channel, the + // extension does not return anything in the authRequred call. We should + // get the call in the extension first, then in the chrome code where we + // cancel the request to avoid dealing with the prompt dialog here. The test + // is to ensure that WebRequest calls the previous notificationCallbacks + // if the authorization is not handled by the onAuthRequired handler. + + let chromeScript = SpecialPowers.loadChromeScript(() => { + /* eslint-env mozilla/chrome-script */ + let observer = channel => { + if (!(channel instanceof Ci.nsIHttpChannel && channel.URI.host === "mochi.test" && + channel.URI.spec.includes("authenticate.sjs"))) { + return; + } + Services.obs.removeObserver(observer, "http-on-modify-request"); + channel.notificationCallbacks = { + QueryInterface: ChromeUtils.generateQI(["nsIInterfaceRequestor", + "nsIAuthPrompt2"]), + getInterface: ChromeUtils.generateQI(["nsIAuthPrompt2"]), + promptAuth(request, level, authInfo) { + throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE); + }, + asyncPromptAuth(request, callback, context, level, authInfo) { + // We just cancel here, we're only ensuring that non-webrequest + // notificationcallbacks get called if webrequest doesn't handle it. + Promise.resolve().then(() => { + request.cancel(Cr.NS_BINDING_ABORTED); + sendAsyncMessage("callback-complete"); + }); + }, + }; + }; + Services.obs.addObserver(observer, "http-on-modify-request"); + sendAsyncMessage("chrome-ready"); + }); + await chromeScript.promiseOneMessage("chrome-ready"); + let callbackComplete = chromeScript.promiseOneMessage("callback-complete"); + + let handlingExt = getAuthHandler(); + await handlingExt.startup(); + + await Assert.rejects(testXHR(`${baseUrl}?realm=auth_nonblocking_forwardAuthPromptProvider&user=auth_nonblocking_forwardAuth&pass=auth_nonblocking_forwardAuth`), + ProgressEvent, + "caught rejected xhr"); + + await callbackComplete; + await handlingExt.awaitMessage("onAuthRequired"); + // We expect onErrorOccurred because the "default" authprompt above cancelled + // the auth request to avoid a dialog. + await handlingExt.awaitMessage("onErrorOccurred"); + await handlingExt.unload(); + chromeScript.destroy(); +}); +</script> +</head> +<body> +<div id="test">Authorization Test</div> + +</body> +</html> |