Skip to content

Commit

Permalink
Fixed the ConnectionString's password persistence in NetCore (#489)
Browse files Browse the repository at this point in the history
Co-authored-by: Davoud Eshtehari <[email protected]>
  • Loading branch information
DavoudEshtehari and DavoudEshtehari authored Mar 25, 2020
1 parent 19cb8fb commit 2c27549
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ private static class SYNONYM
private readonly string _usersConnectionString;
private readonly Dictionary<string, string> _parsetable;
internal readonly NameValuePair _keyChain;
internal readonly bool _hasPasswordKeyword;

internal Dictionary<string, string> Parsetable
{
Expand All @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ public DbConnectionOptions(string connectionString, Dictionary<string, string> s
protected DbConnectionOptions(DbConnectionOptions connectionOptions)
{ // Clone used by SqlConnectionString
_usersConnectionString = connectionOptions._usersConnectionString;
_hasPasswordKeyword = connectionOptions._hasPasswordKeyword;
_parsetable = connectionOptions._parsetable;
_keyChain = connectionOptions._keyChain;
HasPasswordKeyword = connectionOptions.HasPasswordKeyword;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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!");
}
}
}
}

0 comments on commit 2c27549

Please sign in to comment.