Bug 613785 - Updated http auth prompt tests to support tab prompts. r=extension-reviewers,Gijs,zombie on a CLOSED TREE

Differential Revision: https://phabricator.services.mozilla.com/D75567
This commit is contained in:
pbz 2020-09-14 10:27:41 +00:00
parent cfc4fe8560
commit 16ea526e5b
15 changed files with 186 additions and 154 deletions

View File

@ -1,5 +1,14 @@
let { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js");
let authPromptModalType = Services.prefs.getIntPref(
"prompts.modalType.httpAuth"
);
let commonDialogEnabled =
authPromptModalType === Services.prompt.MODAL_TYPE_WINDOW ||
(authPromptModalType === Services.prompt.MODAL_TYPE_TAB &&
Services.prefs.getBoolPref("prompts.tabChromePromptSubDialog"));
let server = new HttpServer();
server.registerPathHandler("/file.html", fileHandler);
server.start(-1);
@ -27,17 +36,27 @@ function fileHandler(metadata, response) {
}
function onCommonDialogLoaded(subject) {
let dialog;
if (commonDialogEnabled) {
dialog = subject.Dialog;
} else {
let promptBox =
subject.ownerGlobal.gBrowser.selectedBrowser.tabModalPromptBox;
dialog = promptBox.getPrompt(subject).Dialog;
}
// Submit random account and password
let dialog = subject.Dialog;
dialog.ui.loginTextbox.setAttribute("value", Math.random());
dialog.ui.password1Textbox.setAttribute("value", Math.random());
dialog.ui.button0.click();
}
Services.obs.addObserver(onCommonDialogLoaded, "common-dialog-loaded");
let authPromptTopic = commonDialogEnabled
? "common-dialog-loaded"
: "tabmodal-dialog-loaded";
Services.obs.addObserver(onCommonDialogLoaded, authPromptTopic);
registerCleanupFunction(() => {
Services.obs.removeObserver(onCommonDialogLoaded, "common-dialog-loaded");
Services.obs.removeObserver(onCommonDialogLoaded, authPromptTopic);
server.stop(() => {
server = null;
});

View File

@ -5,34 +5,14 @@
// This tests that the basic auth dialog can not be used for DOS attacks
// and that the protections are reset on user-initiated navigation/reload.
const PROMPT_URL = "chrome://global/content/commonDialog.xhtml";
let promptModalType = Services.prefs.getIntPref("prompts.modalType.httpAuth");
function promiseAuthWindowShown() {
return new Promise(resolve => {
let listener = {
onOpenWindow(xulWin) {
let domwindow = xulWin.docShell.domWindow;
waitForFocus(() => {
is(
domwindow.document.location.href,
PROMPT_URL,
"Should have seen a prompt window"
);
is(
domwindow.args.promptType,
"promptUserAndPass",
"Should be an authenticate prompt"
);
domwindow.document.getElementById("commonDialog").cancelDialog();
Services.wm.removeListener(listener);
resolve();
}, domwindow);
},
onCloseWindow() {},
};
Services.wm.addListener(listener);
});
return PromptTestUtils.handleNextPrompt(
window,
{ modalType: promptModalType, promptType: "promptUserAndPass" },
{ buttonNumClick: 1 }
);
}
add_task(async function test() {

View File

@ -2,47 +2,33 @@
* 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/. */
const PROMPT_URL = "chrome://global/content/commonDialog.xhtml";
let modalType = Services.prefs.getIntPref("prompts.modalType.httpAuth");
add_task(async function test() {
await new Promise(resolve => {
let tab = BrowserTestUtils.addTab(gBrowser);
isnot(tab, gBrowser.selectedTab, "New tab shouldn't be selected");
let tab = BrowserTestUtils.addTab(gBrowser);
isnot(tab, gBrowser.selectedTab, "New tab shouldn't be selected");
let listener = {
onOpenWindow(xulWin) {
var domwindow = xulWin.docShell.domWindow;
waitForFocus(() => {
is(
domwindow.document.location.href,
PROMPT_URL,
"Should have seen a prompt window"
);
is(
domwindow.args.promptType,
"promptUserAndPass",
"Should be an authenticate prompt"
);
is(gBrowser.selectedTab, tab, "Should have selected the new tab");
domwindow.document.getElementById("commonDialog").cancelDialog();
}, domwindow);
},
onCloseWindow() {},
};
Services.wm.addListener(listener);
registerCleanupFunction(() => {
Services.wm.removeListener(listener);
gBrowser.removeTab(tab);
});
BrowserTestUtils.browserLoaded(tab.linkedBrowser).then(() => finish());
BrowserTestUtils.loadURI(
tab.linkedBrowser,
"http://example.com/browser/toolkit/components/passwordmgr/test/browser/authenticate.sjs"
);
let authPromptShown = PromptTestUtils.waitForPrompt(tab.linkedBrowser, {
modalType,
promptType: "promptUserAndPass",
});
let loadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
BrowserTestUtils.loadURI(
tab.linkedBrowser,
"http://example.com/browser/toolkit/components/passwordmgr/test/browser/authenticate.sjs"
);
// Wait for the basic auth prompt
let dialog = await authPromptShown;
is(gBrowser.selectedTab, tab, "Should have selected the new tab");
// Cancel the auth prompt
PromptTestUtils.handlePrompt(dialog, { buttonNumClick: 1 });
// After closing the prompt the load should finish
await loadPromise;
gBrowser.removeTab(tab);
});

View File

@ -74,14 +74,13 @@ async function loadAccessRestrictedURL(browser, url, username, password) {
let browserLoaded = BrowserTestUtils.browserLoaded(browser);
BrowserTestUtils.loadURI(browser, url);
let promptDoc = await waitForAuthPrompt();
let dialogUI = promptDoc.defaultView.Dialog.ui;
ok(dialogUI, "Got expected HTTP auth dialog Dialog.ui");
// Wait for the auth prompt, enter the login details and close the prompt
await PromptTestUtils.handleNextPrompt(
browser,
{ modalType: authPromptModalType, promptType: "promptUserAndPass" },
{ buttonNumClick: 0, loginInput: username, passwordInput: password }
);
// fill and submit the dialog form
dialogUI.loginTextbox.value = username;
dialogUI.password1Textbox.value = password;
promptDoc.getElementById("commonDialog").acceptDialog();
await SimpleTest.promiseFocus(browser.ownerGlobal);
await browserLoaded;
}
@ -107,11 +106,13 @@ const authUrl = `https://example.com/${DIRECTORY_PATH}authenticate.sjs`;
let normalWin;
let privateWin;
let authPromptModalType;
// XXX: Note that tasks are currently run in sequence. Some tests may assume the state
// resulting from successful or unsuccessful logins in previous tasks
add_task(async function test_setup() {
authPromptModalType = Services.prefs.getIntPref("prompts.modalType.httpAuth");
normalWin = await BrowserTestUtils.openNewBrowserWindow({ private: false });
privateWin = await BrowserTestUtils.openNewBrowserWindow({ private: true });
Services.logins.removeAllLogins();

View File

@ -7,6 +7,7 @@ const { LoginManagerParent } = ChromeUtils.import(
ChromeUtils.import("resource://testing-common/LoginTestUtils.jsm", this);
ChromeUtils.import("resource://testing-common/ContentTaskUtils.jsm", this);
ChromeUtils.import("resource://testing-common/TelemetryTestUtils.jsm", this);
ChromeUtils.import("resource://testing-common/PromptTestUtils.jsm", this);
add_task(async function common_initialize() {
await SpecialPowers.pushPrefEnv({

View File

@ -32,6 +32,23 @@ const {
const LOGIN_FIELD_UTILS = LoginTestUtils.loginField;
const TESTS_DIR = "/tests/toolkit/components/passwordmgr/test/";
// Depending on pref state we either show auth prompts as windows or on tab level.
let authPromptModalType = SpecialPowers.Services.prompt.MODAL_TYPE_WINDOW;
if (SpecialPowers.Services.prefs.getBoolPref("prompts.tab_modal.enabled")) {
authPromptModalType = SpecialPowers.Services.prefs.getIntPref(
"prompts.modalType.httpAuth"
);
}
// Whether the auth prompt is a commonDialog.xhtml or a TabModalPrompt
let authPromptIsCommonDialog =
authPromptModalType === SpecialPowers.Services.prompt.MODAL_TYPE_WINDOW ||
(authPromptModalType === SpecialPowers.Services.prompt.MODAL_TYPE_TAB &&
SpecialPowers.Services.prefs.getBoolPref(
"prompts.tabChromePromptSubDialog",
false
));
/**
* Returns the element with the specified |name| attribute.
*/

View File

@ -119,12 +119,30 @@
sendAsyncMessage("prepareForNextTestDone");
});
let dialogObserverTopic = "common-dialog-loaded";
let modalType = Services.prefs.getIntPref(
"prompts.modalType.httpAuth"
);
let authPromptIsCommonDialog =
modalType === Services.prompt.MODAL_TYPE_WINDOW
|| (modalType === Services.prompt.MODAL_TYPE_TAB
&& Services.prefs.getBoolPref(
"prompts.tabChromePromptSubDialog",
false
));
let dialogObserverTopic = authPromptIsCommonDialog
? "common-dialog-loaded" : "tabmodal-dialog-loaded";
function dialogObserver(subj, topic, data) {
subj.Dialog.ui.prompt.document
if (authPromptIsCommonDialog) {
subj.Dialog.ui.prompt.document
.getElementById("commonDialog")
.acceptDialog();
} else {
let prompt = subj.ownerGlobal.gBrowser.selectedBrowser
.tabModalPromptBox.getPrompt(subj);
prompt.Dialog.ui.button0.click(); // Accept button
}
sendAsyncMessage("promptAccepted");
}

View File

@ -16,9 +16,8 @@
const EXAMPLE_ORG = "http://example.org/tests/toolkit/components/passwordmgr/test/mochitest/";
let mozproxyOrigin;
// Force parent to not look for tab-modal prompts, as they're not used for auth prompts.
// Used by prompt_common.js.
modalType = Ci.nsIPrompt.MODAL_TYPE_WINDOW;
// Let prompt_common know what kind of modal type is enabled for auth prompts.
modalType = authPromptModalType;
// These are magically defined on the window due to the iframe IDs
/* global iframe1, iframe2a, iframe2b */

View File

@ -19,8 +19,8 @@
<script class="testbody" type="text/javascript">
var iframe = document.getElementById("iframe");
// Force parent to not look for tab-modal prompts, as they're not used for auth prompts.
modalType = Ci.nsIPrompt.MODAL_TYPE_WINDOW;
// Let prompt_common know what kind of modal type is enabled for auth prompts.
modalType = authPromptModalType;
const AUTHENTICATE_PATH = new URL("authenticate.sjs", window.location.href).pathname;

View File

@ -17,8 +17,8 @@
<pre id="test">
<script class="testbody" type="text/javascript">
// Force parent to not look for tab-modal prompts, as they're not used for auth prompts.
modalType = Ci.nsIPrompt.MODAL_TYPE_WINDOW;
// Let prompt_common know what kind of modal type is enabled for auth prompts.
modalType = authPromptModalType;
add_task(async function setup() {
let loginAddedPromise = promiseStorageChanged(["addLogin"]);

View File

@ -30,8 +30,8 @@ var authinfo = {
realm: "",
};
// Force parent to not look for tab-modal prompts, as they're not used for auth prompts.
modalType = Ci.nsIPrompt.MODAL_TYPE_WINDOW;
// Let prompt_common know what kind of modal type is enabled for auth prompts.
modalType = authPromptModalType;
let prompterParent = runInParent(() => {
const promptFac = Cc["@mozilla.org/passwordmanager/authpromptfactory;1"].
@ -40,6 +40,7 @@ let prompterParent = runInParent(() => {
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
let chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
let prompter2 = promptFac.getPrompt(chromeWin, Ci.nsIAuthPrompt2);
prompter2.QueryInterface(Ci.nsILoginManagerAuthPrompter).browser = chromeWin.gBrowser.selectedBrowser;
let channels = {};
channels.channel1 = Services.io.newChannel("http://example.com",

View File

@ -40,7 +40,8 @@ var proxyAuthinfo = {
};
// Force parent to not look for tab-modal prompts, as they're not used for auth prompts.
modalType = Ci.nsIPrompt.MODAL_TYPE_WINDOW;
// Let prompt_common know what kind of modal type is enabled for auth prompts.
modalType = authPromptModalType;
const Cc_promptFac = Cc["@mozilla.org/passwordmanager/authpromptfactory;1"];
ok(Cc_promptFac != null, "Access Cc[@mozilla.org/passwordmanager/authpromptfactory;1]");

View File

@ -40,8 +40,8 @@ function xhrLoad(xmlDoc) {
return {username, password, authok};
}
// Force parent to not look for tab-modal prompts, as they're not used for auth prompts.
modalType = Ci.nsIPrompt.MODAL_TYPE_WINDOW;
// Let prompt_common know what kind of modal type is enabled for auth prompts.
modalType = authPromptModalType;
let prompterParent = runInParent(() => {
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
@ -131,15 +131,19 @@ add_task(async function test2() {
checked: false,
focused: "textField",
defButton: "button0",
// Check that the dialog is modal, chrome and dependent;
// We can't just check window.opener because that'll be
// a content window, which therefore isn't exposed (it'll lie and
// be null).
chrome: true,
dialog: true,
chromeDependent: true,
isWindowModal: true,
};
// For window prompts check that the dialog is modal, chrome and dependent;
// We can't just check window.opener because that'll be
// a content window, which therefore isn't exposed (it'll lie and
// be null).
if (authPromptModalType === SpecialPowers.Services.prompt.MODAL_TYPE_WINDOW) {
state.chrome = true;
state.dialog = true;
state.chromeDependent = true;
state.isWindowModal = true;
}
let action = {
buttonClick: "ok",
};

View File

@ -33,6 +33,15 @@ var iframe1Loaded = onloadPromiseFor("iframe_diff_origin");
var iframe2Loaded = onloadPromiseFor("iframe_same_origin");
var iframe_prompt = document.getElementById("iframe_prompt");
// Depending on pref state we either show auth prompts as windows or on tab level.
let authPromptModalType = SpecialPowers.Services.prompt.MODAL_TYPE_WINDOW;
if (SpecialPowers.Services.prefs.getBoolPref("prompts.tab_modal.enabled")) {
authPromptModalType = SpecialPowers.Services.prefs.getIntPref(
"prompts.modalType.httpAuth"
);
}
add_task(async function runTest() {
// This test depends on tab modal prompts being enabled.
if (!tabModalPromptEnabled) {
@ -101,12 +110,11 @@ add_task(async function runTest() {
});
add_task(async function runTestAuth() {
// Following tests chack prompt message for a cross-origin and not
// Following tests check prompt message for a cross-origin and not
// cross-origin subresources load
// Auth prompts are window modal
modalType = Ci.nsIPrompt.MODAL_TYPE_WINDOW;
// Let prompt_common know what kind of modal type is enabled for auth prompts.
modalType = authPromptModalType;
let state, action;

View File

@ -3,6 +3,9 @@
const { PermissionTestUtils } = ChromeUtils.import(
"resource://testing-common/PermissionTestUtils.jsm"
);
const { PromptTestUtils } = ChromeUtils.import(
"resource://testing-common/PromptTestUtils.jsm"
);
const RELATIVE_DIR = "toolkit/mozapps/extensions/test/xpinstall/";
@ -118,12 +121,14 @@ var Harness = {
Services.obs.addObserver(this, "addon-install-failed");
Services.obs.addObserver(this, "addon-install-complete");
// For browser_auth tests which trigger auth dialogs.
Services.obs.addObserver(this, "tabmodal-dialog-loaded");
Services.obs.addObserver(this, "common-dialog-loaded");
this._boundWin = Cu.getWeakReference(win); // need this so our addon manager listener knows which window to use.
AddonManager.addInstallListener(this);
AddonManager.addAddonListener(this);
Services.wm.addListener(this);
win.addEventListener("popupshown", this);
win.PanelUI.notificationPanel.addEventListener("popupshown", this);
@ -143,11 +148,12 @@ var Harness = {
Services.obs.removeObserver(self, "addon-install-failed");
Services.obs.removeObserver(self, "addon-install-complete");
Services.obs.removeObserver(self, "tabmodal-dialog-loaded");
Services.obs.removeObserver(self, "common-dialog-loaded");
AddonManager.removeInstallListener(self);
AddonManager.removeAddonListener(self);
Services.wm.removeListener(self);
win.removeEventListener("popupshown", self);
win.PanelUI.notificationPanel.removeEventListener("popupshown", self);
win = null;
@ -223,40 +229,38 @@ var Harness = {
}
},
// Window open handling
windowReady(window) {
if (window.document.location.href == PROMPT_URL) {
var promptType = window.args.promptType;
let dialog = window.document.getElementById("commonDialog");
switch (promptType) {
case "alert":
case "alertCheck":
case "confirmCheck":
case "confirm":
case "confirmEx":
dialog.acceptDialog();
break;
case "promptUserAndPass":
// This is a login dialog, hopefully an authentication prompt
// for the xpi.
if (this.authenticationCallback) {
var auth = this.authenticationCallback();
if (auth && auth.length == 2) {
window.document.getElementById("loginTextbox").value = auth[0];
window.document.getElementById("password1Textbox").value =
auth[1];
dialog.acceptDialog();
} else {
dialog.cancelDialog();
}
promptReady(dialog) {
let promptType = dialog.args.promptType;
switch (promptType) {
case "alert":
case "alertCheck":
case "confirmCheck":
case "confirm":
case "confirmEx":
PromptTestUtils.handlePrompt(dialog, { buttonNumClick: 0 });
break;
case "promptUserAndPass":
// This is a login dialog, hopefully an authentication prompt
// for the xpi.
if (this.authenticationCallback) {
var auth = this.authenticationCallback();
if (auth && auth.length == 2) {
PromptTestUtils.handlePrompt(dialog, {
loginInput: auth[0],
passwordInput: auth[1],
buttonNumClick: 0,
});
} else {
dialog.cancelDialog();
PromptTestUtils.handlePrompt(dialog, { buttonNumClick: 1 });
}
break;
default:
ok(false, "prompt type " + promptType + " not handled in test.");
break;
}
} else {
PromptTestUtils.handlePrompt(dialog, { buttonNumClick: 1 });
}
break;
default:
ok(false, "prompt type " + promptType + " not handled in test.");
break;
}
},
@ -357,18 +361,6 @@ var Harness = {
}
},
// nsIWindowMediatorListener
onOpenWindow(xulWin) {
var domwindow = xulWin.docShell.domWindow;
var self = this;
waitForFocus(function() {
self.windowReady(domwindow);
}, domwindow);
},
onCloseWindow(window) {},
// Addon Install Listener
onNewInstall(install) {
@ -556,11 +548,16 @@ var Harness = {
);
}, this);
break;
case "tabmodal-dialog-loaded":
let browser = subject.ownerGlobal.gBrowser.selectedBrowser;
let prompt = browser.tabModalPromptBox.getPrompt(subject);
this.promptReady(prompt.Dialog);
break;
case "common-dialog-loaded":
this.promptReady(subject.Dialog);
break;
}
},
QueryInterface: ChromeUtils.generateQI([
"nsIObserver",
"nsIWindowMediatorListener",
]),
QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
};