summaryrefslogtreecommitdiffstats
path: root/toolkit/components/extensions/test/xpcshell/test_ext_webRequest_auth.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/extensions/test/xpcshell/test_ext_webRequest_auth.js')
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_webRequest_auth.js425
1 files changed, 425 insertions, 0 deletions
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_webRequest_auth.js b/toolkit/components/extensions/test/xpcshell/test_ext_webRequest_auth.js
new file mode 100644
index 0000000000..c616d162a5
--- /dev/null
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_webRequest_auth.js
@@ -0,0 +1,425 @@
+"use strict";
+
+const HOSTS = new Set(["example.com"]);
+
+const server = createHttpServer({ hosts: HOSTS });
+
+const BASE_URL = "http://example.com";
+
+// Save seen realms for cache checking.
+let realms = new Set([]);
+
+server.registerPathHandler("/authenticate.sjs", (request, response) => {
+ let url = new URL(`${BASE_URL}${request.path}?${request.queryString}`);
+ let realm = url.searchParams.get("realm") || "mochitest";
+ let proxy_realm = url.searchParams.get("proxy_realm");
+
+ function checkAuthorization(authorization) {
+ let expected_user = url.searchParams.get("user");
+ if (!expected_user) {
+ return true;
+ }
+ let expected_pass = url.searchParams.get("pass");
+ let actual_user, actual_pass;
+ let authHeader = request.getHeader("Authorization");
+ let match = /Basic (.+)/.exec(authHeader);
+ if (match.length != 2) {
+ throw new Error("Couldn't parse auth header: " + authHeader);
+ }
+ let userpass = atob(match[1]); // no atob() :-(
+ match = /(.*):(.*)/.exec(userpass);
+ if (match.length != 3) {
+ throw new Error("Couldn't decode auth header: " + userpass);
+ }
+ actual_user = match[1];
+ actual_pass = match[2];
+ return expected_user === actual_user && expected_pass === actual_pass;
+ }
+
+ response.setHeader("Content-Type", "text/plain; charset=UTF-8", false);
+ if (proxy_realm && !request.hasHeader("Proxy-Authorization")) {
+ // We're not testing anything that requires checking the proxy auth user/password.
+ response.setStatusLine("1.0", 407, "Proxy authentication required");
+ response.setHeader(
+ "Proxy-Authenticate",
+ `basic realm="${proxy_realm}"`,
+ true
+ );
+ response.write("proxy auth required");
+ } else if (
+ !(
+ realms.has(realm) &&
+ request.hasHeader("Authorization") &&
+ checkAuthorization()
+ )
+ ) {
+ realms.add(realm);
+ response.setStatusLine(request.httpVersion, 401, "Authentication required");
+ response.setHeader("WWW-Authenticate", `basic realm="${realm}"`, true);
+ response.write("auth required");
+ } else {
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.write("ok, got authorization");
+ }
+});
+
+function getExtension(bgConfig) {
+ function background(config) {
+ let path = config.path;
+ browser.webRequest.onBeforeRequest.addListener(
+ details => {
+ browser.test.log(
+ `onBeforeRequest called with ${details.requestId} ${details.url}`
+ );
+ browser.test.sendMessage("onBeforeRequest");
+ return (
+ config.onBeforeRequest.hasOwnProperty("result") &&
+ config.onBeforeRequest.result
+ );
+ },
+ { urls: [path] },
+ config.onBeforeRequest.hasOwnProperty("extra")
+ ? config.onBeforeRequest.extra
+ : []
+ );
+ browser.webRequest.onAuthRequired.addListener(
+ details => {
+ browser.test.log(
+ `onAuthRequired called with ${details.requestId} ${details.url}`
+ );
+ browser.test.assertEq(
+ config.realm,
+ details.realm,
+ "providing www authorization"
+ );
+ browser.test.sendMessage("onAuthRequired");
+ return (
+ config.onAuthRequired.hasOwnProperty("result") &&
+ config.onAuthRequired.result
+ );
+ },
+ { urls: [path] },
+ config.onAuthRequired.hasOwnProperty("extra")
+ ? config.onAuthRequired.extra
+ : []
+ );
+ browser.webRequest.onCompleted.addListener(
+ details => {
+ browser.test.log(
+ `onCompleted called with ${details.requestId} ${details.url}`
+ );
+ browser.test.sendMessage("onCompleted");
+ },
+ { urls: [path] }
+ );
+ browser.webRequest.onErrorOccurred.addListener(
+ details => {
+ browser.test.log(
+ `onErrorOccurred called with ${JSON.stringify(details)}`
+ );
+ browser.test.sendMessage("onErrorOccurred");
+ },
+ { urls: [path] }
+ );
+ }
+
+ return ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["webRequest", "webRequestBlocking", bgConfig.path],
+ },
+ background: `(${background})(${JSON.stringify(bgConfig)})`,
+ });
+}
+
+add_task(async function test_webRequest_auth() {
+ let config = {
+ path: `${BASE_URL}/*`,
+ realm: `webRequest_auth${Math.random()}`,
+ onBeforeRequest: {
+ extra: ["blocking"],
+ },
+ onAuthRequired: {
+ extra: ["blocking"],
+ result: {
+ authCredentials: {
+ username: "testuser",
+ password: "testpass",
+ },
+ },
+ },
+ };
+
+ let extension = getExtension(config);
+ await extension.startup();
+
+ let requestUrl = `${BASE_URL}/authenticate.sjs?realm=${config.realm}`;
+ let contentPage = await ExtensionTestUtils.loadContentPage(requestUrl);
+ await Promise.all([
+ extension.awaitMessage("onBeforeRequest"),
+ extension.awaitMessage("onAuthRequired").then(() => {
+ return Promise.all([
+ extension.awaitMessage("onBeforeRequest"),
+ extension.awaitMessage("onCompleted"),
+ ]);
+ }),
+ ]);
+ await contentPage.close();
+
+ // Second time around to test cached credentials
+ contentPage = await ExtensionTestUtils.loadContentPage(requestUrl);
+ await Promise.all([
+ extension.awaitMessage("onBeforeRequest"),
+ extension.awaitMessage("onCompleted"),
+ ]);
+
+ await contentPage.close();
+ await extension.unload();
+});
+
+add_task(async function test_webRequest_auth_cancelled() {
+ // Test that any auth listener can cancel.
+ let config = {
+ path: `${BASE_URL}/*`,
+ realm: `webRequest_auth${Math.random()}`,
+ onBeforeRequest: {
+ extra: ["blocking"],
+ },
+ onAuthRequired: {
+ extra: ["blocking"],
+ result: {
+ authCredentials: {
+ username: "testuser",
+ password: "testpass",
+ },
+ },
+ },
+ };
+
+ let ex1 = getExtension(config);
+ config.onAuthRequired.result = { cancel: true };
+ let ex2 = getExtension(config);
+ await ex1.startup();
+ await ex2.startup();
+
+ let requestUrl = `${BASE_URL}/authenticate.sjs?realm=${config.realm}`;
+ let contentPage = await ExtensionTestUtils.loadContentPage(requestUrl);
+ await Promise.all([
+ ex1.awaitMessage("onBeforeRequest"),
+ ex1.awaitMessage("onAuthRequired"),
+ ex1.awaitMessage("onErrorOccurred"),
+ ex2.awaitMessage("onBeforeRequest"),
+ ex2.awaitMessage("onAuthRequired"),
+ ex2.awaitMessage("onErrorOccurred"),
+ ]);
+
+ await contentPage.close();
+ await ex1.unload();
+ await ex2.unload();
+});
+
+add_task(async function test_webRequest_auth_nonblocking() {
+ let config = {
+ path: `${BASE_URL}/*`,
+ realm: `webRequest_auth${Math.random()}`,
+ onBeforeRequest: {
+ extra: ["blocking"],
+ },
+ onAuthRequired: {
+ extra: ["blocking"],
+ result: {
+ authCredentials: {
+ username: "testuser",
+ password: "testpass",
+ },
+ },
+ },
+ };
+
+ let ex1 = getExtension(config);
+ // non-blocking ext tries to cancel but cannot.
+ delete config.onBeforeRequest.extra;
+ delete config.onAuthRequired.extra;
+ config.onAuthRequired.result = { cancel: true };
+ let ex2 = getExtension(config);
+ await ex1.startup();
+ await ex2.startup();
+
+ let requestUrl = `${BASE_URL}/authenticate.sjs?realm=${config.realm}`;
+ let contentPage = await ExtensionTestUtils.loadContentPage(requestUrl);
+ await Promise.all([
+ ex1.awaitMessage("onBeforeRequest"),
+ ex1.awaitMessage("onAuthRequired").then(() => {
+ return Promise.all([
+ ex1.awaitMessage("onBeforeRequest"),
+ ex1.awaitMessage("onCompleted"),
+ ]);
+ }),
+ ex2.awaitMessage("onBeforeRequest"),
+ ex2.awaitMessage("onAuthRequired").then(() => {
+ return Promise.all([
+ ex2.awaitMessage("onBeforeRequest"),
+ ex2.awaitMessage("onCompleted"),
+ ]);
+ }),
+ ]);
+
+ await contentPage.close();
+ Services.obs.notifyObservers(null, "net:clear-active-logins");
+ await ex1.unload();
+ await ex2.unload();
+});
+
+add_task(async function test_webRequest_auth_blocking_noreturn() {
+ // The first listener is blocking but doesn't return anything. The second
+ // listener cancels the request.
+ let config = {
+ path: `${BASE_URL}/*`,
+ realm: `webRequest_auth${Math.random()}`,
+ onBeforeRequest: {
+ extra: ["blocking"],
+ },
+ onAuthRequired: {
+ extra: ["blocking"],
+ },
+ };
+
+ let ex1 = getExtension(config);
+ config.onAuthRequired.result = { cancel: true };
+ let ex2 = getExtension(config);
+ await ex1.startup();
+ await ex2.startup();
+
+ let requestUrl = `${BASE_URL}/authenticate.sjs?realm=${config.realm}`;
+ let contentPage = await ExtensionTestUtils.loadContentPage(requestUrl);
+ await Promise.all([
+ ex1.awaitMessage("onBeforeRequest"),
+ ex1.awaitMessage("onAuthRequired"),
+ ex1.awaitMessage("onErrorOccurred"),
+ ex2.awaitMessage("onBeforeRequest"),
+ ex2.awaitMessage("onAuthRequired"),
+ ex2.awaitMessage("onErrorOccurred"),
+ ]);
+
+ await contentPage.close();
+ await ex1.unload();
+ await ex2.unload();
+});
+
+add_task(async function test_webRequest_duelingAuth() {
+ let config = {
+ path: `${BASE_URL}/*`,
+ realm: `webRequest_auth${Math.random()}`,
+ onBeforeRequest: {
+ extra: ["blocking"],
+ },
+ onAuthRequired: {
+ extra: ["blocking"],
+ },
+ };
+ let exNone = getExtension(config);
+ await exNone.startup();
+
+ let authCredentials = {
+ username: `testuser_da1${Math.random()}`,
+ password: `testpass_da1${Math.random()}`,
+ };
+ config.onAuthRequired.result = { authCredentials };
+ let ex1 = getExtension(config);
+ await ex1.startup();
+
+ config.onAuthRequired.result = {};
+ let exEmpty = getExtension(config);
+ await exEmpty.startup();
+
+ config.onAuthRequired.result = {
+ authCredentials: {
+ username: `testuser_da2${Math.random()}`,
+ password: `testpass_da2${Math.random()}`,
+ },
+ };
+ let ex2 = getExtension(config);
+ await ex2.startup();
+
+ let requestUrl = `${BASE_URL}/authenticate.sjs?realm=${config.realm}&user=${authCredentials.username}&pass=${authCredentials.password}`;
+ let contentPage = await ExtensionTestUtils.loadContentPage(requestUrl);
+ await Promise.all([
+ exNone.awaitMessage("onBeforeRequest"),
+ exNone.awaitMessage("onAuthRequired").then(() => {
+ return Promise.all([
+ exNone.awaitMessage("onBeforeRequest"),
+ exNone.awaitMessage("onCompleted"),
+ ]);
+ }),
+ exEmpty.awaitMessage("onBeforeRequest"),
+ exEmpty.awaitMessage("onAuthRequired").then(() => {
+ return Promise.all([
+ exEmpty.awaitMessage("onBeforeRequest"),
+ exEmpty.awaitMessage("onCompleted"),
+ ]);
+ }),
+ ex1.awaitMessage("onBeforeRequest"),
+ ex1.awaitMessage("onAuthRequired").then(() => {
+ return Promise.all([
+ ex1.awaitMessage("onBeforeRequest"),
+ ex1.awaitMessage("onCompleted"),
+ ]);
+ }),
+ ex2.awaitMessage("onBeforeRequest"),
+ ex2.awaitMessage("onAuthRequired").then(() => {
+ return Promise.all([
+ ex2.awaitMessage("onBeforeRequest"),
+ ex2.awaitMessage("onCompleted"),
+ ]);
+ }),
+ ]);
+
+ await Promise.all([
+ await contentPage.close(),
+ exNone.unload(),
+ exEmpty.unload(),
+ ex1.unload(),
+ ex2.unload(),
+ ]);
+});
+
+add_task(async function test_webRequest_auth_proxy() {
+ function background(permissionPath) {
+ let proxyOk = false;
+ browser.webRequest.onAuthRequired.addListener(
+ details => {
+ browser.test.log(
+ `handlingExt onAuthRequired called with ${details.requestId} ${details.url}`
+ );
+ if (details.isProxy) {
+ browser.test.succeed("providing proxy authorization");
+ proxyOk = true;
+ return { authCredentials: { username: "puser", password: "ppass" } };
+ }
+ browser.test.assertTrue(
+ proxyOk,
+ "providing www authorization after proxy auth"
+ );
+ browser.test.sendMessage("done");
+ return { authCredentials: { username: "auser", password: "apass" } };
+ },
+ { urls: [permissionPath] },
+ ["blocking"]
+ );
+ }
+
+ let handlingExt = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["webRequest", "webRequestBlocking", `${BASE_URL}/*`],
+ },
+ background: `(${background})("${BASE_URL}/*")`,
+ });
+
+ await handlingExt.startup();
+
+ let requestUrl = `${BASE_URL}/authenticate.sjs?realm=webRequest_auth${Math.random()}&proxy_realm=proxy_auth${Math.random()}`;
+ let contentPage = await ExtensionTestUtils.loadContentPage(requestUrl);
+
+ await handlingExt.awaitMessage("done");
+ await contentPage.close();
+ await handlingExt.unload();
+});