public void TestAnnotationFilenameSelection(string filename, bool expectedResult) { var piiProcessor = new PIIProcessing(_key); var target = new Entity("annotation") { Id = Guid.NewGuid(), ["name"] = "The name", ["deb_idnumber"] = "The id", ["documentbody"] = "The document body can be very very long", // ["birthdate"] = new DateTime(2019,1,25), ["name_encrypted"] = "The name encrypted", ["deb_idnumber_encrypted"] = "The ID encrypted", ["documentbody_encrypted"] = "The docbody encrypted", ["date_encrypted"] = "", ["filename"] = filename }; var original = target.Clone(); Entity preImage = null; var encrypted = piiProcessor.EncryptEntity(target, preImage, s => Debug.WriteLine(s)); Assert.IsTrue(original.Id.Equals(encrypted.Id)); if (expectedResult) { // Documentbody should encrypted Assert.IsTrue(original["documentbody"] != encrypted["documentbody"]); } else { // Documentbody should be un-encrypted Assert.IsFalse(original["documentbody"] == encrypted["documentbody"]); } }
public void TestNotEncryptedEntities() { var piiProcessor = new PIIProcessing(_key); var target = new Entity("nonencrypted") { Id = Guid.NewGuid(), ["name"] = "The name", ["deb_idnumber"] = "The id", ["documentbody"] = "The document body", ["date"] = new DateTime(2019, 1, 25), ["name_encrypted"] = "The name encrypted", ["deb_idnumber_encrypted"] = "The ID encrypted", ["documentbody_encrypted"] = "The docbody encrypted", ["date_encrypted"] = new DateTime(1900, 1, 1), }; var original = target.Clone(); Entity preImage = null; var encrypted = piiProcessor.EncryptEntity(target, preImage, s => Debug.WriteLine(s)); Assert.IsTrue(original.Id.Equals(encrypted.Id)); foreach (var attr in original.Attributes) { Assert.IsTrue(encrypted.Attributes.ContainsKey(attr.Key), $"Missing {attr.Key}"); Assert.IsTrue(attr.Value.Equals(encrypted.Attributes[attr.Key])); } }
public void TestSetupColumnSet() { var piiProcessor = new PIIProcessing(_key); var target = new Entity("contact") { Id = Guid.NewGuid(), ["name"] = "The name", ["deb_idnumber"] = "The id", ["documentbody"] = "The document body", ["birthdate"] = new DateTime(2019, 1, 25), ["name_encrypted"] = "The name encrypted", ["deb_idnumber_encrypted"] = "The ID encrypted", ["documentbody_encrypted"] = "The docbody encrypted", ["date_encrypted"] = "", }; var target2 = new Entity("annotation") { Id = Guid.NewGuid(), ["name"] = "Note", ["documentbody"] = "The document body" }; ColumnSetTest(piiProcessor, target.ToEntityReference(), new[] { "deb_idnumber" }, new[] { "deb_idnumber_encrypted" }); ColumnSetTest(piiProcessor, target2.ToEntityReference(), new[] { "documentbody" }); ColumnSetTest(piiProcessor, target.ToEntityReference(), new[] { "deb_idnumber", "birthdate" }, new[] { "deb_idnumber_encrypted", "deb_birthdate_encrypted" }); ColumnSetTest(piiProcessor, target2.ToEntityReference(), new [] { "name" }, null); }
private void EncryptPII(IPluginExecutionContext context, int stage, Action <string> trace) { if (!context.InputParameters.ContainsKey("Target")) { trace("PluginExecutionContext does not contain Target"); } else { var target = (Entity)context.InputParameters["Target"]; Entity preImage = null; if (context.PreEntityImages.ContainsKey("PreImage")) { preImage = context.PreEntityImages["PreImage"]; } var PIIProcessing = new PIIProcessing(encryptionKey); trace($"Message: {context.MessageName} Entity: {context.PrimaryEntityName}"); if ((context.MessageName == "Create" || context.MessageName == "Update") && stage == PreOperation) { PIIProcessing.EncryptEntity(target, preImage, trace); } else { trace($"Ignore this message: {context.MessageName} stage: {stage}"); } } }
public void TestLiveMayDecrypt() { // Assumes that the test user has "View Confidential Information" privilege, and that the "CRM Service" user does not have this privilege. var service = TestUtilities.TestUserService; var piiProcessor = new PIIProcessing(_key); var myUserId = Guid.Empty; FluentSystemUser.CurrentUser(service) .WeakExtract((Guid id) => myUserId = id, "systemuserid").Execute(); Assert.IsFalse(Guid.Empty.Equals(myUserId)); var otherUserId = Guid.Empty; FluentSystemUser.SystemUser(service) .Trace(s => Debug.WriteLine(s)) .Where("fullname").Equals("CRM Service").WeakExtract((Guid id) => otherUserId = id, "systemuserid") .Execute(); Assert.IsFalse(Guid.Empty.Equals(otherUserId)); var result = piiProcessor.MayDecrypt(myUserId, service); Assert.IsTrue(result); result = piiProcessor.MayDecrypt(otherUserId, service); Assert.IsFalse(result); }
public void TestDateEncryption() { var piiProcessor = new PIIProcessing(_key); var target = new Entity("contact") { Id = Guid.NewGuid(), ["name"] = "The name", ["deb_idnumber"] = "The id", ["documentbody"] = "The document body", ["birthdate"] = new DateTime(2019, 1, 25), ["name_encrypted"] = "The name encrypted", ["deb_idnumber_encrypted"] = "The ID encrypted", ["documentbody_encrypted"] = "The docbody encrypted", ["date_encrypted"] = "", }; var original = target.Clone(); var encrypted = piiProcessor.EncryptEntity(target, null, s => Debug.WriteLine(s)); Assert.IsTrue(original.Id.Equals(encrypted.Id)); foreach (var attr in new[] { "name", "documentbody", "name_encrypted", "documentbody_encrypted" }) { Debug.WriteLine($"Attribute: {attr}"); Assert.IsTrue(encrypted.Attributes.ContainsKey(attr), $"Missing {attr}"); Assert.IsTrue(original.Attributes[attr].Equals(encrypted.Attributes[attr])); } Assert.AreEqual("******", encrypted.Attributes["deb_idnumber"]); Assert.AreNotEqual("The ID Encrypted", encrypted.Attributes["deb_idnumber_encrypted"]); Assert.AreEqual(new DateTime(1900, 1, 1), encrypted.Attributes["birthdate"]); Assert.AreNotEqual("The ID Encrypted", encrypted.Attributes["deb_birthdate_encrypted"]); Debug.WriteLine(encrypted.GetAttributeValue <string>("deb_birthdate_encrypted")); // Now decrypt the encrypted entity. var decrypted = piiProcessor.DecryptEntity(target, s => Debug.WriteLine(s)); // Assert that deb_idnumber (and other fields) should be as they were. foreach (var attr in new[] { "name", "documentbody", "name_encrypted", "documentbody_encrypted", "deb_idnumber", "birthdate" }) { Debug.WriteLine($"Attribute: {attr}"); Assert.IsTrue(decrypted.Attributes.ContainsKey(attr), $"Missing {attr}"); if (!original.Attributes[attr].Equals(decrypted.Attributes[attr])) { Assert.IsTrue(original.Attributes[attr].Equals(decrypted.Attributes[attr])); } } Assert.AreNotEqual("The ID Encrypted", encrypted.Attributes["deb_birthdate_encrypted"]); Assert.AreEqual(decrypted.Attributes["deb_birthdate_encrypted"], encrypted.Attributes["deb_birthdate_encrypted"]); }
/// <summary> /// Update the column set parameter directly. /// </summary> /// <param name="context"></param> /// <param name="trace"></param> private void UpdateColumnSet(IPluginExecutionContext context, PIIProcessing PIIProcessing, Action <string> trace) { if (!context.InputParameters.ContainsKey("ColumnSet") || !context.InputParameters.ContainsKey("Target")) { trace("Input parameters for Retrieve does not contain ColumnSet or Target"); } else { var colSet = (ColumnSet)context.InputParameters["ColumnSet"]; var target = (EntityReference)context.InputParameters["Target"]; trace("Adding encrypted columns to columnSet"); PIIProcessing.AddAdditionalColumns(target, colSet, trace); } }
// Update the column set in the associated query. private void UpdateColumnSetInQuery(IPluginExecutionContext context, PIIProcessing PIIProcessing, Action <string> trace) { if (!(context.InputParameters.ContainsKey("Query") && context.InputParameters["Query"] is QueryExpression)) { trace("Input parameters for RetrieveMultiple does not contain Query or is not QueryExpression"); } else { var query = (QueryExpression)context.InputParameters["Query"]; var colSet = query.ColumnSet; var target = new EntityReference(query.EntityName, Guid.Empty); trace("Adding encrypted columns to query columnSet"); PIIProcessing.AddAdditionalColumns(target, colSet, trace); } }
public void TestAnnotationEncryption() { var piiProcessor = new PIIProcessing(_key); var target = new Entity("annotation") { Id = Guid.NewGuid(), ["name"] = "The name", ["deb_idnumber"] = "The id", ["documentbody"] = "The document body can be very very long", // ["birthdate"] = new DateTime(2019,1,25), ["name_encrypted"] = "The name encrypted", ["deb_idnumber_encrypted"] = "The ID encrypted", ["documentbody_encrypted"] = "The docbody encrypted", ["date_encrypted"] = "", }; var original = target.Clone(); var preImage = new Entity("annotation") { ["filename"] = "PersonalID.jpg" }; var encrypted = piiProcessor.EncryptEntity(target, preImage, s => Debug.WriteLine(s)); Assert.IsTrue(original.Id.Equals(encrypted.Id)); foreach (var attr in new[] { "name", "deb_idnumber", "name_encrypted", "documentbody_encrypted", "deb_idnumber_encrypted" }) { Debug.WriteLine($"Attribute: {attr}"); Assert.IsTrue(encrypted.Attributes.ContainsKey(attr), $"Missing {attr}"); Assert.IsTrue(original.Attributes[attr].Equals(encrypted.Attributes[attr])); } Assert.AreNotEqual(original.Attributes["documentbody"], encrypted.Attributes["documentbody"]); // Now decrypt the encrypted entity. var decrypted = piiProcessor.DecryptEntity(target, s => Debug.WriteLine(s)); // Assert that deb_idnumber (and other fields) should be as they were. foreach (var attr in original.Attributes.Keys) { Debug.WriteLine($"Attribute: {attr}"); Assert.IsTrue(encrypted.Attributes.ContainsKey(attr), $"Missing {attr}"); Assert.IsTrue(original.Attributes[attr].Equals(encrypted.Attributes[attr])); } }
private void DecryptPIIForSingleEntity(LocalPluginContext localContext, int stage, Action <string> trace, IPluginExecutionContext context) { if (!context.OutputParameters.ContainsKey("BusinessEntity")) { trace("PluginExecutionContext does not contain BusinessEntity in OutputParameters"); } else { var target = (Entity)context.OutputParameters["BusinessEntity"]; var PIIProcessing = new PIIProcessing(encryptionKey); if (stage == PostOperation) { PIIProcessing.DecryptEntity(target, trace); } } }
private void ColumnSetTest(PIIProcessing processor, EntityReference target, string[] initial, string[] added = null) { var columnSet = new ColumnSet(initial); var expectedColumnSet = new HashSet <string>(initial); if (added != null) { added.ForEach((a, i) => expectedColumnSet.Add((string)a.GetValue(i))); } processor.AddAdditionalColumns(target, columnSet, s => Debug.WriteLine(s)); Assert.AreEqual(expectedColumnSet.Count, columnSet.Columns.Count); foreach (var s in expectedColumnSet) { Assert.IsTrue(columnSet.Columns.Contains(s), $"Columnset did not contain expected value {s}"); } foreach (var s in columnSet.Columns) { Assert.IsTrue(expectedColumnSet.Contains(s), $"Columnset contained unexpected value {s}"); } }
/// <summary> /// Ensure that we are also retrieving the encrypted columns (for decryption during post-operation phase) /// Note that Retrieve and RetrieveMultiple have different approaches to specifying the columnset. /// Retrieve has a "ColumnSet" parameter in the InputParameters collection. /// RetrieveMultiple has a "Query" parameter in the Input Parameters collection - this is a QueryExpression and the column set is elsewhere. /// Also avoid adding the extra columns if the user does not have privilege to decrypt - and store MayDecrypt setting in a shared Variable. /// </summary> /// <param name="context"></param> /// <param name="trace"></param> private void AddEncryptedColsToRetreivedCols(LocalPluginContext context, Action <string> trace) { var PIIProcessing = new PIIProcessing(encryptionKey); var pluginContext = context.PluginExecutionContext; if (PIIProcessing.MayDecrypt(pluginContext.UserId, context.OrganizationService, trace)) { pluginContext.SharedVariables.Add(MayDecrypt, true); if (pluginContext.MessageName == "Retrieve") { UpdateColumnSet(pluginContext, PIIProcessing, trace); } else { UpdateColumnSetInQuery(pluginContext, PIIProcessing, trace); } } else { pluginContext.SharedVariables.Add(MayDecrypt, false); } }
public void TestMayDecrypt() { var piiProcessor = new PIIProcessing(_key); var userId = Guid.NewGuid(); #region "Setup fake" var user = new Entity("systemuser") { Id = userId }; var securityRole = new Entity("role") { Id = Guid.NewGuid(), ["name"] = "View Confidential Information" }; var systemUserRole = new Entity("systemuserroles") { Id = Guid.NewGuid(), ["roleid"] = securityRole.Id, ["systemuserid"] = userId }; var context = new XrmFakedContext(); context.Initialize(new List <Entity>() { user, securityRole, systemUserRole }); #endregion var result = piiProcessor.MayDecrypt(userId, context.GetOrganizationService()); Assert.IsTrue(result); result = piiProcessor.MayDecrypt(Guid.NewGuid(), context.GetOrganizationService()); Assert.IsFalse(result); }