forked from mirrors/gecko-dev
150 lines
4.8 KiB
JavaScript
150 lines
4.8 KiB
JavaScript
/* 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.loadURI(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;
|
|
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;
|
|
}
|
|
);
|
|
|
|
is(loginResult == "PASS", expectAuthed, "Site has expected auth state");
|
|
is(user, expectAuthed ? authOptions.user : "", "Sent correct user");
|
|
is(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));
|
|
|
|
is(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");
|
|
is(
|
|
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));
|
|
});
|