mirror of
https://github.com/mRemoteNG/mRemoteNG.git
synced 2026-02-17 22:11:48 +08:00
sql now encrypts and decrypts passwords
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using System.Security;
|
||||
using mRemoteNG.Config.Serializers.MsSql;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNGTests.TestHelpers;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers
|
||||
@@ -13,30 +14,37 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
public class DataTableDeserializerTests
|
||||
{
|
||||
private DataTableDeserializer _deserializer;
|
||||
private ICryptographyProvider _cryptographyProvider;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_cryptographyProvider = new LegacyRijndaelCryptographyProvider();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WeCanDeserializeATree()
|
||||
{
|
||||
var model = CreateConnectionTreeModel();
|
||||
var dataTable = CreateDataTable(model.RootNodes[0]);
|
||||
_deserializer = new DataTableDeserializer();
|
||||
_deserializer = new DataTableDeserializer(_cryptographyProvider, new SecureString());
|
||||
var output = _deserializer.Deserialize(dataTable);
|
||||
Assert.That(output.GetRecursiveChildList().Count(), Is.EqualTo(model.GetRecursiveChildList().Count()));
|
||||
Assert.That(output.GetRecursiveChildList().Count, Is.EqualTo(model.GetRecursiveChildList().Count));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WeCanDeserializeASingleEntry()
|
||||
{
|
||||
var dataTable = CreateDataTable(new ConnectionInfo());
|
||||
_deserializer = new DataTableDeserializer();
|
||||
_deserializer = new DataTableDeserializer(_cryptographyProvider, new SecureString());
|
||||
var output = _deserializer.Deserialize(dataTable);
|
||||
Assert.That(output.GetRecursiveChildList().Count(), Is.EqualTo(1));
|
||||
Assert.That(output.GetRecursiveChildList().Count, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
|
||||
private DataTable CreateDataTable(ConnectionInfo tableContent)
|
||||
{
|
||||
var serializer = new DataTableSerializer(new SaveFilter());
|
||||
var serializer = new DataTableSerializer(new SaveFilter(), _cryptographyProvider, new SecureString());
|
||||
return serializer.Serialize(tableContent);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Config.Serializers.MsSql;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using mRemoteNGTests.TestHelpers;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers
|
||||
@@ -20,7 +23,10 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
public void Setup()
|
||||
{
|
||||
_saveFilter = new SaveFilter();
|
||||
_dataTableSerializer = new DataTableSerializer(_saveFilter);
|
||||
_dataTableSerializer = new DataTableSerializer(
|
||||
_saveFilter,
|
||||
new LegacyRijndaelCryptographyProvider(),
|
||||
new SecureString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.Connection;
|
||||
|
||||
namespace mRemoteNG.App.Info
|
||||
{
|
||||
public static class SettingsFileInfo
|
||||
{
|
||||
private static readonly string ExePath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
|
||||
private static readonly string ExePath = Path.GetDirectoryName(Assembly.GetAssembly(typeof(ConnectionInfo))?.Location);
|
||||
|
||||
public static string SettingsPath => Runtime.IsPortableEdition ? ExePath : Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\" + Application.ProductName;
|
||||
public static string LayoutFileName { get; } = "pnlLayout.xml";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using mRemoteNG.Config.DatabaseConnectors;
|
||||
using System;
|
||||
using mRemoteNG.Config.DatabaseConnectors;
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Config.Serializers.MsSql;
|
||||
@@ -9,6 +10,10 @@ using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.Authentication;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
|
||||
namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
@@ -17,6 +22,9 @@ namespace mRemoteNG.Config.Connections
|
||||
private readonly IDeserializer<string, IEnumerable<LocalConnectionPropertiesModel>> _localConnectionPropertiesDeserializer;
|
||||
private readonly IDataProvider<string> _dataProvider;
|
||||
|
||||
public Func<Optional<SecureString>> AuthenticationRequestor { get; set; } =
|
||||
() => MiscTools.PasswordDialog("", false);
|
||||
|
||||
public SqlConnectionsLoader(
|
||||
IDeserializer<string, IEnumerable<LocalConnectionPropertiesModel>> localConnectionPropertiesDeserializer,
|
||||
IDataProvider<string> dataProvider)
|
||||
@@ -31,16 +39,34 @@ namespace mRemoteNG.Config.Connections
|
||||
var dataProvider = new SqlDataProvider(connector);
|
||||
var metaDataRetriever = new SqlDatabaseMetaDataRetriever();
|
||||
var databaseVersionVerifier = new SqlDatabaseVersionVerifier(connector);
|
||||
var deserializer = new DataTableDeserializer();
|
||||
var cryptoProvider = new LegacyRijndaelCryptographyProvider();
|
||||
|
||||
var metaData = metaDataRetriever.GetDatabaseMetaData(connector);
|
||||
var decryptionKey = GetDecryptionKey(metaData);
|
||||
|
||||
if (!decryptionKey.Any())
|
||||
throw new Exception("Could not load SQL connections");
|
||||
|
||||
databaseVersionVerifier.VerifyDatabaseVersion(metaData.ConfVersion);
|
||||
var dataTable = dataProvider.Load();
|
||||
var deserializer = new DataTableDeserializer(cryptoProvider, decryptionKey.First());
|
||||
var connectionTree = deserializer.Deserialize(dataTable);
|
||||
ApplyLocalConnectionProperties(connectionTree.RootNodes.First(i => i is RootNodeInfo));
|
||||
return connectionTree;
|
||||
}
|
||||
|
||||
private Optional<SecureString> GetDecryptionKey(SqlConnectionListMetaData metaData)
|
||||
{
|
||||
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
|
||||
var cipherText = metaData.Protected;
|
||||
var authenticator = new PasswordAuthenticator(cryptographyProvider, cipherText, AuthenticationRequestor);
|
||||
var authenticated = authenticator.Authenticate(new RootNodeInfo(RootNodeType.Connection).DefaultPassword.ConvertToSecureString());
|
||||
|
||||
if (authenticated)
|
||||
return authenticator.LastAuthenticatedPassword;
|
||||
return Optional<SecureString>.Empty;
|
||||
}
|
||||
|
||||
private void ApplyLocalConnectionProperties(ContainerInfo rootNode)
|
||||
{
|
||||
var localPropertiesXml = _dataProvider.Load();
|
||||
|
||||
@@ -149,13 +149,15 @@ namespace mRemoteNG.Config.Connections
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateConnectionsTable(ContainerInfo rootTreeNode, SqlDatabaseConnector sqlDatabaseConnector)
|
||||
private void UpdateConnectionsTable(RootNodeInfo rootTreeNode, SqlDatabaseConnector sqlDatabaseConnector)
|
||||
{
|
||||
var sqlQuery = new SqlCommand("DELETE FROM tblCons", sqlDatabaseConnector.SqlConnection);
|
||||
sqlQuery.ExecuteNonQuery();
|
||||
var serializer = new DataTableSerializer(_saveFilter);
|
||||
var cryptoProvider = new LegacyRijndaelCryptographyProvider();
|
||||
var serializer = new DataTableSerializer(_saveFilter, cryptoProvider, rootTreeNode.PasswordString.ConvertToSecureString());
|
||||
var dataTable = serializer.Serialize(rootTreeNode);
|
||||
var dataProvider = new SqlDataProvider(sqlDatabaseConnector);
|
||||
|
||||
var sqlQuery = new SqlCommand("DELETE FROM tblCons", sqlDatabaseConnector.SqlConnection);
|
||||
sqlQuery.ExecuteNonQuery();
|
||||
dataProvider.Save(dataTable);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,11 +12,24 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers.MsSql
|
||||
{
|
||||
public class DataTableDeserializer : IDeserializer<DataTable, ConnectionTreeModel>
|
||||
{
|
||||
private readonly ICryptographyProvider _cryptographyProvider;
|
||||
private readonly SecureString _decryptionKey;
|
||||
|
||||
public DataTableDeserializer(ICryptographyProvider cryptographyProvider, SecureString decryptionKey)
|
||||
{
|
||||
_cryptographyProvider = cryptographyProvider.ThrowIfNull(nameof(cryptographyProvider));
|
||||
_decryptionKey = decryptionKey.ThrowIfNull(nameof(decryptionKey));
|
||||
}
|
||||
|
||||
public ConnectionTreeModel Deserialize(DataTable table)
|
||||
{
|
||||
var connectionList = CreateNodesFromTable(table);
|
||||
@@ -73,7 +86,7 @@ namespace mRemoteNG.Config.Serializers.MsSql
|
||||
connectionInfo.Panel = (string)dataRow["Panel"];
|
||||
connectionInfo.Username = (string)dataRow["Username"];
|
||||
connectionInfo.Domain = (string)dataRow["DomainName"];
|
||||
connectionInfo.Password = (string)dataRow["Password"];
|
||||
connectionInfo.Password = DecryptValue((string)dataRow["Password"]);
|
||||
connectionInfo.Hostname = (string)dataRow["Hostname"];
|
||||
connectionInfo.Protocol = (ProtocolType)Enum.Parse(typeof(ProtocolType), (string)dataRow["Protocol"]);
|
||||
connectionInfo.PuttySession = (string)dataRow["PuttySession"];
|
||||
@@ -113,7 +126,7 @@ namespace mRemoteNG.Config.Serializers.MsSql
|
||||
connectionInfo.VNCProxyIP = (string)dataRow["VNCProxyIP"];
|
||||
connectionInfo.VNCProxyPort = (int)dataRow["VNCProxyPort"];
|
||||
connectionInfo.VNCProxyUsername = (string)dataRow["VNCProxyUsername"];
|
||||
connectionInfo.VNCProxyPassword = (string)dataRow["VNCProxyPassword"];
|
||||
connectionInfo.VNCProxyPassword = DecryptValue((string)dataRow["VNCProxyPassword"]);
|
||||
connectionInfo.VNCColors = (ProtocolVNC.Colors)Enum.Parse(typeof(ProtocolVNC.Colors), (string)dataRow["VNCColors"]);
|
||||
connectionInfo.VNCSmartSizeMode = (ProtocolVNC.SmartSizeMode)Enum.Parse(typeof(ProtocolVNC.SmartSizeMode), (string)dataRow["VNCSmartSizeMode"]);
|
||||
connectionInfo.VNCViewOnly = (bool)dataRow["VNCViewOnly"];
|
||||
@@ -121,7 +134,7 @@ namespace mRemoteNG.Config.Serializers.MsSql
|
||||
connectionInfo.RDGatewayHostname = (string)dataRow["RDGatewayHostname"];
|
||||
connectionInfo.RDGatewayUseConnectionCredentials = (RdpProtocol.RDGatewayUseConnectionCredentials)Enum.Parse(typeof(RdpProtocol.RDGatewayUseConnectionCredentials), (string)dataRow["RDGatewayUseConnectionCredentials"]);
|
||||
connectionInfo.RDGatewayUsername = (string)dataRow["RDGatewayUsername"];
|
||||
connectionInfo.RDGatewayPassword = (string)dataRow["RDGatewayPassword"];
|
||||
connectionInfo.RDGatewayPassword = DecryptValue((string)dataRow["RDGatewayPassword"]);
|
||||
connectionInfo.RDGatewayDomain = (string)dataRow["RDGatewayDomain"];
|
||||
|
||||
connectionInfo.Inheritance.CacheBitmaps = (bool)dataRow["InheritCacheBitmaps"];
|
||||
@@ -180,10 +193,26 @@ namespace mRemoteNG.Config.Serializers.MsSql
|
||||
connectionInfo.Inheritance.RDGatewayDomain = (bool)dataRow["InheritRDGatewayDomain"];
|
||||
}
|
||||
|
||||
private string DecryptValue(string cipherText)
|
||||
{
|
||||
try
|
||||
{
|
||||
return _cryptographyProvider.Decrypt(cipherText, _decryptionKey);
|
||||
}
|
||||
catch (EncryptionException)
|
||||
{
|
||||
// value may not be encrypted
|
||||
return cipherText;
|
||||
}
|
||||
}
|
||||
|
||||
private ConnectionTreeModel CreateNodeHierarchy(List<ConnectionInfo> connectionList, DataTable dataTable)
|
||||
{
|
||||
var connectionTreeModel = new ConnectionTreeModel();
|
||||
var rootNode = new RootNodeInfo(RootNodeType.Connection, "0");
|
||||
var rootNode = new RootNodeInfo(RootNodeType.Connection, "0")
|
||||
{
|
||||
PasswordString = _decryptionKey.ConvertToUnsecureString()
|
||||
};
|
||||
connectionTreeModel.AddRootNode(rootNode);
|
||||
|
||||
foreach (DataRow row in dataTable.Rows)
|
||||
|
||||
@@ -7,19 +7,25 @@ using System;
|
||||
using System.Data;
|
||||
using System.Data.SqlTypes;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers.MsSql
|
||||
{
|
||||
public class DataTableSerializer : ISerializer<ConnectionInfo,DataTable>
|
||||
{
|
||||
private readonly ICryptographyProvider _cryptographyProvider;
|
||||
private readonly SecureString _encryptionKey;
|
||||
private DataTable _dataTable;
|
||||
private const string TableName = "tblCons";
|
||||
private readonly SaveFilter _saveFilter;
|
||||
private int _currentNodeIndex;
|
||||
|
||||
public DataTableSerializer(SaveFilter saveFilter)
|
||||
public DataTableSerializer(SaveFilter saveFilter, ICryptographyProvider cryptographyProvider, SecureString encryptionKey)
|
||||
{
|
||||
_saveFilter = saveFilter;
|
||||
_saveFilter = saveFilter.ThrowIfNull(nameof(saveFilter));
|
||||
_cryptographyProvider = cryptographyProvider.ThrowIfNull(nameof(cryptographyProvider));
|
||||
_encryptionKey = encryptionKey.ThrowIfNull(nameof(encryptionKey));
|
||||
}
|
||||
|
||||
|
||||
@@ -210,7 +216,9 @@ namespace mRemoteNG.Config.Serializers.MsSql
|
||||
dataRow["Panel"] = connectionInfo.Panel;
|
||||
dataRow["Username"] = _saveFilter.SaveUsername ? connectionInfo.Username : "";
|
||||
dataRow["DomainName"] = _saveFilter.SaveDomain ? connectionInfo.Domain : "";
|
||||
dataRow["Password"] = _saveFilter.SavePassword ? connectionInfo.Password : "";
|
||||
dataRow["Password"] = _saveFilter.SavePassword
|
||||
? _cryptographyProvider.Encrypt(connectionInfo.Password, _encryptionKey)
|
||||
: "";
|
||||
dataRow["Hostname"] = connectionInfo.Hostname;
|
||||
dataRow["Protocol"] = connectionInfo.Protocol;
|
||||
dataRow["PuttySession"] = connectionInfo.PuttySession;
|
||||
@@ -251,14 +259,14 @@ namespace mRemoteNG.Config.Serializers.MsSql
|
||||
dataRow["VNCProxyIP"] = connectionInfo.VNCProxyIP;
|
||||
dataRow["VNCProxyPort"] = connectionInfo.VNCProxyPort;
|
||||
dataRow["VNCProxyUsername"] = connectionInfo.VNCProxyUsername;
|
||||
dataRow["VNCProxyPassword"] = connectionInfo.VNCProxyPassword;
|
||||
dataRow["VNCProxyPassword"] = _cryptographyProvider.Encrypt(connectionInfo.VNCProxyPassword, _encryptionKey);
|
||||
dataRow["VNCColors"] = connectionInfo.VNCColors;
|
||||
dataRow["VNCSmartSizeMode"] = connectionInfo.VNCSmartSizeMode;
|
||||
dataRow["VNCViewOnly"] = connectionInfo.VNCViewOnly;
|
||||
dataRow["RDGatewayUsageMethod"] = connectionInfo.RDGatewayUsageMethod;
|
||||
dataRow["RDGatewayHostname"] = connectionInfo.RDGatewayHostname;
|
||||
dataRow["RDGatewayUseConnectionCredentials"] = connectionInfo.RDGatewayUseConnectionCredentials;
|
||||
dataRow["RDGatewayUsername"] = connectionInfo.RDGatewayUsername;
|
||||
dataRow["RDGatewayUsername"] = _cryptographyProvider.Encrypt(connectionInfo.RDGatewayUsername, _encryptionKey);
|
||||
dataRow["RDGatewayPassword"] = connectionInfo.RDGatewayPassword;
|
||||
dataRow["RDGatewayDomain"] = connectionInfo.RDGatewayDomain;
|
||||
if (_saveFilter.SaveInheritance)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Security;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers.MsSql
|
||||
{
|
||||
|
||||
@@ -44,7 +44,8 @@ namespace mRemoteNG.Connection
|
||||
throw new ArgumentNullException(nameof(puttySessionsManager));
|
||||
|
||||
_puttySessionsManager = puttySessionsManager;
|
||||
_localConnectionPropertiesDataProvider = new FileDataProvider(Path.Combine(SettingsFileInfo.SettingsPath, "LocalConnectionProperties.xml"));
|
||||
var path = SettingsFileInfo.SettingsPath;
|
||||
_localConnectionPropertiesDataProvider = new FileDataProvider(Path.Combine(path, "LocalConnectionProperties.xml"));
|
||||
_localConnectionPropertiesSerializer = new LocalConnectionPropertiesXmlSerializer();
|
||||
}
|
||||
|
||||
|
||||
@@ -180,7 +180,7 @@
|
||||
<Compile Include="Config\Serializers\MiscSerializers\RemoteDesktopConnectionDeserializer.cs" />
|
||||
<Compile Include="Config\Serializers\MiscSerializers\RemoteDesktopConnectionManagerDeserializer.cs" />
|
||||
<Compile Include="Config\Serializers\ConnectionSerializers\Xml\XmlConnectionNodeSerializer26.cs" />
|
||||
<Compile Include="Config\Serializers\Versioning\SqlDatabaseMetaDataRetriever.cs" />
|
||||
<Compile Include="Config\Serializers\ConnectionSerializers\MsSql\SqlDatabaseMetaDataRetriever.cs" />
|
||||
<Compile Include="Config\Serializers\Versioning\IVersionUpgrader.cs" />
|
||||
<Compile Include="Config\Serializers\Versioning\SqlVersion22To23Upgrader.cs" />
|
||||
<Compile Include="Config\Serializers\Versioning\SqlVersion23To24Upgrader.cs" />
|
||||
|
||||
Reference in New Issue
Block a user