Bug 1403081 - Optionally protect filling of saved logins with OS authentication (including biometrics). r=sgalich,settings-reviewers,fluent-reviewers,flod

Depends on D207219

Differential Revision: https://phabricator.services.mozilla.com/D201276
This commit is contained in:
Sidharth Sachdev
2024-05-05 15:59:35 +00:00
parent e5b55bbc65
commit 8716cffc2b
6 changed files with 93 additions and 26 deletions

View File

@@ -17,7 +17,6 @@ ChromeUtils.defineESModuleGetters(lazy, {
LoginExport: "resource://gre/modules/LoginExport.sys.mjs", LoginExport: "resource://gre/modules/LoginExport.sys.mjs",
LoginHelper: "resource://gre/modules/LoginHelper.sys.mjs", LoginHelper: "resource://gre/modules/LoginHelper.sys.mjs",
MigrationUtils: "resource:///modules/MigrationUtils.sys.mjs", MigrationUtils: "resource:///modules/MigrationUtils.sys.mjs",
OSKeyStore: "resource://gre/modules/OSKeyStore.sys.mjs",
UIState: "resource://services-sync/UIState.sys.mjs", UIState: "resource://services-sync/UIState.sys.mjs",
}); });
@@ -36,12 +35,6 @@ XPCOMUtils.defineLazyPreferenceGetter(
"identity.fxaccounts.enabled", "identity.fxaccounts.enabled",
false false
); );
XPCOMUtils.defineLazyPreferenceGetter(
lazy,
"OS_AUTH_ENABLED",
"signon.management.page.os-auth.enabled",
true
);
XPCOMUtils.defineLazyPreferenceGetter( XPCOMUtils.defineLazyPreferenceGetter(
lazy, lazy,
"VULNERABLE_PASSWORDS_ENABLED", "VULNERABLE_PASSWORDS_ENABLED",
@@ -266,11 +259,15 @@ export class AboutLoginsParent extends JSWindowActorParent {
let messageText = { value: "NOT SUPPORTED" }; let messageText = { value: "NOT SUPPORTED" };
let captionText = { value: "" }; let captionText = { value: "" };
const isOSAuthEnabled = lazy.LoginHelper.getOSAuthEnabled(
lazy.LoginHelper.OS_AUTH_FOR_PASSWORDS_PREF
);
// This feature is only supported on Windows and macOS // This feature is only supported on Windows and macOS
// but we still call in to OSKeyStore on Linux to get // but we still call in to OSKeyStore on Linux to get
// the proper auth_details for Telemetry. // the proper auth_details for Telemetry.
// See bug 1614874 for Linux support. // See bug 1614874 for Linux support.
if (lazy.OS_AUTH_ENABLED && lazy.OSKeyStore.canReauth()) { if (isOSAuthEnabled) {
messageId += "-" + AppConstants.platform; messageId += "-" + AppConstants.platform;
[messageText, captionText] = await lazy.AboutLoginsL10n.formatMessages([ [messageText, captionText] = await lazy.AboutLoginsL10n.formatMessages([
{ {
@@ -284,7 +281,7 @@ export class AboutLoginsParent extends JSWindowActorParent {
let { isAuthorized, telemetryEvent } = await lazy.LoginHelper.requestReauth( let { isAuthorized, telemetryEvent } = await lazy.LoginHelper.requestReauth(
this.browsingContext.embedderElement, this.browsingContext.embedderElement,
lazy.OS_AUTH_ENABLED, isOSAuthEnabled,
AboutLogins._authExpirationTime, AboutLogins._authExpirationTime,
messageText.value, messageText.value,
captionText.value captionText.value
@@ -378,11 +375,15 @@ export class AboutLoginsParent extends JSWindowActorParent {
let messageText = { value: "NOT SUPPORTED" }; let messageText = { value: "NOT SUPPORTED" };
let captionText = { value: "" }; let captionText = { value: "" };
const isOSAuthEnabled = lazy.LoginHelper.getOSAuthEnabled(
lazy.LoginHelper.OS_AUTH_FOR_PASSWORDS_PREF
);
// This feature is only supported on Windows and macOS // This feature is only supported on Windows and macOS
// but we still call in to OSKeyStore on Linux to get // but we still call in to OSKeyStore on Linux to get
// the proper auth_details for Telemetry. // the proper auth_details for Telemetry.
// See bug 1614874 for Linux support. // See bug 1614874 for Linux support.
if (lazy.OSKeyStore.canReauth()) { if (isOSAuthEnabled) {
const messageId = const messageId =
EXPORT_PASSWORD_OS_AUTH_DIALOG_MESSAGE_IDS[AppConstants.platform]; EXPORT_PASSWORD_OS_AUTH_DIALOG_MESSAGE_IDS[AppConstants.platform];
if (!messageId) { if (!messageId) {

View File

@@ -551,6 +551,12 @@
/> />
</hbox> </hbox>
</vbox> </vbox>
<vbox>
<hbox id="osReauthRow" align="center">
<checkbox id="osReauthCheckbox"
data-l10n-id="forms-os-reauth"/>
</hbox>
</vbox>
<vbox> <vbox>
<hbox id="masterPasswordRow" align="center"> <hbox id="masterPasswordRow" align="center">
<checkbox id="useMasterPassword" <checkbox id="useMasterPassword"

View File

@@ -60,6 +60,10 @@ ChromeUtils.defineLazyGetter(this, "AlertsServiceDND", function () {
} }
}); });
ChromeUtils.defineLazyGetter(lazy, "AboutLoginsL10n", () => {
return new Localization(["branding/brand.ftl", "browser/aboutLogins.ftl"]);
});
XPCOMUtils.defineLazyServiceGetter( XPCOMUtils.defineLazyServiceGetter(
lazy, lazy,
"gParentalControlsService", "gParentalControlsService",
@@ -67,13 +71,6 @@ XPCOMUtils.defineLazyServiceGetter(
"nsIParentalControlsService" "nsIParentalControlsService"
); );
XPCOMUtils.defineLazyPreferenceGetter(
this,
"OS_AUTH_ENABLED",
"signon.management.page.os-auth.enabled",
true
);
XPCOMUtils.defineLazyPreferenceGetter( XPCOMUtils.defineLazyPreferenceGetter(
this, this,
"gIsFirstPartyIsolated", "gIsFirstPartyIsolated",
@@ -1053,6 +1050,7 @@ var gPrivacyPane = {
this._initPasswordGenerationUI(); this._initPasswordGenerationUI();
this._initRelayIntegrationUI(); this._initRelayIntegrationUI();
this._initMasterPasswordUI(); this._initMasterPasswordUI();
this._initOSAuthentication();
this.initListenersForExtensionControllingPasswordManager(); this.initListenersForExtensionControllingPasswordManager();
@@ -2863,8 +2861,7 @@ var gPrivacyPane = {
// OS reauthenticate functionality is not available on Linux yet (bug 1527745) // OS reauthenticate functionality is not available on Linux yet (bug 1527745)
if ( if (
!LoginHelper.isPrimaryPasswordSet() && !LoginHelper.isPrimaryPasswordSet() &&
OS_AUTH_ENABLED && LoginHelper.getOSAuthEnabled(LoginHelper.OS_AUTH_FOR_PASSWORDS_PREF)
OSKeyStore.canReauth()
) { ) {
// Uses primary-password-os-auth-dialog-message-win and // Uses primary-password-os-auth-dialog-message-win and
// primary-password-os-auth-dialog-message-macosx via concatenation: // primary-password-os-auth-dialog-message-macosx via concatenation:
@@ -2961,6 +2958,54 @@ var gPrivacyPane = {
this._updateRelayIntegrationUI(); this._updateRelayIntegrationUI();
}, },
async _toggleOSAuth() {
let osReauthCheckbox = document.getElementById("osReauthCheckbox");
const messageText = await lazy.AboutLoginsL10n.formatValue(
"about-logins-os-auth-dialog-message"
);
const captionText = await lazy.AboutLoginsL10n.formatValue(
"about-logins-os-auth-dialog-caption"
);
let win =
osReauthCheckbox.ownerGlobal.docShell.chromeEventHandler.ownerGlobal;
// Calling OSKeyStore.ensureLoggedIn() instead of LoginHelper.verifyOSAuth()
// since we want to authenticate user each time this stting is changed.
let isAuthorized = (
await OSKeyStore.ensureLoggedIn(messageText, captionText, win, false)
).authenticated;
if (!isAuthorized) {
osReauthCheckbox.checked = !osReauthCheckbox.checked;
return;
}
// If osReauthCheckbox is checked enable osauth.
LoginHelper.setOSAuthEnabled(
LoginHelper.OS_AUTH_FOR_PASSWORDS_PREF,
osReauthCheckbox.checked
);
},
_initOSAuthentication() {
let osReauthCheckbox = document.getElementById("osReauthCheckbox");
if (!OSKeyStore.canReauth()) {
osReauthCheckbox.hidden = true;
return;
}
osReauthCheckbox.setAttribute(
"checked",
LoginHelper.getOSAuthEnabled(LoginHelper.OS_AUTH_FOR_PASSWORDS_PREF)
);
setEventListener(
"osReauthCheckbox",
"command",
gPrivacyPane._toggleOSAuth.bind(gPrivacyPane)
);
},
/** /**
* Shows the sites where the user has saved passwords and the associated login * Shows the sites where the user has saved passwords and the associated login
* information. * information.

View File

@@ -134,12 +134,20 @@ login-item-timeline-action-used = Used
## OS Authentication dialog ## OS Authentication dialog
about-logins-os-auth-dialog-caption = { -brand-full-name }
## The macOS strings are preceded by the operating system with "Firefox is trying to " ## The macOS strings are preceded by the operating system with "Firefox is trying to "
## and includes subtitle of "Enter password for the user "xxx" to allow this." These ## and includes subtitle of "Enter password for the user "xxx" to allow this." These
## notes are only valid for English. Please test in your respected locale. ## notes are only valid for English. Please test in your respected locale.
# The macOS strings are preceded by the operating system with "Firefox is trying to ".
# This message can be seen when attempting to disable osauth in about:preferences.
about-logins-os-auth-dialog-message=
{ PLATFORM() ->
[macos] change the settings for passwords
*[other] { -brand-short-name } is trying to change the settings for passwords. Use your device sign in to allow this.
}
about-logins-os-auth-dialog-caption = { -brand-full-name }
# This message can be seen when attempting to edit a login in about:logins on Windows. # This message can be seen when attempting to edit a login in about:logins on Windows.
about-logins-edit-login-os-auth-dialog-message2-win = To edit your password, enter your Windows login credentials. This helps protect the security of your accounts. about-logins-edit-login-os-auth-dialog-message2-win = To edit your password, enter your Windows login credentials. This helps protect the security of your accounts.
# This message can be seen when attempting to edit a login in about:logins # This message can be seen when attempting to edit a login in about:logins

View File

@@ -1036,6 +1036,9 @@ forms-saved-passwords =
forms-primary-pw-use = forms-primary-pw-use =
.label = Use a Primary Password .label = Use a Primary Password
.accesskey = U .accesskey = U
# This operation requires the user to authenticate with the operating system (device sign-in)
forms-os-reauth =
.label = Require device sign in to fill and manage passwords
forms-primary-pw-learn-more-link = Learn more forms-primary-pw-learn-more-link = Learn more
# This string uses the former name of the Primary Password feature # This string uses the former name of the Primary Password feature
# ("Master Password" in English) so that the preferences can be found # ("Master Password" in English) so that the preferences can be found

View File

@@ -373,7 +373,7 @@ class ImportRowProcessor {
return this.summary; return this.summary;
} }
} }
const OS_AUTH_FOR_PASSWORDS_PREF = "signon.management.page.os-auth.optout";
/** /**
* Contains functions shared by different Login Manager components. * Contains functions shared by different Login Manager components.
*/ */
@@ -401,6 +401,7 @@ export const LoginHelper = {
testOnlyUserHasInteractedWithDocument: null, testOnlyUserHasInteractedWithDocument: null,
userInputRequiredToCapture: null, userInputRequiredToCapture: null,
captureInputChanges: null, captureInputChanges: null,
OS_AUTH_FOR_PASSWORDS_PREF,
init() { init() {
// Watch for pref changes to update cached pref values. // Watch for pref changes to update cached pref values.
@@ -1728,18 +1729,21 @@ export const LoginHelper = {
} }
// Use the OS auth dialog if there is no primary password // Use the OS auth dialog if there is no primary password
if (!token.hasPassword && OSReauthEnabled) { if (!token.hasPassword && OSReauthEnabled) {
let result = await lazy.OSKeyStore.ensureLoggedIn( let isAuthorized = await this.verifyUserOSAuth(
OS_AUTH_FOR_PASSWORDS_PREF,
messageText, messageText,
captionText, captionText,
browser.ownerGlobal, browser.ownerGlobal,
false false
); );
isAuthorized = result.authenticated; let value = lazy.OSKeyStore.canReauth()
? "success"
: "success_unsupported_platform";
telemetryEvent = { telemetryEvent = {
object: "os_auth", object: "os_auth",
method: "reauthenticate", method: "reauthenticate",
value: result.auth_details, value: isAuthorized ? value : "fail",
extra: result.auth_details_extra,
}; };
return { return {
isAuthorized, isAuthorized,