///<summary>Every optional parameter provided should coincide with a commandline arguement. ///The values passed in will typically override any settings loaded in from the config file. ///Passing in a value for webServiceUri or databaseName will cause the config file to not even be considered.</summary> public static ChooseDatabaseModel GetChooseDatabaseModelFromConfig(string webServiceUri = "", YN webServiceIsEcw = YN.Unknown, string odUser = "" , string serverName = "", string databaseName = "", string mySqlUser = "", string mySqlPassword = "", string mySqlPassHash = "", YN noShow = YN.Unknown) { ChooseDatabaseModel chooseDatabaseModel = new ChooseDatabaseModel(); //Even if we are passed a URI as a command line argument we still need to check the FreeDentalConfig file for middle tier automatic log in. //The only time we do not need to do that is if a direct DB has been passed in. if (string.IsNullOrEmpty(databaseName)) { #region Config File //command-line support for the upper portion of this window will be added later. //Improvement should be made here to avoid requiring admin priv. //Search path should be something like this: //1. /home/username/.opendental/config.xml (or corresponding user path in Windows) //2. /etc/opendental/config.xml (or corresponding machine path in Windows) (should be default for new installs) //3. Application Directory/FreeDentalConfig.xml (read-only if user is not admin) string xmlPath = ODFileUtils.CombinePaths(Application.StartupPath, "FreeDentalConfig.xml"); if (!File.Exists(xmlPath)) { FileStream fs; try { fs = File.Create(xmlPath); } catch (Exception) { //No translation right here because we typically do not have a database connection yet. throw new ODException("The very first time that the program is run, it must be run as an Admin. " + "If using Vista, right click, run as Admin."); } fs.Close(); } XmlDocument document = new XmlDocument(); try { document.Load(xmlPath); XPathNavigator Navigator = document.CreateNavigator(); XPathNavigator nav; //Database type nav = Navigator.SelectSingleNode("//DatabaseType"); DataConnection.DBtype = DatabaseType.MySql; if (nav != null && nav.Value == "Oracle") { DataConnection.DBtype = DatabaseType.Oracle; } nav = Navigator.SelectSingleNode("//AdminCompNames"); if (nav != null) { chooseDatabaseModel.ListAdminCompNames.Clear(); //this method gets called more than once XPathNodeIterator navIterator = nav.SelectChildren(XPathNodeType.All); for (int i = 0; i < navIterator.Count; i++) { navIterator.MoveNext(); chooseDatabaseModel.ListAdminCompNames.Add(navIterator.Current.Value); //Add this computer name to the list. } } //See if there's a ConnectionString nav = Navigator.SelectSingleNode("//ConnectionString"); if (nav != null) { //If there is a ConnectionString, then use it. chooseDatabaseModel.ConnectionString = nav.Value; return(chooseDatabaseModel); } //See if there's a UseXWebTestGateway nav = Navigator.SelectSingleNode("//UseXWebTestGateway"); if (nav != null) { OpenDentBusiness.WebTypes.Shared.XWeb.XWebs.UseXWebTestGateway = nav.Value.ToLower() == "true"; } //See if there's a DatabaseConnection nav = Navigator.SelectSingleNode("//DatabaseConnection"); if (nav != null) { //If there is a DatabaseConnection, then use it. chooseDatabaseModel.CentralConnectionCur.ServerName = nav.SelectSingleNode("ComputerName").Value; chooseDatabaseModel.CentralConnectionCur.DatabaseName = nav.SelectSingleNode("Database").Value; chooseDatabaseModel.CentralConnectionCur.MySqlUser = nav.SelectSingleNode("User").Value; chooseDatabaseModel.CentralConnectionCur.MySqlPassword = nav.SelectSingleNode("Password").Value; XPathNavigator encryptedPwdNode = nav.SelectSingleNode("MySQLPassHash"); //If the Password node is empty, but there is a value in the MySQLPassHash node, decrypt the node value and use that instead string _decryptedPwd; if (chooseDatabaseModel.CentralConnectionCur.MySqlPassword == "" && encryptedPwdNode != null && encryptedPwdNode.Value != "" && CDT.Class1.Decrypt(encryptedPwdNode.Value, out _decryptedPwd)) { //decrypted value could be an empty string, which means they don't have a password set, so textPassword will be an empty string chooseDatabaseModel.CentralConnectionCur.MySqlPassword = _decryptedPwd; } XPathNavigator noshownav = nav.SelectSingleNode("NoShowOnStartup"); if (noshownav != null && noshownav.Value == "True") { chooseDatabaseModel.NoShow = YN.Yes; } return(chooseDatabaseModel); } nav = Navigator.SelectSingleNode("//ServerConnection"); /* example: * <ServerConnection> * <URI>http://server/OpenDentalServer/ServiceMain.asmx</URI> * <UsingEcw>True</UsingEcw> * </ServerConnection> */ if (nav != null) { //If there is a ServerConnection, then use it. chooseDatabaseModel.CentralConnectionCur.ServiceURI = nav.SelectSingleNode("URI").Value; XPathNavigator ecwnav = nav.SelectSingleNode("UsingEcw"); if (ecwnav != null && ecwnav.Value == "True") { chooseDatabaseModel.NoShow = YN.Yes; chooseDatabaseModel.CentralConnectionCur.WebServiceIsEcw = true; } XPathNavigator autoLoginNav = nav.SelectSingleNode("UsingAutoLogin"); //Auto login the user using their windows credentials if (autoLoginNav != null && autoLoginNav.Value == "True") { chooseDatabaseModel.CentralConnectionCur.OdUser = nav.SelectSingleNode("User").Value; //Get the user's password from Windows Credential Manager try { chooseDatabaseModel.CentralConnectionCur.OdPassword = PasswordVaultWrapper.RetrievePassword(chooseDatabaseModel.CentralConnectionCur.ServiceURI, chooseDatabaseModel.CentralConnectionCur.OdUser); //Must set this so FormChooseDatabase() does not launch chooseDatabaseModel.NoShow = YN.Yes; chooseDatabaseModel.CentralConnectionCur.IsAutomaticLogin = true; } catch (Exception ex) { ex.DoNothing(); //We still want to display the server URI and the user name if getting the password fails. } } } } catch (Exception) { //Common error: root element is missing chooseDatabaseModel.CentralConnectionCur.ServerName = "localhost"; #if (TRIALONLY) chooseDatabaseModel.CentralConnectionCur.ServerName = "demo"; #else chooseDatabaseModel.CentralConnectionCur.DatabaseName = "opendental"; #endif chooseDatabaseModel.CentralConnectionCur.MySqlUser = "******"; } #endregion } //Command line args should always trump settings from the config file. #region Command Line Arguements if (webServiceUri != "") //if a URI was passed in { chooseDatabaseModel.CentralConnectionCur.ServiceURI = webServiceUri; } if (webServiceIsEcw != YN.Unknown) { chooseDatabaseModel.CentralConnectionCur.WebServiceIsEcw = (webServiceIsEcw == YN.Yes ? true : false); } if (odUser != "") { chooseDatabaseModel.CentralConnectionCur.OdUser = odUser; } //OdPassHash;//not allowed to be used here. Instead, only used directly in TryToConnect //OdPassword//not allowed to be used here. Instead, only used directly in TryToConnect if (serverName != "") { chooseDatabaseModel.CentralConnectionCur.ServerName = serverName; } if (databaseName != "") { chooseDatabaseModel.CentralConnectionCur.DatabaseName = databaseName; } if (mySqlUser != "") { chooseDatabaseModel.CentralConnectionCur.MySqlUser = mySqlUser; } if (mySqlPassword != "") { chooseDatabaseModel.CentralConnectionCur.MySqlPassword = mySqlPassword; } if (mySqlPassHash != "") { string decryptedPwd; CDT.Class1.Decrypt(mySqlPassHash, out decryptedPwd); chooseDatabaseModel.CentralConnectionCur.MySqlPassword = decryptedPwd; } if (noShow != YN.Unknown) { chooseDatabaseModel.NoShow = noShow; } #endregion return(chooseDatabaseModel); }
///<summary>Gets all of the connection setting information from the FreeDentalConfig.xml ///Throws exceptions.</summary> public static void GetChooseDatabaseConnectionSettings(out CentralConnection centralConnection, out string connectionString, out YN noShow , out DatabaseType dbType, out List <string> listAdminCompNames) { //No remoting role check; out parameters are used. centralConnection = new CentralConnection(); connectionString = ""; noShow = YN.Unknown; dbType = DatabaseType.MySql; listAdminCompNames = new List <string>(); string xmlPath = ODFileUtils.CombinePaths(Application.StartupPath, "FreeDentalConfig.xml"); #region Permission Check //Improvement should be made here to avoid requiring admin priv. //Search path should be something like this: //1. /home/username/.opendental/config.xml (or corresponding user path in Windows) //2. /etc/opendental/config.xml (or corresponding machine path in Windows) (should be default for new installs) //3. Application Directory/FreeDentalConfig.xml (read-only if user is not admin) if (!File.Exists(xmlPath)) { FileStream fs; try { fs = File.Create(xmlPath); } catch (Exception) { //No translation right here because we typically do not have a database connection yet. throw new ODException("The very first time that the program is run, it must be run as an Admin. " + "If using Vista, right click, run as Admin."); } fs.Close(); } #endregion XmlDocument document = new XmlDocument(); try { document.Load(xmlPath); XPathNavigator Navigator = document.CreateNavigator(); XPathNavigator nav; #region Nodes with No UI //Always look for these settings first in order to always preserve them correctly. nav = Navigator.SelectSingleNode("//AdminCompNames"); if (nav != null) { listAdminCompNames.Clear(); //this method gets called more than once XPathNodeIterator navIterator = nav.SelectChildren(XPathNodeType.All); for (int i = 0; i < navIterator.Count; i++) { navIterator.MoveNext(); listAdminCompNames.Add(navIterator.Current.Value); //Add this computer name to the list. } } //See if there's a UseXWebTestGateway nav = Navigator.SelectSingleNode("//UseXWebTestGateway"); if (nav != null) { OpenDentBusiness.WebTypes.Shared.XWeb.XWebs.UseXWebTestGateway = nav.Value.ToLower() == "true"; } #endregion #region Nodes from Choose Database Window #region Nodes with No Group Box //Database Type nav = Navigator.SelectSingleNode("//DatabaseType"); dbType = DatabaseType.MySql; if (nav != null && nav.Value == "Oracle") { dbType = DatabaseType.Oracle; } //ConnectionString nav = Navigator.SelectSingleNode("//ConnectionString"); if (nav != null) { //If there is a ConnectionString, then use it. connectionString = nav.Value; } #endregion #region Connection Settings Group Box //See if there's a DatabaseConnection nav = Navigator.SelectSingleNode("//DatabaseConnection"); if (nav != null) { //If there is a DatabaseConnection, then use it. centralConnection.ServerName = nav.SelectSingleNode("ComputerName").Value; centralConnection.DatabaseName = nav.SelectSingleNode("Database").Value; centralConnection.MySqlUser = nav.SelectSingleNode("User").Value; centralConnection.MySqlPassword = nav.SelectSingleNode("Password").Value; XPathNavigator encryptedPwdNode = nav.SelectSingleNode("MySQLPassHash"); //If the Password node is empty, but there is a value in the MySQLPassHash node, decrypt the node value and use that instead string _decryptedPwd; if (centralConnection.MySqlPassword == "" && encryptedPwdNode != null && encryptedPwdNode.Value != "" && CDT.Class1.Decrypt(encryptedPwdNode.Value, out _decryptedPwd)) { //decrypted value could be an empty string, which means they don't have a password set, so textPassword will be an empty string centralConnection.MySqlPassword = _decryptedPwd; } XPathNavigator noshownav = nav.SelectSingleNode("NoShowOnStartup"); if (noshownav != null) { if (noshownav.Value == "True") { noShow = YN.Yes; } else { noShow = YN.No; } } } #endregion #region Connect to Middle Tier Group Box nav = Navigator.SelectSingleNode("//ServerConnection"); /* example: * <ServerConnection> * <URI>http://server/OpenDentalServer/ServiceMain.asmx</URI> * <UsingEcw>True</UsingEcw> * </ServerConnection> */ if (nav != null) { //If there is a ServerConnection, then use it. centralConnection.ServiceURI = nav.SelectSingleNode("URI").Value; XPathNavigator ecwnav = nav.SelectSingleNode("UsingEcw"); if (ecwnav != null && ecwnav.Value == "True") { noShow = YN.Yes; centralConnection.WebServiceIsEcw = true; } XPathNavigator autoLoginNav = nav.SelectSingleNode("UsingAutoLogin"); //Auto login the user using their windows credentials if (autoLoginNav != null && autoLoginNav.Value == "True") { centralConnection.OdUser = nav.SelectSingleNode("User").Value; //Get the user's password from Windows Credential Manager try { centralConnection.OdPassword = PasswordVaultWrapper.RetrievePassword(centralConnection.ServiceURI, centralConnection.OdUser); //Must set this so FormChooseDatabase() does not launch noShow = YN.Yes; centralConnection.IsAutomaticLogin = true; } catch (Exception ex) { ex.DoNothing(); //We still want to display the server URI and the user name if getting the password fails. } } } #endregion #endregion } catch (Exception) { //Common error: root element is missing centralConnection.ServerName = "localhost"; #if (TRIALONLY) centralConnection.ServerName = "demo"; #else centralConnection.DatabaseName = "opendental"; #endif centralConnection.MySqlUser = "******"; } }
///<summary>Returns true if the connection settings were successfully saved to the FreeDentalConfig file and/or Windows PasswordVault. ///Otherwise, false. ///Set isCommandLineArgs to true in order to preserve settings within FreeDentalConfig.xml that are not command line args. ///E.g. the current value within the FreeDentalConfig.xml for NoShowOnStartup will be preserved instead of the value passed in.</summary> public static bool TrySaveConnectionSettings(CentralConnection centralConnection, DatabaseType dbType, string connectionString = "" , bool noShowOnStartup = false, List <string> listAdminCompNames = null, bool isCommandLineArgs = false, bool useDynamicMode = false, bool allowAutoLogin = true) { try { //The parameters passed in might have misleading information (like noShowOnStartup) if they were comprised from command line arguments. //Non-command line settings within the FreeDentalConfig.xml need to be preserved when command line arguments are used. if (isCommandLineArgs) { //Updating the freedentalconfig.xml file when connecting via command line arguments causes issues for users //who prefer to have a desktop icon pointing to their main database and additional icons for other databases (popular amongst CEMT users). return(false); /**** The following code will be reintroduced in the near future. Leaving as a comment on purpose. **** * //Override all variables that are NOT valid command line arguments with their current values within the FreeDentalConfig.xml * //This will preserve the values that should stay the same (e.g. noShowOnStartup is NOT a command line arg and will always be true). * CentralConnection centralConnectionFile; * string connectionStringFile; * YN noShowFile; * DatabaseType dbTypeFile; * List<string> listAdminCompNamesFile; * GetChooseDatabaseConnectionSettings(out centralConnectionFile,out connectionStringFile,out noShowFile,out dbTypeFile * ,out listAdminCompNamesFile,out useDynamicMode); * //Since command line args are being used, override any variables that are NOT allowed to be passed in via the command line. #region FreeDentalConfig Nodes That Do Not Have a Corresponding Command Line Arg * switch(noShowFile) {//config node: <NoShowOnStartup> * case YN.Yes: * noShowOnStartup=true; * break; * case YN.No: * case YN.Unknown: * //Either NoShowOnStartup was not found or was explicitly set to no. * noShowOnStartup=false; * break; * } * listAdminCompNames=listAdminCompNamesFile;//config node: <AdminCompNames> * connectionString=connectionStringFile;//config node: <ConnectionString> * centralConnection.IsAutomaticLogin=centralConnectionFile.IsAutomaticLogin;//config node: <UsingAutoLogin> #endregion ********************************************************************************************************/ } XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; settings.IndentChars = (" "); using (XmlWriter writer = XmlWriter.Create(ODFileUtils.CombinePaths(Application.StartupPath, "FreeDentalConfig.xml"), settings)) { writer.WriteStartElement("ConnectionSettings"); if (!allowAutoLogin) { //Only add if it was added before. writer.WriteElementString("AllowAutoLogin", "False"); } if (connectionString != "") { writer.WriteStartElement("ConnectionString"); writer.WriteString(connectionString); writer.WriteEndElement(); } else if (RemotingClient.RemotingRole == RemotingRole.ClientDirect) { writer.WriteStartElement("DatabaseConnection"); writer.WriteStartElement("ComputerName"); writer.WriteString(centralConnection.ServerName); writer.WriteEndElement(); writer.WriteStartElement("Database"); writer.WriteString(centralConnection.DatabaseName); writer.WriteEndElement(); writer.WriteStartElement("User"); writer.WriteString(centralConnection.MySqlUser); writer.WriteEndElement(); string encryptedPwd; CDT.Class1.Encrypt(centralConnection.MySqlPassword, out encryptedPwd); //sets encryptedPwd ot value or null writer.WriteStartElement("Password"); //If encryption fails, write plain text password to xml file; maintains old behavior. writer.WriteString(string.IsNullOrEmpty(encryptedPwd) ? centralConnection.MySqlPassword : ""); writer.WriteEndElement(); writer.WriteStartElement("MySQLPassHash"); writer.WriteString(encryptedPwd ?? ""); writer.WriteEndElement(); writer.WriteStartElement("NoShowOnStartup"); if (noShowOnStartup) { writer.WriteString("True"); } else { writer.WriteString("False"); } writer.WriteEndElement(); writer.WriteEndElement(); } else if (RemotingClient.RemotingRole == RemotingRole.ClientWeb) { writer.WriteStartElement("ServerConnection"); writer.WriteStartElement("URI"); writer.WriteString(centralConnection.ServiceURI); writer.WriteEndElement(); //end URI if (centralConnection.IsAutomaticLogin) { writer.WriteStartElement("User"); writer.WriteString(centralConnection.OdUser); writer.WriteEndElement(); //end Username writer.WriteStartElement("UsingAutoLogin"); writer.WriteString("True"); writer.WriteEndElement(); //end UsingAutoLogin } writer.WriteStartElement("UsingEcw"); if (centralConnection.WebServiceIsEcw) { writer.WriteString("True"); } else { writer.WriteString("False"); } writer.WriteEndElement(); //end UsingEcw writer.WriteEndElement(); //end ServerConnection } writer.WriteStartElement("DatabaseType"); if (dbType == DatabaseType.MySql) { writer.WriteString("MySql"); } else { writer.WriteString("Oracle"); } writer.WriteEndElement(); writer.WriteStartElement("UseDynamicMode"); writer.WriteString(useDynamicMode.ToString()); writer.WriteEndElement(); if (OpenDentBusiness.WebTypes.Shared.XWeb.XWebs.UseXWebTestGateway) { writer.WriteStartElement("UseXWebTestGateway"); writer.WriteString("True"); writer.WriteEndElement(); } if (listAdminCompNames != null && listAdminCompNames.Count > 0) { writer.WriteStartElement("AdminCompNames"); foreach (string compName in listAdminCompNames) { writer.WriteStartElement("CompName"); writer.WriteString(compName); writer.WriteEndElement(); } writer.WriteEndElement(); } writer.WriteEndElement(); writer.Flush(); } //using writer //Input the user's credentials to WCM (Windows Credential Manager) if necessary. if (RemotingClient.RemotingRole == RemotingRole.ClientWeb && !string.IsNullOrWhiteSpace(centralConnection.ServiceURI) && centralConnection.IsAutomaticLogin) { bool isCredentialSaveRequired = true; //Assume credentials are not saved yet. if (PasswordVaultWrapper.TryRetrieveUserName(centralConnection.ServiceURI, out string userName)) //Found a saved OD MT UserName //Update the credentials if the user or password is different. { if (centralConnection.OdUser != userName || PasswordVaultWrapper.RetrievePassword(centralConnection.ServiceURI, userName) != centralConnection.OdPassword) { //UserName or Password in the saved credentials does not match current password. Delete the saved credentials and save the new //credentials. This will clear all the saved credentials from the PasswordVault for the currently logged in Windows User, which is //desired behavior as each Windows User should only have one set of OpenDental Middle Tier credentials. PasswordVaultWrapper.ClearCredentials(centralConnection.ServiceURI); } else { isCredentialSaveRequired = false; //Username and Password already saved and match current credentials. } } if (isCredentialSaveRequired) { if (!string.IsNullOrWhiteSpace(centralConnection.OdUser) && !string.IsNullOrWhiteSpace(centralConnection.OdPassword)) { //Save the new credentials. PasswordVaultWrapper.WritePassword(centralConnection.ServiceURI, centralConnection.OdUser, centralConnection.OdPassword); } else { return(false); //Invalid username/password. } } } } catch (Exception ex) { ex.DoNothing(); return(false); } return(true); }