Bug 1429148 - Policy: Don't let a Master Password to be set. r=MattN,keeler draft
authorFelipe Gomes <felipc@gmail.com>
Tue, 20 Feb 2018 20:46:11 -0300
changeset 757640 95bfce8e2bdc44fbd6fde33da82219a9a762674d
parent 757639 17372be75d6722fe92582087d7297e91e6de3ceb
push id99816
push userfelipc@gmail.com
push dateTue, 20 Feb 2018 23:48:38 +0000
reviewersMattN, keeler
bugs1429148
milestone60.0a1
Bug 1429148 - Policy: Don't let a Master Password to be set. r=MattN,keeler MozReview-Commit-ID: 8Adqg0KU7cZ
browser/components/enterprisepolicies/Policies.jsm
browser/components/enterprisepolicies/helpers/sample.json
browser/components/enterprisepolicies/schemas/policies-schema.json
browser/components/enterprisepolicies/tests/browser/browser.ini
browser/components/enterprisepolicies/tests/browser/browser_policy_disable_masterpassword.js
browser/components/preferences/in-content/privacy.js
security/manager/pki/resources/content/device_manager.js
--- a/browser/components/enterprisepolicies/Policies.jsm
+++ b/browser/components/enterprisepolicies/Policies.jsm
@@ -74,16 +74,24 @@ this.Policies = {
   "block_set_desktop_background": {
     onBeforeUIStartup(manager, param) {
       if (param == true) {
         manager.disallowFeature("setDesktopBackground", true);
       }
     }
   },
 
+  "CreateMasterPassword": {
+    onBeforeUIStartup(manager, param) {
+      if (!param) {
+        manager.disallowFeature("createMasterPassword");
+      }
+    }
+  },
+
   "DisableFirefoxScreenshots": {
     onBeforeAddons(manager, param) {
       if (param == true) {
         setAndLockPref("extensions.screenshots.disabled", true);
       }
     }
   },
 
--- a/browser/components/enterprisepolicies/helpers/sample.json
+++ b/browser/components/enterprisepolicies/helpers/sample.json
@@ -8,11 +8,12 @@
         "https://www.example.com"
       ],
 
       "block": [
         "https://www.example.org"
       ]
     },
 
-    "block_about_profiles": true
+    "block_about_profiles": true,
+    "CreateMasterPassword": false
   }
 }
--- a/browser/components/enterprisepolicies/schemas/policies-schema.json
+++ b/browser/components/enterprisepolicies/schemas/policies-schema.json
@@ -29,16 +29,24 @@
     "block_set_desktop_background": {
       "description": "Prevents usage of the \"Set Image as Desktop Background\" feature.",
       "first_available": "60.0",
 
       "type": "boolean",
       "enum": [true]
     },
 
+    "CreateMasterPassword": {
+      "description": "If false, removes access to create a master password.",
+      "first_available": "60.0",
+
+      "type": "boolean",
+      "enum": [false]
+    },
+
     "DisableFirefoxScreenshots": {
       "description": "Prevents usage of the Firefox Screenshots feature.",
       "first_available": "60.0",
 
       "type": "boolean",
       "enum": [true]
     },
 
--- a/browser/components/enterprisepolicies/tests/browser/browser.ini
+++ b/browser/components/enterprisepolicies/tests/browser/browser.ini
@@ -9,14 +9,15 @@ support-files =
 [browser_policies_broken_json.js]
 [browser_policies_popups_cookies_addons_flash.js]
 [browser_policies_setAndLockPref_API.js]
 [browser_policies_simple_policies.js]
 [browser_policies_validate_and_parse_API.js]
 [browser_policy_block_set_desktop_background.js]
 [browser_policy_default_browser_check.js]
 [browser_policy_disable_fxscreenshots.js]
+[browser_policy_disable_masterpassword.js]
 [browser_policy_display_bookmarks.js]
 [browser_policy_disable_formhistory.js]
 [browser_policy_display_menu.js]
 [browser_policy_disable_shield.js]
 [browser_policy_remember_passwords.js]
 
new file mode 100644
--- /dev/null
+++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_masterpassword.js
@@ -0,0 +1,79 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const MASTER_PASSWORD = "omgsecret!";
+const mpToken = Cc["@mozilla.org/security/pk11tokendb;1"]
+                  .getService(Ci.nsIPK11TokenDB)
+                  .getInternalKeyToken();
+
+async function checkDeviceManager({buttonIsDisabled}) {
+  let deviceManagerWindow = window.openDialog("chrome://pippki/content/device_manager.xul", "", "");
+  await new Promise(resolve => {
+    deviceManagerWindow.addEventListener("load", resolve, {once: true});
+  });
+
+  let tree = deviceManagerWindow.document.getElementById("device_tree");
+  ok(tree, "The device tree exists");
+
+  // Find and select the item related to the internal key token
+  for (let i = 0; i < tree.view.rowCount; i++) {
+    tree.view.selection.select(i);
+
+    try {
+      let selected_token = deviceManagerWindow.selected_slot.getToken();
+      if (selected_token.isInternalKeyToken) {
+        break;
+      }
+    } catch (e) {}
+  }
+
+  // Check to see if the button was updated correctly
+  let changePwButton = deviceManagerWindow.document.getElementById("change_pw_button");
+  is(changePwButton.getAttribute("disabled") == "true", buttonIsDisabled,
+     "Change Password button is in the correct state: " + buttonIsDisabled);
+
+  await BrowserTestUtils.closeWindow(deviceManagerWindow);
+}
+
+async function checkAboutPreferences({checkboxIsDisabled}) {
+  await BrowserTestUtils.withNewTab("about:preferences#privacy", async browser => {
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
+  is(browser.contentDocument.getElementById("useMasterPassword").disabled, checkboxIsDisabled,
+    "Master Password checkbox is in the correct state: " + checkboxIsDisabled);
+});
+
+}
+
+add_task(async function test_policy_disable_masterpassword() {
+  ok(!mpToken.hasPassword, "Starting the test with no password");
+
+  // No password and no policy: access to setting a master password
+  // should be enabled.
+  await checkDeviceManager({buttonIsDisabled: false});
+  await checkAboutPreferences({checkboxIsDisabled: false});
+
+  await setupPolicyEngineWithJson({
+    "policies": {
+      "CreateMasterPassword": false
+    }
+  });
+
+  // With the `CreateMasterPassword: false` policy active, the
+  // UI entry points for creating a Master Password should be disabled.
+  await checkDeviceManager({buttonIsDisabled: true});
+  await checkAboutPreferences({checkboxIsDisabled: true});
+
+  mpToken.changePassword("", MASTER_PASSWORD);
+  ok(mpToken.hasPassword, "Master password was set");
+
+  // If a Master Password is already set, there's no point in disabling
+  // the
+  await checkDeviceManager({buttonIsDisabled: false});
+  await checkAboutPreferences({checkboxIsDisabled: false});
+
+  // Clean up
+  mpToken.changePassword(MASTER_PASSWORD, "");
+  ok(!mpToken.hasPassword, "Master password was cleaned up");
+});
--- a/browser/components/preferences/in-content/privacy.js
+++ b/browser/components/preferences/in-content/privacy.js
@@ -1131,16 +1131,17 @@ var gPrivacyPane = {
   _initMasterPasswordUI() {
     var noMP = !LoginHelper.isMasterPasswordSet();
 
     var button = document.getElementById("changeMasterPassword");
     button.disabled = noMP;
 
     var checkbox = document.getElementById("useMasterPassword");
     checkbox.checked = !noMP;
+    checkbox.disabled = noMP && !Services.policies.isAllowed("createMasterPassword");
   },
 
   /**
    * Enables/disables the master password button depending on the state of the
    * "use master password" checkbox, and prompts for master password removal if
    * one is set.
    */
   updateMasterPasswordButton() {
--- a/security/manager/pki/resources/content/device_manager.js
+++ b/security/manager/pki/resources/content/device_manager.js
@@ -157,16 +157,22 @@ function enableButtons() {
         if (selected_token.needsLogin()) {
           if (selected_token.isLoggedIn()) {
             logout_toggle = "false";
           } else {
             login_toggle = "false";
           }
         }
       }
+
+      if (!Services.policies.isAllowed("createMasterPassword") &&
+          selected_token.isInternalKeyToken &&
+          !selected_token.hasPassword) {
+        pw_toggle = "true";
+      }
     }
     showSlotInfo();
   }
   document.getElementById("login_button")
           .setAttribute("disabled", login_toggle);
   document.getElementById("logout_button")
           .setAttribute("disabled", logout_toggle);
   document.getElementById("change_pw_button")