forked from WaelHamze/xrm-ci-framework
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added feature to manage encrypted CRM connections in json config
- Loading branch information
Showing
14 changed files
with
705 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
56 changes: 56 additions & 0 deletions
56
.../Xrm.Framework.CI/Xrm.Framework.CI.Common.IntegrationTests/ConnectionConfigManagerTest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
using System; | ||
using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
using Xrm.Framework.CI.Common.IntegrationTests.Logging; | ||
|
||
namespace Xrm.Framework.CI.Common.IntegrationTests | ||
{ | ||
[TestClass] | ||
public class ConnectionConfigManagerTest | ||
{ | ||
public TestContext TestContext | ||
{ | ||
get; | ||
set; | ||
} | ||
|
||
[TestMethod] | ||
public void TestConnection() | ||
{ | ||
string config = $"{TestContext.TestLogsDir}\\connections.json"; | ||
|
||
TestLogger logger = new TestLogger(); | ||
XrmEncryptionManager encryption = new XrmEncryptionManager(logger); | ||
XrmConnectionConfigManager manager = new XrmConnectionConfigManager(logger, encryption, config); | ||
|
||
string con1 = "AuthType=Office365;[email protected];Password=passwork;Url=https://name1.crmregion.dynamics.com"; | ||
string key1 = "crm1"; | ||
|
||
string con2 = "AuthType=Office365;[email protected];Password=passwork;Url=https://name2.crmregion.dynamics.com"; | ||
string key2 = "crm2"; | ||
|
||
Assert.AreEqual(manager.GetConnections().Count, 0); | ||
|
||
manager.SetConnection(key1, con1); | ||
|
||
Assert.AreEqual(con1, manager.GetConnection(key1)); | ||
|
||
manager.SetConnection(key2, con2); | ||
|
||
Assert.AreEqual(con2, manager.GetConnection(key2)); | ||
Assert.AreEqual(manager.GetConnections().Count, 2); | ||
Assert.AreEqual(manager.GetConnections()[0], key1); | ||
Assert.AreEqual(manager.GetConnections()[1], key2); | ||
|
||
manager.RemoveConnection(key1); | ||
|
||
Assert.AreEqual(manager.GetConnections().Count, 1); | ||
Assert.AreEqual(null, manager.GetConnection(key1)); | ||
Assert.AreEqual(con2, manager.GetConnection(key2)); | ||
|
||
manager.RemoveConnection(key2); | ||
|
||
Assert.AreEqual(null, manager.GetConnection(key2)); | ||
Assert.AreEqual(manager.GetConnections().Count, 0); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
197 changes: 197 additions & 0 deletions
197
MSDYNV9/Xrm.Framework.CI/Xrm.Framework.CI.Common/XrmConnectionConfigManager.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using Xrm.Framework.CI.Common.Logging; | ||
|
||
namespace Xrm.Framework.CI.Common | ||
{ | ||
public class XrmConnectionConfigManager | ||
{ | ||
#region Properties | ||
|
||
protected ILogger Logger | ||
{ | ||
get; | ||
set; | ||
} | ||
|
||
protected IXrmEncryption Encryption | ||
{ | ||
get; | ||
set; | ||
} | ||
|
||
public string ConfigPath | ||
{ | ||
get; | ||
private set; | ||
} | ||
|
||
internal XrmConnectionInfoList ConnectionList | ||
{ | ||
get; | ||
set; | ||
} | ||
|
||
#endregion | ||
|
||
#region Constructors | ||
|
||
public XrmConnectionConfigManager(ILogger logger, IXrmEncryption encryption, string configPath) | ||
{ | ||
Logger = logger; | ||
Encryption = encryption; | ||
|
||
if (!String.IsNullOrEmpty(configPath)) | ||
{ | ||
ConfigPath = configPath; | ||
} | ||
else | ||
{ | ||
ConfigPath = GetTempConfig(); | ||
} | ||
Init(); | ||
} | ||
|
||
#endregion | ||
|
||
#region Methods | ||
|
||
public void SetConnection(string key, string connectionString) | ||
{ | ||
string encryptedValue = Encryption.Encrypt(connectionString); | ||
|
||
XrmConnectionInfo info = FindConnection(key); | ||
|
||
if (info != null) | ||
{ | ||
info.Value = encryptedValue; | ||
} | ||
else | ||
{ | ||
ConnectionList.Connections.Add(new XrmConnectionInfo | ||
{ | ||
Key = key, | ||
Value = encryptedValue | ||
}); | ||
} | ||
|
||
SaveList(); | ||
} | ||
|
||
public void RemoveConnection(string key) | ||
{ | ||
XrmConnectionInfo info = FindConnection(key); | ||
|
||
if (info != null) | ||
{ | ||
ConnectionList.Connections.Remove(info); | ||
SaveList(); | ||
} | ||
else | ||
{ | ||
throw new Exception($"No connection found with key: {key}"); | ||
} | ||
} | ||
|
||
public string GetConnection(string key) | ||
{ | ||
XrmConnectionInfo found = FindConnection(key); | ||
|
||
if (found != null) | ||
{ | ||
return Encryption.Decrypt(found.Value); | ||
} | ||
else | ||
{ | ||
return null; | ||
} | ||
} | ||
|
||
public List<string> GetConnections() | ||
{ | ||
return (from c in ConnectionList.Connections | ||
select c.Key).ToList<string>(); | ||
|
||
} | ||
|
||
private string GetTempConfig() | ||
{ | ||
string tempFolder = Path.GetTempPath(); | ||
string configFolder = Path.Combine(tempFolder, "xRMCIFramework"); | ||
if (!Directory.Exists(configFolder)) | ||
{ | ||
Directory.CreateDirectory(configFolder); | ||
} | ||
string configFile = "connections.json"; | ||
|
||
return Path.Combine(configFolder, configFile); | ||
} | ||
|
||
private void Init() | ||
{ | ||
if (!File.Exists(ConfigPath)) | ||
{ | ||
ConnectionList = new XrmConnectionInfoList(); | ||
SaveList(); | ||
} | ||
else | ||
{ | ||
LoadList(); | ||
} | ||
} | ||
|
||
private XrmConnectionInfo FindConnection(string key) | ||
{ | ||
var c = from cons in ConnectionList.Connections | ||
where cons.Key == key | ||
select cons; | ||
|
||
List<XrmConnectionInfo> found = c.ToList<XrmConnectionInfo>(); | ||
|
||
if (found.Count > 1) | ||
{ | ||
throw new Exception($"More than one connection found with key: {key}"); | ||
} | ||
else if (found.Count == 1) | ||
{ | ||
return found[0]; | ||
} | ||
else | ||
{ | ||
return null; | ||
} | ||
} | ||
|
||
private void SaveList() | ||
{ | ||
Serializers.SaveJson<XrmConnectionInfoList>(ConfigPath, ConnectionList); | ||
} | ||
|
||
private void LoadList() | ||
{ | ||
ConnectionList = Serializers.ParseJson<XrmConnectionInfoList>(ConfigPath); | ||
} | ||
|
||
#endregion | ||
} | ||
|
||
public class XrmConnectionInfo | ||
{ | ||
public string Key { get; set; } | ||
public string Value { get; set; } | ||
} | ||
|
||
internal class XrmConnectionInfoList | ||
{ | ||
public List<XrmConnectionInfo> Connections { get; set; } | ||
|
||
public XrmConnectionInfoList() | ||
{ | ||
Connections = new List<XrmConnectionInfo>(); | ||
} | ||
} | ||
} |
85 changes: 85 additions & 0 deletions
85
MSDYNV9/Xrm.Framework.CI/Xrm.Framework.CI.Common/XrmEncryptionManager.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Security.Cryptography; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using Xrm.Framework.CI.Common.Logging; | ||
|
||
namespace Xrm.Framework.CI.Common | ||
{ | ||
public interface IXrmEncryption | ||
{ | ||
string Encrypt(string secret); | ||
string Decrypt(string encryptedSecret); | ||
} | ||
|
||
public class XrmEncryptionManager : IXrmEncryption | ||
{ | ||
#region Properties | ||
|
||
protected ILogger Logger | ||
{ | ||
get; | ||
set; | ||
} | ||
|
||
#endregion | ||
|
||
#region Constructors | ||
|
||
public XrmEncryptionManager(ILogger logger ) | ||
{ | ||
Logger = logger; | ||
} | ||
|
||
#endregion | ||
|
||
#region Methods | ||
|
||
public string Encrypt(string secret) | ||
{ | ||
Logger.LogVerbose("Ecrypting secret"); | ||
|
||
if (string.IsNullOrEmpty(secret)) | ||
{ | ||
throw new Exception("secret can't be empty"); | ||
} | ||
|
||
byte[] bytes = Encoding.Default.GetBytes(secret); | ||
|
||
byte[] encryptedBytes = ProtectedData.Protect(bytes, (byte[])null, DataProtectionScope.CurrentUser); | ||
|
||
string encryptedSecret = BitConverter.ToString(encryptedBytes).Replace("-", ""); | ||
|
||
Logger.LogVerbose("Secret encrypted"); | ||
|
||
return encryptedSecret; | ||
} | ||
|
||
public string Decrypt(string encryptedSecret) | ||
{ | ||
Logger.LogVerbose("Decrypting secret"); | ||
|
||
byte[] encryptedBytes = StringToByteArray(encryptedSecret); | ||
|
||
byte[] bytes = ProtectedData.Unprotect(encryptedBytes, (byte[])null, DataProtectionScope.CurrentUser); | ||
|
||
string secret = Encoding.Default.GetString(bytes); | ||
|
||
Logger.LogVerbose("Decryptings secret"); | ||
|
||
return secret; | ||
} | ||
|
||
private static byte[] StringToByteArray(string hex) | ||
{ | ||
return Enumerable.Range(0, hex.Length) | ||
.Where(x => x % 2 == 0) | ||
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) | ||
.ToArray(); | ||
} | ||
|
||
#endregion | ||
} | ||
} |
Oops, something went wrong.