diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/Common/DbConnectionOptions.Common.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/Common/DbConnectionOptions.Common.cs index 470425d3fb..635674dde8 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/Common/DbConnectionOptions.Common.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/Common/DbConnectionOptions.Common.cs @@ -101,7 +101,6 @@ private static class SYNONYM private readonly string _usersConnectionString; private readonly Dictionary _parsetable; internal readonly NameValuePair _keyChain; - internal readonly bool _hasPasswordKeyword; internal Dictionary Parsetable { @@ -114,14 +113,14 @@ public string UsersConnectionString(bool hidePassword) => private string UsersConnectionString(bool hidePassword, bool forceHidePassword) { string connectionString = _usersConnectionString; - if (_hasPasswordKeyword && (forceHidePassword || (hidePassword && !HasPersistablePassword))) + if (HasPasswordKeyword && (forceHidePassword || (hidePassword && !HasPersistablePassword))) { ReplacePasswordPwd(out connectionString, false); } return connectionString ?? string.Empty; } - internal bool HasPersistablePassword => _hasPasswordKeyword ? + internal bool HasPersistablePassword => HasPasswordKeyword ? ConvertValueToBoolean(KEY.Persist_Security_Info, false) : true; // no password means persistable password so we don't have to munge diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Common/DbConnectionOptions.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Common/DbConnectionOptions.cs index 8d1a7043ba..e2d4d2b698 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Common/DbConnectionOptions.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Common/DbConnectionOptions.cs @@ -33,7 +33,6 @@ public DbConnectionOptions(string connectionString, Dictionary s protected DbConnectionOptions(DbConnectionOptions connectionOptions) { // Clone used by SqlConnectionString _usersConnectionString = connectionOptions._usersConnectionString; - _hasPasswordKeyword = connectionOptions._hasPasswordKeyword; _parsetable = connectionOptions._parsetable; _keyChain = connectionOptions._keyChain; HasPasswordKeyword = connectionOptions.HasPasswordKeyword; diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs index 17230c06de..2828842c66 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs @@ -208,6 +208,11 @@ public static bool IsUTF8Supported() return retval; } + public static bool IsTCPConnectionStringPasswordIncluded() + { + return RetrieveValueFromConnStr(TCPConnectionString, new string[] { "Password", "PWD" }) != string.Empty; + } + // the name length will be no more then (16 + prefix.Length + escapeLeft.Length + escapeRight.Length) // some providers does not support names (Oracle supports up to 30) public static string GetUniqueName(string prefix) @@ -482,5 +487,30 @@ public static void DropFunction(SqlConnection sqlConnection, string funcName) cmd.ExecuteNonQuery(); } } + + public static string RetrieveValueFromConnStr(string connStr, string[] keywords) + { + // tokenize connection string and retrieve value for a specific key. + string res = ""; + if (connStr != null && keywords != null) + { + string[] keys = connStr.Split(';'); + foreach (var key in keys) + { + foreach (var keyword in keywords) + { + if (!string.IsNullOrEmpty(key.Trim())) + { + if (key.Trim().ToLower().StartsWith(keyword.Trim().ToLower())) + { + res = key.Substring(key.IndexOf('=') + 1).Trim(); + break; + } + } + } + } + } + return res; + } } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/ConnectivityTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/ConnectivityTest.cs index 47aea11739..02977b3116 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/ConnectivityTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/ConnectivityTest.cs @@ -10,7 +10,7 @@ namespace Microsoft.Data.SqlClient.ManualTesting.Tests { - public static class ConnectivityParametersTest + public static class ConnectivityTest { private const string COL_SPID = "SPID"; private const string COL_PROGRAM_NAME = "ProgramName"; @@ -226,5 +226,33 @@ public static void ConnectionKilledTest() DataTestUtility.RunNonQuery(s_connectionString, s_dropDatabaseCmd); } } + + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsTCPConnectionStringPasswordIncluded))] + public static void ConnectionStringPersistantInfoTest() + { + SqlConnectionStringBuilder connectionStringBuilder = new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString); + connectionStringBuilder.PersistSecurityInfo = false; + string cnnString = connectionStringBuilder.ConnectionString; + + connectionStringBuilder.Clear(); + using (SqlConnection sqlCnn = new SqlConnection(cnnString)) + { + sqlCnn.Open(); + connectionStringBuilder.ConnectionString = sqlCnn.ConnectionString; + Assert.True(connectionStringBuilder.Password == string.Empty, "Password must not persist according to set the PersistSecurityInfo by false!"); + } + + connectionStringBuilder.ConnectionString = DataTestUtility.TCPConnectionString; + connectionStringBuilder.PersistSecurityInfo = true; + cnnString = connectionStringBuilder.ConnectionString; + + connectionStringBuilder.Clear(); + using (SqlConnection sqlCnn = new SqlConnection(cnnString)) + { + sqlCnn.Open(); + connectionStringBuilder.ConnectionString = sqlCnn.ConnectionString; + Assert.True(connectionStringBuilder.Password != string.Empty, "Password must persist according to set the PersistSecurityInfo by true!"); + } + } } }