Bug 422135: fix login manager's nsIAuthPrompt implementation to deal with NS_GetAuthKey-generated realms, r=dolske/standard8
This commit is contained in:
Родитель
27bc03acb8
Коммит
1a4e915cf9
|
@ -215,46 +215,49 @@ LoginManagerPrompter.prototype = {
|
|||
*/
|
||||
promptUsernameAndPassword : function (aDialogTitle, aText, aPasswordRealm,
|
||||
aSavePassword, aUsername, aPassword) {
|
||||
this.log("===== promptUsernameAndPassword() called =====");
|
||||
|
||||
if (aSavePassword == Ci.nsIAuthPrompt.SAVE_PASSWORD_FOR_SESSION)
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
var selectedLogin = null;
|
||||
var checkBox = { value : false };
|
||||
var checkBoxLabel = null;
|
||||
var hostname = this._getFormattedHostname(aPasswordRealm);
|
||||
var [hostname, realm, unused] = this._getRealmInfo(aPasswordRealm);
|
||||
|
||||
this.log("===== promptUsernameAndPassword() called =====");
|
||||
// If hostname is null, we can't save this login.
|
||||
if (hostname) {
|
||||
var canRememberLogin = (aSavePassword ==
|
||||
Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY) &&
|
||||
this._pwmgr.getLoginSavingEnabled(hostname);
|
||||
|
||||
var canRememberLogin = (aSavePassword ==
|
||||
Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY) &&
|
||||
this._pwmgr.getLoginSavingEnabled(hostname);
|
||||
// if checkBoxLabel is null, the checkbox won't be shown at all.
|
||||
if (canRememberLogin)
|
||||
checkBoxLabel = this._getLocalizedString("rememberPassword");
|
||||
|
||||
// if checkBoxLabel is null, the checkbox won't be shown at all.
|
||||
if (canRememberLogin)
|
||||
checkBoxLabel = this._getLocalizedString("rememberPassword");
|
||||
// Look for existing logins.
|
||||
var foundLogins = this._pwmgr.findLogins({}, hostname, null,
|
||||
realm);
|
||||
|
||||
// Look for existing logins.
|
||||
var foundLogins = this._pwmgr.findLogins({}, hostname, null,
|
||||
aPasswordRealm);
|
||||
// XXX Like the original code, we can't deal with multiple
|
||||
// account selection. (bug 227632)
|
||||
if (foundLogins.length > 0) {
|
||||
selectedLogin = foundLogins[0];
|
||||
|
||||
// XXX Like the original code, we can't deal with multiple
|
||||
// account selection. (bug 227632)
|
||||
if (foundLogins.length > 0) {
|
||||
selectedLogin = foundLogins[0];
|
||||
// If the caller provided a username, try to use it. If they
|
||||
// provided only a password, this will try to find a password-only
|
||||
// login (or return null if none exists).
|
||||
if (aUsername.value)
|
||||
selectedLogin = this._repickSelectedLogin(foundLogins,
|
||||
aUsername.value);
|
||||
|
||||
// If the caller provided a username, try to use it. If they
|
||||
// provided only a password, this will try to find a password-only
|
||||
// login (or return null if none exists).
|
||||
if (aUsername.value)
|
||||
selectedLogin = this._repickSelectedLogin(foundLogins,
|
||||
aUsername.value);
|
||||
|
||||
if (selectedLogin) {
|
||||
checkBox.value = true;
|
||||
aUsername.value = selectedLogin.username;
|
||||
// If the caller provided a password, prefer it.
|
||||
if (!aPassword.value)
|
||||
aPassword.value = selectedLogin.password;
|
||||
if (selectedLogin) {
|
||||
checkBox.value = true;
|
||||
aUsername.value = selectedLogin.username;
|
||||
// If the caller provided a password, prefer it.
|
||||
if (!aPassword.value)
|
||||
aPassword.value = selectedLogin.password;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -262,14 +265,12 @@ LoginManagerPrompter.prototype = {
|
|||
aDialogTitle, aText, aUsername, aPassword,
|
||||
checkBoxLabel, checkBox);
|
||||
|
||||
if (!ok || !checkBox.value)
|
||||
if (!ok || !checkBox.value || !hostname)
|
||||
return ok;
|
||||
|
||||
|
||||
var newLogin = Cc["@mozilla.org/login-manager/loginInfo;1"].
|
||||
createInstance(Ci.nsILoginInfo);
|
||||
newLogin.init(hostname, null, aPasswordRealm,
|
||||
aUsername.value, aPassword.value,
|
||||
newLogin.init(hostname, null, realm, aUsername.value, aPassword.value,
|
||||
"", "");
|
||||
|
||||
// XXX We can't prompt with multiple logins yet (bug 227632), so
|
||||
|
@ -281,11 +282,11 @@ LoginManagerPrompter.prototype = {
|
|||
// changed, save as a new login.
|
||||
if (!selectedLogin) {
|
||||
// add as new
|
||||
this.log("New login seen for " + aPasswordRealm);
|
||||
this.log("New login seen for " + realm);
|
||||
this._pwmgr.addLogin(newLogin);
|
||||
} else if (aPassword.value != selectedLogin.password) {
|
||||
// update password
|
||||
this.log("Updating password for " + aPasswordRealm);
|
||||
this.log("Updating password for " + realm);
|
||||
this._pwmgr.modifyLogin(selectedLogin, newLogin);
|
||||
} else {
|
||||
this.log("Login unchanged, no further action needed.");
|
||||
|
@ -306,54 +307,56 @@ LoginManagerPrompter.prototype = {
|
|||
* allows it, then the password will be saved in the database.
|
||||
*/
|
||||
promptPassword : function (aDialogTitle, aText, aPasswordRealm,
|
||||
aSavePassword, aPassword) {
|
||||
aSavePassword, aPassword) {
|
||||
this.log("===== promptPassword called() =====");
|
||||
|
||||
if (aSavePassword == Ci.nsIAuthPrompt.SAVE_PASSWORD_FOR_SESSION)
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
var checkBox = { value : false };
|
||||
var checkBoxLabel = null;
|
||||
var [hostname, username, pathname] = this._decomposeURI(aPasswordRealm);
|
||||
var newRealm = hostname + pathname;
|
||||
var [hostname, realm, username] = this._getRealmInfo(aPasswordRealm);
|
||||
|
||||
this.log("===== promptPassword called() =====");
|
||||
|
||||
var canRememberLogin = (aSavePassword ==
|
||||
Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY) &&
|
||||
this._pwmgr.getLoginSavingEnabled(hostname);
|
||||
|
||||
// if checkBoxLabel is null, the checkbox won't be shown at all.
|
||||
if (canRememberLogin)
|
||||
checkBoxLabel = this._getLocalizedString("rememberPassword");
|
||||
|
||||
if (!aPassword.value) {
|
||||
// Look for existing logins.
|
||||
var foundLogins = this._pwmgr.findLogins({}, hostname, null,
|
||||
newRealm);
|
||||
|
||||
// XXX Like the original code, we can't deal with multiple
|
||||
// account selection (bug 227632). We can deal with finding the
|
||||
// account based on the supplied username - but in this case we'll
|
||||
// just return the first match.
|
||||
for (var i = 0; i < foundLogins.length; ++i) {
|
||||
if (foundLogins[i].username == username) {
|
||||
aPassword.value = foundLogins[i].password;
|
||||
// wallet returned straight away, so this mimics that code
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// If hostname is null, we can't save this login.
|
||||
if (hostname) {
|
||||
var canRememberLogin = (aSavePassword ==
|
||||
Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY) &&
|
||||
this._pwmgr.getLoginSavingEnabled(hostname);
|
||||
|
||||
// if checkBoxLabel is null, the checkbox won't be shown at all.
|
||||
if (canRememberLogin)
|
||||
checkBoxLabel = this._getLocalizedString("rememberPassword");
|
||||
|
||||
if (!aPassword.value) {
|
||||
// Look for existing logins.
|
||||
var foundLogins = this._pwmgr.findLogins({}, hostname, null,
|
||||
realm);
|
||||
|
||||
// XXX Like the original code, we can't deal with multiple
|
||||
// account selection (bug 227632). We can deal with finding the
|
||||
// account based on the supplied username - but in this case we'll
|
||||
// just return the first match.
|
||||
for (var i = 0; i < foundLogins.length; ++i) {
|
||||
if (foundLogins[i].username == username) {
|
||||
aPassword.value = foundLogins[i].password;
|
||||
// wallet returned straight away, so this mimics that code
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var ok = this._promptService.promptPassword(this._window, aDialogTitle,
|
||||
aText, aPassword,
|
||||
checkBoxLabel, checkBox);
|
||||
|
||||
if (ok && checkBox.value) {
|
||||
if (ok && checkBox.value && hostname) {
|
||||
var newLogin = Cc["@mozilla.org/login-manager/loginInfo;1"].
|
||||
createInstance(Ci.nsILoginInfo);
|
||||
newLogin.init(hostname, null, newRealm, username,
|
||||
newLogin.init(hostname, null, realm, username,
|
||||
aPassword.value, "", "");
|
||||
|
||||
this.log("New login seen for " + newRealm);
|
||||
this.log("New login seen for " + realm);
|
||||
|
||||
this._pwmgr.addLogin(newLogin);
|
||||
}
|
||||
|
@ -361,8 +364,36 @@ LoginManagerPrompter.prototype = {
|
|||
return ok;
|
||||
},
|
||||
|
||||
/* ---------- nsIAuthPrompt helpers ---------- */
|
||||
|
||||
|
||||
/**
|
||||
* Given aRealmString, such as "http://user@example.com/foo", returns an
|
||||
* array of:
|
||||
* - the formatted hostname
|
||||
* - the realm (hostname + path)
|
||||
* - the username, if present
|
||||
*
|
||||
* If aRealmString is in the format produced by NS_GetAuthKey for HTTP[S]
|
||||
* channels, e.g. "example.com:80 (httprealm)", null is returned for all
|
||||
* arguments to let callers know the login can't be saved because we don't
|
||||
* know whether it's http or https.
|
||||
*/
|
||||
_getRealmInfo : function (aRealmString) {
|
||||
var httpRealm = /^.+ \(.+\)$/;
|
||||
if (httpRealm.test(aRealmString))
|
||||
return [null, null, null];
|
||||
|
||||
var uri = this._ioService.newURI(aRealmString, null, null);
|
||||
var pathname = "";
|
||||
|
||||
if (uri.path != "/")
|
||||
pathname = uri.path;
|
||||
|
||||
var formattedHostname = this._getFormattedHostname(uri);
|
||||
|
||||
return [formattedHostname, formattedHostname + pathname, uri.username];
|
||||
},
|
||||
|
||||
/* ---------- nsIAuthPrompt2 prompts ---------- */
|
||||
|
||||
|
@ -977,20 +1008,6 @@ LoginManagerPrompter.prototype = {
|
|||
return hostname;
|
||||
},
|
||||
|
||||
/**
|
||||
* Extracts a hostname, username and a pathname from a string based URI
|
||||
* via a standard URI implementation.
|
||||
*/
|
||||
_decomposeURI: function (aURIString) {
|
||||
var uri = this._ioService.newURI(aURIString, null, null);
|
||||
var pathname = "";
|
||||
|
||||
if (uri.path != "/")
|
||||
pathname = uri.path;
|
||||
|
||||
return [this._getFormattedHostname(uri), uri.username, pathname];
|
||||
},
|
||||
|
||||
/*
|
||||
* _getAuthTarget
|
||||
*
|
||||
|
|
|
@ -145,6 +145,12 @@ function handleDialog(doc, testNum) {
|
|||
passfield.setAttribute("value", "secret");
|
||||
break;
|
||||
|
||||
case 30:
|
||||
case 31:
|
||||
is(password, "", "Checking provided password");
|
||||
passfield.setAttribute("value", "fill2pass");
|
||||
break;
|
||||
|
||||
case 100:
|
||||
is(username, "inuser", "Checking provided username");
|
||||
is(password, "inpass", "Checking provided password");
|
||||
|
@ -188,6 +194,14 @@ function handleDialog(doc, testNum) {
|
|||
passfield.setAttribute("value", "user2pass");
|
||||
break;
|
||||
|
||||
case 120:
|
||||
case 121:
|
||||
is(username, "", "Checking filled username");
|
||||
is(password, "", "Checking filled password");
|
||||
userfield.setAttribute("value", "fill2user");
|
||||
passfield.setAttribute("value", "fill2pass");
|
||||
break;
|
||||
|
||||
case 500:
|
||||
is(username, "inuser", "Checking unfilled username");
|
||||
is(password, "inpass", "Checking unfilled password");
|
||||
|
@ -493,6 +507,27 @@ is(pword.value, "user2pass", "Checking returned password");
|
|||
// XXX test saving a password with Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY
|
||||
|
||||
|
||||
// ===== test 30 =====
|
||||
// We don't pre-fill or save for NS_GetAuthKey-generated realms, but we should still prompt
|
||||
testNum = 30;
|
||||
pword.value = null;
|
||||
startCallbackTimer();
|
||||
isOk = prompter1.promptPassword(dialogTitle(), dialogText, "example2.com:80 (somerealm)",
|
||||
Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
|
||||
ok(isOk, "Checking dialog return value (accept)");
|
||||
is(pword.value, "fill2pass", "Checking returned password");
|
||||
|
||||
// ===== test 31 =====
|
||||
// We don't pre-fill or save for NS_GetAuthKey-generated realms, but we should still prompt
|
||||
testNum++;
|
||||
pword.value = null;
|
||||
startCallbackTimer();
|
||||
isOk = prompter1.promptPassword(dialogTitle(), dialogText, "example2.com:80 (somerealm)",
|
||||
Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, pword);
|
||||
ok(isOk, "Checking dialog return value (accept)");
|
||||
is(pword.value, "fill2pass", "Checking returned password");
|
||||
|
||||
|
||||
// ===== test 100 =====
|
||||
testNum = 100;
|
||||
uname.value = "inuser";
|
||||
|
@ -585,6 +620,29 @@ ok(isOk, "Checking dialog return value (accept)");
|
|||
is(uname.value, "user2name", "Checking returned username");
|
||||
is(pword.value, "user2pass", "Checking returned password");
|
||||
|
||||
// ===== test 120 =====
|
||||
// We don't pre-fill or save for NS_GetAuthKey-generated realms, but we should still prompt
|
||||
testNum = 120;
|
||||
uname.value = null;
|
||||
pword.value = null;
|
||||
startCallbackTimer();
|
||||
isOk = prompter1.promptUsernameAndPassword(dialogTitle(), dialogText, "example2.com:80 (somerealm)",
|
||||
Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, uname, pword);
|
||||
ok(isOk, "Checking dialog return value (accept)");
|
||||
is(uname.value, "fill2user", "Checking returned username");
|
||||
is(pword.value, "fill2pass", "Checking returned password");
|
||||
|
||||
// ===== test 121 =====
|
||||
// We don't pre-fill or save for NS_GetAuthKey-generated realms, but we should still prompt
|
||||
testNum++;
|
||||
uname.value = null;
|
||||
pword.value = null;
|
||||
startCallbackTimer();
|
||||
isOk = prompter1.promptUsernameAndPassword(dialogTitle(), dialogText, "example2.com:80 (somerealm)",
|
||||
Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, uname, pword);
|
||||
ok(isOk, "Checking dialog return value (accept)");
|
||||
is(uname.value, "fill2user", "Checking returned username");
|
||||
is(pword.value, "fill2pass", "Checking returned password");
|
||||
|
||||
|
||||
var channel1 = Cc["@mozilla.org/network/io-service;1"].
|
||||
|
|
Загрузка…
Ссылка в новой задаче