summaryrefslogtreecommitdiffstats
path: root/toolkit/components/passwordmgr/test/browser/browser_basicAuth_multiTab.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/passwordmgr/test/browser/browser_basicAuth_multiTab.js')
-rw-r--r--toolkit/components/passwordmgr/test/browser/browser_basicAuth_multiTab.js158
1 files changed, 158 insertions, 0 deletions
diff --git a/toolkit/components/passwordmgr/test/browser/browser_basicAuth_multiTab.js b/toolkit/components/passwordmgr/test/browser/browser_basicAuth_multiTab.js
new file mode 100644
index 0000000000..0069c653a5
--- /dev/null
+++ b/toolkit/components/passwordmgr/test/browser/browser_basicAuth_multiTab.js
@@ -0,0 +1,158 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+/**
+ * Tests that can show multiple auth prompts in different tabs and handle them
+ * correctly.
+ */
+
+const ORIGIN1 = "https://example.com";
+const ORIGIN2 = "https://example.org";
+
+const AUTH_PATH =
+ "/browser/toolkit/components/passwordmgr/test/browser/authenticate.sjs";
+
+/**
+ * Opens a tab and navigates to the auth test path.
+ * @param {String} origin - Origin to open with test path.
+ * @param {Object} authOptions - Authentication options to pass to server and
+ * test for.
+ * @param {String} authOptions.user - Expected username.
+ * @param {String} authOptions.pass - Expected password.
+ * @param {String} authOptions.realm - Realm to return on auth request.
+ * @returns {Object} - An object containing passed origin and authOptions,
+ * opened tab, a promise which resolves once the tab loads, a promise which
+ * resolves once the prompt has been opened.
+ */
+async function openTabWithAuthPrompt(origin, authOptions) {
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ "https://example.com"
+ );
+
+ let promptPromise = PromptTestUtils.waitForPrompt(tab.linkedBrowser, {
+ modalType: Services.prompt.MODAL_TYPE_TAB,
+ promptType: "promptUserAndPass",
+ });
+ let url = new URL(origin + AUTH_PATH);
+ Object.entries(authOptions).forEach(([key, value]) =>
+ url.searchParams.append(key, value)
+ );
+ let loadPromise = BrowserTestUtils.browserLoaded(
+ tab.linkedBrowser,
+ false,
+ url.toString()
+ );
+ info("Loading " + url.toString());
+ BrowserTestUtils.startLoadingURIString(tab.linkedBrowser, url.toString());
+ return { origin, tab, authOptions, loadPromise, promptPromise };
+}
+
+/**
+ * Waits for tab to load and tests for expected auth state.
+ * @param {boolean} expectAuthed - true: auth success, false otherwise.
+ * @param {Object} tabInfo - Information about the tab as generated by
+ * openTabWithAuthPrompt.
+ */
+async function testTabAuthed(expectAuthed, { tab, loadPromise, authOptions }) {
+ // Wait for tab to load after auth.
+ await loadPromise;
+ Assert.ok(true, "Tab loads after auth");
+
+ // Fetch auth results from body (set by authenticate.sjs).
+ let { loginResult, user, pass } = await SpecialPowers.spawn(
+ tab.linkedBrowser,
+ [],
+ () => {
+ let result = {};
+ result.loginResult = content.document.getElementById("ok").innerText;
+ result.user = content.document.getElementById("user").innerText;
+ result.pass = content.document.getElementById("pass").innerText;
+ return result;
+ }
+ );
+
+ Assert.equal(
+ loginResult == "PASS",
+ expectAuthed,
+ "Site has expected auth state"
+ );
+ Assert.equal(user, expectAuthed ? authOptions.user : "", "Sent correct user");
+ Assert.equal(
+ pass,
+ expectAuthed ? authOptions.pass : "",
+ "Sent correct password"
+ );
+}
+
+add_setup(async function () {
+ await SpecialPowers.pushPrefEnv({
+ // This test relies on tab auth prompts.
+ set: [["prompts.modalType.httpAuth", Services.prompt.MODAL_TYPE_TAB]],
+ });
+});
+
+add_task(async function test() {
+ let tabA = await openTabWithAuthPrompt(ORIGIN1, {
+ user: "userA",
+ pass: "passA",
+ realm: "realmA",
+ });
+ // Tab B and C share realm and credentials.
+ // However, since the auth happens in separate tabs we should get two prompts.
+ let tabB = await openTabWithAuthPrompt(ORIGIN2, {
+ user: "userB",
+ pass: "passB",
+ realm: "realmB",
+ });
+ let tabC = await openTabWithAuthPrompt(ORIGIN2, {
+ user: "userB",
+ pass: "passB",
+ realm: "realmB",
+ });
+ let tabs = [tabA, tabB, tabC];
+
+ info(`Opening ${tabs.length} tabs with auth prompts`);
+ let prompts = await Promise.all(tabs.map(tab => tab.promptPromise));
+
+ Assert.equal(prompts.length, tabs.length, "Should have one prompt per tab");
+
+ for (let i = 0; i < prompts.length; i++) {
+ let titleEl = prompts[i].ui.prompt.document.querySelector("#titleText");
+ Assert.equal(
+ titleEl.textContent,
+ new URL(tabs[i].origin).host,
+ "Prompt matches the tab's host"
+ );
+ }
+
+ // Interact with the prompts. This is deliberately done out of order
+ // (no FIFO, LIFO).
+ let [promptA, promptB, promptC] = prompts;
+
+ // Accept prompt B with correct login details.
+ await PromptTestUtils.handlePrompt(promptB, {
+ loginInput: tabB.authOptions.user,
+ passwordInput: tabB.authOptions.pass,
+ });
+ await testTabAuthed(true, tabB);
+
+ // Accept prompt A with correct login details
+ await PromptTestUtils.handlePrompt(promptA, {
+ loginInput: tabA.authOptions.user,
+ passwordInput: tabA.authOptions.pass,
+ });
+ await testTabAuthed(true, tabA);
+
+ // Cancel prompt C
+ await PromptTestUtils.handlePrompt(promptC, {
+ buttonNumClick: 1,
+ });
+ await testTabAuthed(false, tabC);
+
+ // Cleanup tabs
+ tabs.forEach(({ tab }) => BrowserTestUtils.removeTab(tab));
+});