forked from mirrors/gecko-dev
		
	 2c4e35b0a6
			
		
	
	
		2c4e35b0a6
		
	
	
	
	
		
			
			Differential Revision: https://phabricator.services.mozilla.com/D65509 --HG-- extra : moz-landing-system : lando
		
			
				
	
	
		
			425 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			425 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| "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();
 | |
| });
 |