Bug 1493249 - Add policy for security devices. r=Felipe
authorMichael Kaply <mozilla@kaply.com>
Tue, 02 Oct 2018 03:47:17 +0000
changeset 494839 86baeb291e666af5a6a981898401521d0ec06bd1
parent 494838 c4a515cf1d8fb6e422a09adb0c807ab240ec6e03
child 494840 425d54d1ad00d4c6f13bee902311c10de82cac4f
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersFelipe
bugs1493249
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1493249 - Add policy for security devices. r=Felipe Differential Revision: https://phabricator.services.mozilla.com/D6525
browser/components/enterprisepolicies/EnterprisePolicies.js
browser/components/enterprisepolicies/Policies.jsm
browser/components/enterprisepolicies/schemas/policies-schema.json
toolkit/components/utils/JsonSchemaValidator.jsm
toolkit/components/utils/test/browser/browser_JsonSchemaValidator.js
--- a/browser/components/enterprisepolicies/EnterprisePolicies.js
+++ b/browser/components/enterprisepolicies/EnterprisePolicies.js
@@ -132,17 +132,17 @@ EnterprisePoliciesManager.prototype = {
                                 this, /* the EnterprisePoliciesManager */
                                 parsedParameters));
         }
       }
     }
   },
 
   _callbacks: {
-    // The earlist that a policy callback can run. This will
+    // The earliest that a policy callback can run. This will
     // happen right after the Policy Engine itself has started,
     // and before the Add-ons Manager has started.
     onBeforeAddons: [],
 
     // This happens after all the initialization related to
     // the profile has finished (prefs, places database, etc.).
     onProfileAfterChange: [],
 
--- a/browser/components/enterprisepolicies/Policies.jsm
+++ b/browser/components/enterprisepolicies/Policies.jsm
@@ -749,16 +749,35 @@ var Policies = {
               }
             }
           });
         }
       });
     },
   },
 
+  "SecurityDevices": {
+    onProfileAfterChange(manager, param) {
+      let securityDevices = param;
+      runOncePerModification("securityDevices",
+                             JSON.stringify(securityDevices),
+                             () => {
+        let pkcs11 = Cc["@mozilla.org/security/pkcs11moduledb;1"].getService(Ci.nsIPKCS11ModuleDB);
+        for (let deviceName in securityDevices) {
+          try {
+            pkcs11.addModule(deviceName, securityDevices[deviceName], 0, 0);
+          } catch (ex) {
+            log.error("Unable to add security device ${deviceName}");
+            log.debug(ex);
+          }
+        }
+      });
+    },
+  },
+
   "WebsiteFilter": {
     onBeforeUIStartup(manager, param) {
       this.filter = new WebsiteFilter(param.Block || [], param.Exceptions || []);
     },
   },
 
 };
 
--- a/browser/components/enterprisepolicies/schemas/policies-schema.json
+++ b/browser/components/enterprisepolicies/schemas/policies-schema.json
@@ -627,16 +627,23 @@
           "type": "array",
           "items": {
             "type": "string"
           }
         }
       }
     },
 
+    "SecurityDevices": {
+      "type": "object",
+      "patternProperties": {
+        "^.*$": { "type": "string" }
+      }
+    },
+
     "WebsiteFilter": {
       "machine_only": "true",
 
       "type": "object",
       "properties": {
         "Block": {
           "type": "array",
           "items": {
--- a/toolkit/components/utils/JsonSchemaValidator.jsm
+++ b/toolkit/components/utils/JsonSchemaValidator.jsm
@@ -103,36 +103,62 @@ function validateAndParseParamRecursive(
 
     case "object": {
       if (typeof(param) != "object") {
         log.error("Object expected but not received");
         return [false, null];
       }
 
       let parsedObj = {};
-      for (let property of Object.keys(properties.properties)) {
-        log.debug(`in object, checking\n    property: ${property}\n    value: ${param[property]}\n    expected type: ${properties.properties[property].type}`);
+      let patternProperties = [];
+      if ("patternProperties" in properties) {
+        for (let propName of Object.keys(properties.patternProperties || {})) {
+          let pattern;
+          try {
+            pattern = new RegExp(propName);
+          } catch (e) {
+            throw new Error(`Internal error: Invalid property pattern ${propName}`);
+          }
+          patternProperties.push({
+            pattern,
+            schema: properties.patternProperties[propName],
+          });
+        }
+      }
 
-        if (!param.hasOwnProperty(property)) {
-          if (properties.required && properties.required.includes(property)) {
-            log.error(`Object is missing required property ${property}`);
+      if (properties.required) {
+        for (let required of properties.required) {
+          if (!(required in param)) {
+            log.error(`Object is missing required property ${required}`);
             return [false, null];
           }
-          continue;
         }
-
-        let [valid, parsedValue] = validateAndParseParamRecursive(param[property], properties.properties[property]);
-
-        if (!valid) {
-          return [false, null];
-        }
-
-        parsedObj[property] = parsedValue;
       }
 
+      for (let item of Object.keys(param)) {
+        let schema;
+        if ("properties" in properties &&
+            properties.properties.hasOwnProperty(item)) {
+          schema = properties.properties[item];
+        } else if (patternProperties.length) {
+          for (let patternProperty of patternProperties) {
+            if (patternProperty.pattern.test(item)) {
+              schema = patternProperty.schema;
+              break;
+            }
+          }
+        }
+        if (schema) {
+          let [valid, parsedValue] = validateAndParseParamRecursive(param[item], schema);
+          if (!valid) {
+            return [false, null];
+          }
+          parsedObj[item] = parsedValue;
+        }
+      }
       return [true, parsedObj];
     }
   }
 
   return [false, null];
 }
 
 function validateAndParseSimpleParam(param, type) {
--- a/toolkit/components/utils/test/browser/browser_JsonSchemaValidator.js
+++ b/toolkit/components/utils/test/browser/browser_JsonSchemaValidator.js
@@ -391,8 +391,59 @@ add_task(async function test_number_or_a
   // Invalid values:
   ok(!JsonSchemaValidator.validateAndParseParameters(true, schema)[0], "Invalid value");
   ok(!JsonSchemaValidator.validateAndParseParameters({}, schema)[0], "Invalid value");
   ok(!JsonSchemaValidator.validateAndParseParameters(null, schema)[0], "Invalid value");
   ok(!JsonSchemaValidator.validateAndParseParameters(["a", "b"], schema)[0], "Invalid value");
   ok(!JsonSchemaValidator.validateAndParseParameters([[]], schema)[0], "Invalid value");
   ok(!JsonSchemaValidator.validateAndParseParameters([0, 1, [2, 3]], schema)[0], "Invalid value");
 });
+
+add_task(async function test_patternProperties() {
+  let schema = {
+    type: "object",
+    properties: {
+      "S-bool-property": { "type": "boolean" },
+    },
+    patternProperties: {
+      "^S-": { "type": "string" },
+      "^N-": { "type": "number" },
+      "^B-": { "type": "boolean" },
+    },
+  };
+
+  let valid, parsed;
+  [valid, parsed] = JsonSchemaValidator.validateAndParseParameters({
+    "S-string": "test",
+    "N-number": 5,
+    "B-boolean": true,
+    "S-bool-property": false,
+  }, schema);
+
+  ok(valid, "Object is valid");
+  is(parsed["S-string"], "test", "parsedProperty is correct");
+  is(parsed["N-number"], 5, "parsedProperty is correct");
+  is(parsed["B-boolean"], true, "parsedProperty is correct");
+  is(parsed["S-bool-property"], false, "property is correct");
+
+  [valid, parsed] = JsonSchemaValidator.validateAndParseParameters({
+    "N-string": "test",
+  }, schema);
+
+  ok(!valid, "Object is not valid since there is a type mismatch");
+
+  [valid, parsed] = JsonSchemaValidator.validateAndParseParameters({
+    "S-number": 5,
+  }, schema);
+
+  ok(!valid, "Object is not valid since there is a type mismatch");
+
+  schema = {
+    type: "object",
+    patternProperties: {
+      "[": {" type": "string" },
+    },
+  };
+
+  Assert.throws(() => {
+    [valid, parsed] = JsonSchemaValidator.validateAndParseParameters({}, schema);
+  }, /Invalid property pattern/, "Checking that invalid property patterns throw");
+});