diff --git a/Step.Config/Config/cmsConnectConfig.xml b/Step.Config/Config/cmsConnectConfig.xml new file mode 100644 index 00000000..0fe16b37 --- /dev/null +++ b/Step.Config/Config/cmsConnectConfig.xml @@ -0,0 +1,10 @@ + + + + true + +
192.168.214.200
+ gsHOP9H9aJHqgVzxruZg/T3XiZ9AfS1NdS/y/JFl05y8nCY9rmrCssxSONSyN/xkkLRvEcEYd/kf0HrluGX6MGrv8qLlCIIZXS6uKQNz7mtG4HokLFqIrHKdu3u3P6jI +
+
+
\ No newline at end of file diff --git a/Step.Config/Config/cmsConnectConfigValidator.xsd b/Step.Config/Config/cmsConnectConfigValidator.xsd new file mode 100644 index 00000000..fdf6760a --- /dev/null +++ b/Step.Config/Config/cmsConnectConfigValidator.xsd @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Step.Config/Config/serverConfig.xml b/Step.Config/Config/serverConfig.xml index 2ae275c9..6949760e 100644 --- a/Step.Config/Config/serverConfig.xml +++ b/Step.Config/Config/serverConfig.xml @@ -24,7 +24,6 @@ false C:\CMS\MTC\ADAPTER\ SCMA - true 50000 5000 diff --git a/Step.Config/Config/serverConfigValidator.xsd b/Step.Config/Config/serverConfigValidator.xsd index bb2e14ef..3bc53d0c 100644 --- a/Step.Config/Config/serverConfigValidator.xsd +++ b/Step.Config/Config/serverConfigValidator.xsd @@ -36,8 +36,7 @@ - - + diff --git a/Step.Config/ServerConfig.cs b/Step.Config/ServerConfig.cs index b7336c29..c60ffd61 100644 --- a/Step.Config/ServerConfig.cs +++ b/Step.Config/ServerConfig.cs @@ -24,6 +24,7 @@ namespace Step.Config public static List InitialAlarmsConfig; public static List HeadsConfig; public static ToolManagerConfigModel ToolManagerConfig; + public static CmsConnectConfigModel CmsConnectConfig; public static AreasConfigModel ProductionConfig; public static AreasConfigModel ToolingConfig; diff --git a/Step.Config/ServerConfigController.cs b/Step.Config/ServerConfigController.cs index 3021db0d..ff8dcc42 100644 --- a/Step.Config/ServerConfigController.cs +++ b/Step.Config/ServerConfigController.cs @@ -33,6 +33,7 @@ namespace Step.Config ReadAlarmsConfig(); ReadHeadsConfig(); ReadToolManagerConfig(); + ReadCMSConnectConfig(); ReadMacros(); ReadScadaFile(); //ReadMainProgram(); @@ -306,8 +307,7 @@ namespace Step.Config MTCFolderPath = x.Element("MTCFolderPath").Value, MTCApplicationName = x.Element("MTCApplicationName").Value, MaxAlarmsRows = Convert.ToInt32(x.Element("maxAlarmsRows").Value), - AlarmToDelete = Convert.ToInt32(x.Element("alarmToDelete").Value), - CMSConnectReady = Convert.ToBoolean(x.Element("CMSConnectReady").Value) + AlarmToDelete = Convert.ToInt32(x.Element("alarmToDelete").Value), }).FirstOrDefault(); int softwareId = 0; @@ -547,6 +547,50 @@ namespace Step.Config .ToList(); } + + private static void ReadCMSConnectConfig() + { + String _tempUSR, _tempPSW; + XDocument xmlConfigFile = GetXmlHandlerWithValidator(CMS_CONNECT_CONFIG_SCHEMA_PATH, CMS_CONNECT_CONFIG_PATH); + + XElement l = xmlConfigFile + .Root + .Descendants("cmsConnectConfig") + .FirstOrDefault(); + + // Read config from XML file + CmsConnectConfig = xmlConfigFile + .Root + .Descendants("cmsConnectConfig") + .Select(x => new CmsConnectConfigModel() + { + Enabled = Convert.ToBoolean(x.Element("enabled").Value) + }) + .FirstOrDefault(); + + // Read config from XML file for Gateway + GatewayConfigModel tempGatewayConfigModel = xmlConfigFile + .Root + .Descendants("gateway") + .Select(x => new GatewayConfigModel() + { + Address = x.Element("address").Value, + Token = x.Element("token").Value + }) + .FirstOrDefault(); + + if (DecodeCMSConnectGatewayLogin(tempGatewayConfigModel.Token, out _tempUSR, out _tempPSW)) + { + tempGatewayConfigModel.Username = _tempUSR; + tempGatewayConfigModel.Password = _tempPSW; + } + else + throw new Exception("Error while reading \""+ CMS_CONNECT_CONFIG_PATH + "\": Gateway Token not valid"); + + CmsConnectConfig.Gateway = tempGatewayConfigModel; + } + + public static void ReadMacros() { XDocument xmlConfigFile = GetXmlHandlerWithValidator(MACROS_CONFIG_SCHEMA_PATH, MACROS_CONFIG_PATH); diff --git a/Step.Config/Step.Config.csproj b/Step.Config/Step.Config.csproj index 60932e76..8f51832a 100644 --- a/Step.Config/Step.Config.csproj +++ b/Step.Config/Step.Config.csproj @@ -42,6 +42,9 @@ + + PreserveNewest + PreserveNewest @@ -144,5 +147,10 @@ Designer + + + Designer + + \ No newline at end of file diff --git a/Step.Core/ThreadsFunctions.cs b/Step.Core/ThreadsFunctions.cs index 074ed7a1..92cec6e1 100644 --- a/Step.Core/ThreadsFunctions.cs +++ b/Step.Core/ThreadsFunctions.cs @@ -834,7 +834,7 @@ public static class ThreadsFunctions foreach (M154DataModel m154 in data) { - if(ServerStartupConfig.CMSConnectReady) + if(CmsConnectConfig.Enabled) { if (m154.Parameters.Count() >= 2 && m154.Parameters[0] == "SOUR") diff --git a/Step.Model/ConfigModels/CmsConnectConfigModel.cs b/Step.Model/ConfigModels/CmsConnectConfigModel.cs new file mode 100644 index 00000000..2b615c61 --- /dev/null +++ b/Step.Model/ConfigModels/CmsConnectConfigModel.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Step.Model.ConfigModels +{ + public class CmsConnectConfigModel + { + public CmsConnectConfigModel() + { + Gateway = new GatewayConfigModel(); + } + public bool Enabled { get; set; } + + public GatewayConfigModel Gateway { get; set; } + } + + public class GatewayConfigModel + { + public string Address { get; set; } + public string Token { get; set; } + public string Username { get; set; } + public string Password { get; set; } + + } +} diff --git a/Step.Model/ConfigModels/ServerConfigModel.cs b/Step.Model/ConfigModels/ServerConfigModel.cs index a2f5dbb7..1479bafd 100644 --- a/Step.Model/ConfigModels/ServerConfigModel.cs +++ b/Step.Model/ConfigModels/ServerConfigModel.cs @@ -18,7 +18,6 @@ namespace Step.Model.ConfigModels public string MTCFolderPath { get; set; } public string MTCApplicationName { get; set; } - public Boolean CMSConnectReady { get; set; } public int MaxAlarmsRows { get; set; } public int AlarmToDelete { get; set; } diff --git a/Step.Model/Constants.cs b/Step.Model/Constants.cs index 1a8abe06..ca6e47ac 100644 --- a/Step.Model/Constants.cs +++ b/Step.Model/Constants.cs @@ -184,6 +184,9 @@ namespace Step.Model public const string TOOL_MANAGER_CONFIG_SCHEMA_PATH = RESOURCE_DIRECTORY + "toolManagerConfigValidator.xsd"; public const string TOOL_MANAGER_CONFIG_PATH = CONFIG_DIRECTORY + "toolManagerConfig.xml"; + public const string CMS_CONNECT_CONFIG_SCHEMA_PATH = RESOURCE_DIRECTORY + "cmsConnectConfigValidator.xsd"; + public const string CMS_CONNECT_CONFIG_PATH = CONFIG_DIRECTORY + "cmsConnectConfig.xml"; + public const string MACROS_CONFIG_SCHEMA_PATH = RESOURCE_DIRECTORY + "macrosConfigValidator.xsd"; public const string MACROS_CONFIG_PATH = CONFIG_DIRECTORY + "macrosConfig.xml"; diff --git a/Step.Model/Step.Model.csproj b/Step.Model/Step.Model.csproj index d49b564b..3332d080 100644 --- a/Step.Model/Step.Model.csproj +++ b/Step.Model/Step.Model.csproj @@ -64,6 +64,7 @@ + diff --git a/Step.Utils/supportFunctions.cs b/Step.Utils/supportFunctions.cs index ac142322..2ad16536 100644 --- a/Step.Utils/supportFunctions.cs +++ b/Step.Utils/supportFunctions.cs @@ -8,6 +8,8 @@ using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; +using System.Security.Cryptography; +using System.Text; using static CMS_CORE_Library.Models.DataStructures; using static Step.Model.Constants; @@ -15,6 +17,8 @@ namespace Step.Utils { public static class SupportFunctions { + private static readonly string CMSCONNECT_TOKEN = "59f1qik5PYfiJLiXZ4xZ05pjzx5E9FscQWtj4lmfLKXaF1OAxkvu7ziBzXFBuuVQ"; + public static SOFTKEY_TYPE GetSoftKeyType(string type) { switch (type) @@ -399,7 +403,158 @@ namespace Step.Utils } return ""; - } - + } + + + public static Boolean DecodeCMSConnectGatewayLogin(string encryptedString, out string login, out string password) + { + login = ""; + password = ""; + + //Check if is null + if (String.IsNullOrEmpty(encryptedString)) + return false; + + //Decode it + String decodedLogin = StringCipher.Decrypt(encryptedString, CMSCONNECT_TOKEN); + + //Check if contains the Space + if (!decodedLogin.Contains(" ")) + return false; + + //Split it and check + String[] tempLogin = decodedLogin.Split(' '); + if (tempLogin.Length != 2) + return false; + + //Set the variable + login = tempLogin[0]; + password = tempLogin[1]; + + return true; + } + + + + public static Boolean EncodeCMSConnectGatewayLogin(out string encryptedString, string login, string password) + { + encryptedString = ""; + + //Check if contains the Space + if (String.IsNullOrEmpty(login) || login.Contains(" ")) + return false; + + //Check if contains the Space + if (String.IsNullOrEmpty(password) || password.Contains(" ")) + return false; + + encryptedString = StringCipher.Encrypt(login + " " + password, CMSCONNECT_TOKEN); + return true; + } + + //----- Chipher Private Class --------------------------------- + #region Chipher_Private_Class + + private static class StringCipher + { + // This constant is used to determine the keysize of the encryption algorithm in bits. + // We divide this by 8 within the code below to get the equivalent number of bytes. + private const int Keysize = 256; + + // This constant determines the number of iterations for the password bytes generation function. + private const int DerivationIterations = 1000; + + public static string Encrypt(string plainText, string passPhrase) + { + // Salt and IV is randomly generated each time, but is preprended to encrypted cipher text + // so that the same Salt and IV values can be used when decrypting. + var saltStringBytes = Generate256BitsOfRandomEntropy(); + var ivStringBytes = Generate256BitsOfRandomEntropy(); + var plainTextBytes = Encoding.UTF8.GetBytes(plainText); + using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations)) + { + var keyBytes = password.GetBytes(Keysize / 8); + using (var symmetricKey = new RijndaelManaged()) + { + symmetricKey.BlockSize = 256; + symmetricKey.Mode = CipherMode.CBC; + symmetricKey.Padding = PaddingMode.PKCS7; + using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes)) + { + using (var memoryStream = new MemoryStream()) + { + using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) + { + cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length); + cryptoStream.FlushFinalBlock(); + // Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes. + var cipherTextBytes = saltStringBytes; + cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray(); + cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray(); + memoryStream.Close(); + cryptoStream.Close(); + return Convert.ToBase64String(cipherTextBytes); + } + } + } + } + } + } + + public static string Decrypt(string cipherText, string passPhrase) + { + // Get the complete stream of bytes that represent: + // [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText] + var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText); + // Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes. + var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray(); + // Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes. + var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray(); + // Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string. + var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray(); + + using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations)) + { + var keyBytes = password.GetBytes(Keysize / 8); + using (var symmetricKey = new RijndaelManaged()) + { + symmetricKey.BlockSize = 256; + symmetricKey.Mode = CipherMode.CBC; + symmetricKey.Padding = PaddingMode.PKCS7; + using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes)) + { + using (var memoryStream = new MemoryStream(cipherTextBytes)) + { + using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) + { + var plainTextBytes = new byte[cipherTextBytes.Length]; + var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length); + memoryStream.Close(); + cryptoStream.Close(); + return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount); + } + } + } + } + } + } + + private static byte[] Generate256BitsOfRandomEntropy() + { + var randomBytes = new byte[32]; // 32 Bytes will give us 256 bits. + using (var rngCsp = new RNGCryptoServiceProvider()) + { + // Fill the array with cryptographically secure random bytes. + rngCsp.GetBytes(randomBytes); + } + return randomBytes; + } + } + + #endregion } + + + + } \ No newline at end of file