From 48daafedb7a0303f9f722a565a4d4acb68f17f06 Mon Sep 17 00:00:00 2001 From: Cheena Malhotra Date: Mon, 16 Aug 2021 12:41:11 -0700 Subject: [PATCH 1/7] Fix Async thread blocking on SqlConnection open for AAD modes --- .../Data/SqlClient/SqlInternalConnectionTds.cs | 10 +++++----- .../Data/SqlClient/SqlInternalConnectionTds.cs | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs index d506f9ba11..d8fa6495d7 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs @@ -2352,7 +2352,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) } else { - _fedAuthToken = authProvider.AcquireTokenAsync(authParamsBuilder).Result.ToSqlFedAuthToken(); + _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken(); _activeDirectoryAuthTimeoutRetryHelper.CachedToken = _fedAuthToken; } break; @@ -2368,7 +2368,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) else { authParamsBuilder.WithUserId(ConnectionOptions.UserID); - _fedAuthToken = authProvider.AcquireTokenAsync(authParamsBuilder).Result.ToSqlFedAuthToken(); + _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken(); _activeDirectoryAuthTimeoutRetryHelper.CachedToken = _fedAuthToken; } break; @@ -2384,13 +2384,13 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) { username = _credential.UserId; authParamsBuilder.WithUserId(username).WithPassword(_credential.Password); - _fedAuthToken = authProvider.AcquireTokenAsync(authParamsBuilder).Result.ToSqlFedAuthToken(); + _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken(); } else { username = ConnectionOptions.UserID; authParamsBuilder.WithUserId(username).WithPassword(ConnectionOptions.Password); - _fedAuthToken = authProvider.AcquireTokenAsync(authParamsBuilder).Result.ToSqlFedAuthToken(); + _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken(); } _activeDirectoryAuthTimeoutRetryHelper.CachedToken = _fedAuthToken; } @@ -2632,7 +2632,7 @@ internal void OnFeatureExtAck(int featureId, byte[] data) Debug.Assert(_tceVersionSupported <= TdsEnums.MAX_SUPPORTED_TCE_VERSION, "Client support TCE version 2"); _parser.IsColumnEncryptionSupported = true; _parser.TceVersionSupported = _tceVersionSupported; - _parser.AreEnclaveRetriesSupported = _tceVersionSupported == 3; + _parser.AreEnclaveRetriesSupported = _tceVersionSupported == 3; if (data.Length > 1) { diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs index b9b0a217e4..678978fc17 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs @@ -2790,7 +2790,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) } else { - fedAuthToken = authProvider.AcquireTokenAsync(authParamsBuilder).Result.ToSqlFedAuthToken(); + fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken(); _activeDirectoryAuthTimeoutRetryHelper.CachedToken = fedAuthToken; } break; @@ -2806,7 +2806,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) else { authParamsBuilder.WithUserId(ConnectionOptions.UserID); - fedAuthToken = authProvider.AcquireTokenAsync(authParamsBuilder).Result.ToSqlFedAuthToken(); + fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken(); _activeDirectoryAuthTimeoutRetryHelper.CachedToken = fedAuthToken; } break; @@ -2822,13 +2822,13 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) { username = _credential.UserId; authParamsBuilder.WithUserId(username).WithPassword(_credential.Password); - fedAuthToken = authProvider.AcquireTokenAsync(authParamsBuilder).Result.ToSqlFedAuthToken(); + fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken(); } else { username = ConnectionOptions.UserID; authParamsBuilder.WithUserId(username).WithPassword(ConnectionOptions.Password); - fedAuthToken = authProvider.AcquireTokenAsync(authParamsBuilder).Result.ToSqlFedAuthToken(); + fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken(); } _activeDirectoryAuthTimeoutRetryHelper.CachedToken = fedAuthToken; } From 9adeb8cb5cdfcefa04de96b266ae413235153692 Mon Sep 17 00:00:00 2001 From: Cheena Malhotra Date: Tue, 17 Aug 2021 00:43:20 -0700 Subject: [PATCH 2/7] back to result --- .../Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs | 8 ++++---- .../Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs index d8fa6495d7..dc84b45678 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs @@ -2352,7 +2352,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) } else { - _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken(); + _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).Result.ToSqlFedAuthToken(); _activeDirectoryAuthTimeoutRetryHelper.CachedToken = _fedAuthToken; } break; @@ -2368,7 +2368,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) else { authParamsBuilder.WithUserId(ConnectionOptions.UserID); - _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken(); + _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).Result.ToSqlFedAuthToken(); _activeDirectoryAuthTimeoutRetryHelper.CachedToken = _fedAuthToken; } break; @@ -2384,13 +2384,13 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) { username = _credential.UserId; authParamsBuilder.WithUserId(username).WithPassword(_credential.Password); - _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken(); + _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).Result.ToSqlFedAuthToken(); } else { username = ConnectionOptions.UserID; authParamsBuilder.WithUserId(username).WithPassword(ConnectionOptions.Password); - _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken(); + _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).Result.ToSqlFedAuthToken(); } _activeDirectoryAuthTimeoutRetryHelper.CachedToken = _fedAuthToken; } diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs index 678978fc17..81466341a3 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs @@ -2790,7 +2790,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) } else { - fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken(); + fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).Result.ToSqlFedAuthToken(); _activeDirectoryAuthTimeoutRetryHelper.CachedToken = fedAuthToken; } break; @@ -2806,7 +2806,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) else { authParamsBuilder.WithUserId(ConnectionOptions.UserID); - fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken(); + fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).Result.ToSqlFedAuthToken(); _activeDirectoryAuthTimeoutRetryHelper.CachedToken = fedAuthToken; } break; @@ -2822,13 +2822,13 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) { username = _credential.UserId; authParamsBuilder.WithUserId(username).WithPassword(_credential.Password); - fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken(); + fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).Result.ToSqlFedAuthToken(); } else { username = ConnectionOptions.UserID; authParamsBuilder.WithUserId(username).WithPassword(ConnectionOptions.Password); - fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken(); + fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).Result.ToSqlFedAuthToken(); } _activeDirectoryAuthTimeoutRetryHelper.CachedToken = fedAuthToken; } From cf15d35a372635a50605a9f4b35df97a228e3cb9 Mon Sep 17 00:00:00 2001 From: Cheena Malhotra Date: Tue, 17 Aug 2021 13:03:12 -0700 Subject: [PATCH 3/7] Fix AAD Tests --- .../SqlClient/SqlInternalConnectionTds.cs | 8 +++--- .../netcore/src/Resources/Strings.Designer.cs | 2 +- .../netcore/src/Resources/Strings.resx | 2 +- .../SqlClient/SqlInternalConnectionTds.cs | 8 +++--- .../netfx/src/Resources/Strings.Designer.cs | 2 +- .../netfx/src/Resources/Strings.resx | 2 +- .../ManualTests/DataCommon/DataTestUtility.cs | 23 +++++++++++++++++ .../ConnectivityTests/AADConnectionTest.cs | 25 +++++++++++++------ 8 files changed, 53 insertions(+), 19 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs index dc84b45678..d8fa6495d7 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs @@ -2352,7 +2352,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) } else { - _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).Result.ToSqlFedAuthToken(); + _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken(); _activeDirectoryAuthTimeoutRetryHelper.CachedToken = _fedAuthToken; } break; @@ -2368,7 +2368,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) else { authParamsBuilder.WithUserId(ConnectionOptions.UserID); - _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).Result.ToSqlFedAuthToken(); + _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken(); _activeDirectoryAuthTimeoutRetryHelper.CachedToken = _fedAuthToken; } break; @@ -2384,13 +2384,13 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) { username = _credential.UserId; authParamsBuilder.WithUserId(username).WithPassword(_credential.Password); - _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).Result.ToSqlFedAuthToken(); + _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken(); } else { username = ConnectionOptions.UserID; authParamsBuilder.WithUserId(username).WithPassword(ConnectionOptions.Password); - _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).Result.ToSqlFedAuthToken(); + _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken(); } _activeDirectoryAuthTimeoutRetryHelper.CachedToken = _fedAuthToken; } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Resources/Strings.Designer.cs b/src/Microsoft.Data.SqlClient/netcore/src/Resources/Strings.Designer.cs index 291bead3d3..824deb1601 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Resources/Strings.Designer.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Resources/Strings.Designer.cs @@ -2833,7 +2833,7 @@ internal static string SQL_MSALFailure { } /// - /// Looks up a localized string similar to Error code 0x{0}; state {1}. + /// Looks up a localized string similar to Error code 0x{0}.. /// internal static string SQL_MSALInnerException { get { diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Resources/Strings.resx b/src/Microsoft.Data.SqlClient/netcore/src/Resources/Strings.resx index 2ae63630be..857ef5cddc 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Resources/Strings.resx +++ b/src/Microsoft.Data.SqlClient/netcore/src/Resources/Strings.resx @@ -1348,7 +1348,7 @@ Failed to authenticate the user {0} in Active Directory (Authentication={1}). - Error code 0x{0}; state {1} + Error code 0x{0} Internal connection fatal error. Error state: {0}. diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs index 81466341a3..678978fc17 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs @@ -2790,7 +2790,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) } else { - fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).Result.ToSqlFedAuthToken(); + fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken(); _activeDirectoryAuthTimeoutRetryHelper.CachedToken = fedAuthToken; } break; @@ -2806,7 +2806,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) else { authParamsBuilder.WithUserId(ConnectionOptions.UserID); - fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).Result.ToSqlFedAuthToken(); + fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken(); _activeDirectoryAuthTimeoutRetryHelper.CachedToken = fedAuthToken; } break; @@ -2822,13 +2822,13 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) { username = _credential.UserId; authParamsBuilder.WithUserId(username).WithPassword(_credential.Password); - fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).Result.ToSqlFedAuthToken(); + fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken(); } else { username = ConnectionOptions.UserID; authParamsBuilder.WithUserId(username).WithPassword(ConnectionOptions.Password); - fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).Result.ToSqlFedAuthToken(); + fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken(); } _activeDirectoryAuthTimeoutRetryHelper.CachedToken = fedAuthToken; } diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs index 2644b0a713..72f7fa5243 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs @@ -9658,7 +9658,7 @@ internal static string SQL_MSALFailure { } /// - /// Looks up a localized string similar to Error code 0x{0}; state {1}. + /// Looks up a localized string similar to Error code 0x{0}.. /// internal static string SQL_MSALInnerException { get { diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx index 893c22f01c..0d9e331900 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx @@ -2563,7 +2563,7 @@ Failed to authenticate the user {0} in Active Directory (Authentication={1}). - Error code 0x{0}; state {1} + Error code 0x{0} ChangePassword requires SQL Server 9.0 or later. diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs index 1f6ad4ddea..e3a1fea22d 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs @@ -728,6 +728,29 @@ public static string GetValueString(object paramValue) return paramValue.ToString(); } + public static string FetchKeyInConnStr(string connStr, string[] keys) + { + // tokenize connection string and find matching key + if (connStr != null && keys != null) + { + string[] connProps = connStr.Split(';'); + foreach (string cp in connProps) + { + if (!string.IsNullOrEmpty(cp.Trim())) + { + foreach (var key in keys) + { + if (cp.Trim().ToLower().StartsWith(key.Trim().ToLower())) + { + return cp.Substring(cp.IndexOf('=') + 1); + } + } + } + } + } + return null; + } + public static string RemoveKeysInConnStr(string connStr, string[] keysToRemove) { // tokenize connection string and remove input keys. diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs index 5723958636..03038393a0 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs @@ -161,10 +161,10 @@ public static void AADPasswordWithWrongPassword() string[] credKeys = { "Password", "PWD" }; string connStr = DataTestUtility.RemoveKeysInConnStr(DataTestUtility.AADPasswordConnectionString, credKeys) + "Password=TestPassword;"; - AggregateException e = Assert.Throws(() => ConnectAndDisconnect(connStr)); + SqlException e = Assert.Throws(() => ConnectAndDisconnect(connStr)); string expectedMessage = "ID3242: The security token could not be authenticated or authorized."; - Assert.Contains(expectedMessage, e.InnerException.InnerException.Message); + Assert.Contains(expectedMessage, e.Message); } @@ -241,7 +241,11 @@ public static void EmptyPasswordInConnStrAADPassword() // connection fails with expected error message. string[] pwdKey = { "Password", "PWD" }; string connStr = DataTestUtility.RemoveKeysInConnStr(DataTestUtility.AADPasswordConnectionString, pwdKey) + "Password=;"; - Assert.Throws(() => ConnectAndDisconnect(connStr)); + SqlException e = Assert.Throws(() => ConnectAndDisconnect(connStr)); + + string user = DataTestUtility.FetchKeyInConnStr(DataTestUtility.AADPasswordConnectionString, new string[] { "User Id", "UID" }); + string expectedMessage = string.Format("Failed to authenticate the user {0} in Active Directory (Authentication=ActiveDirectoryPassword).", user); + Assert.Contains(expectedMessage, e.Message); } [PlatformSpecific(TestPlatforms.Windows)] @@ -251,7 +255,10 @@ public static void EmptyCredInConnStrAADPassword() // connection fails with expected error message. string[] removeKeys = { "User ID", "Password", "UID", "PWD" }; string connStr = DataTestUtility.RemoveKeysInConnStr(DataTestUtility.AADPasswordConnectionString, removeKeys) + "User ID=; Password=;"; - Assert.Throws(() => ConnectAndDisconnect(connStr)); + SqlException e = Assert.Throws(() => ConnectAndDisconnect(connStr)); + + string expectedMessage = "Failed to authenticate the user in Active Directory (Authentication=ActiveDirectoryPassword)."; + Assert.Contains(expectedMessage, e.Message); } [PlatformSpecific(TestPlatforms.AnyUnix)] @@ -261,7 +268,7 @@ public static void EmptyCredInConnStrAADPasswordAnyUnix() // connection fails with expected error message. string[] removeKeys = { "User ID", "Password", "UID", "PWD" }; string connStr = DataTestUtility.RemoveKeysInConnStr(DataTestUtility.AADPasswordConnectionString, removeKeys) + "User ID=; Password=;"; - Assert.Throws(() => ConnectAndDisconnect(connStr)); + SqlException e = Assert.Throws(() => ConnectAndDisconnect(connStr)); } [ConditionalFact(nameof(IsAADConnStringsSetup))] @@ -269,8 +276,12 @@ public static void AADPasswordWithInvalidUser() { // connection fails with expected error message. string[] removeKeys = { "User ID", "UID" }; - string connStr = DataTestUtility.RemoveKeysInConnStr(DataTestUtility.AADPasswordConnectionString, removeKeys) + "User ID=testdotnet@microsoft.com"; - Assert.Throws(() => ConnectAndDisconnect(connStr)); + string user = "testdotnet@domain.com"; + string connStr = DataTestUtility.RemoveKeysInConnStr(DataTestUtility.AADPasswordConnectionString, removeKeys) + $"User ID={user}"; + SqlException e = Assert.Throws(() => ConnectAndDisconnect(connStr)); + + string expectedMessage = string.Format("Failed to authenticate the user {0} in Active Directory (Authentication=ActiveDirectoryPassword).", user); + Assert.Contains(expectedMessage, e.Message); } [ConditionalFact(nameof(IsAADConnStringsSetup))] From 4d69e29f471ae3e90281589221742aeaf3769760 Mon Sep 17 00:00:00 2001 From: Cheena Malhotra Date: Tue, 17 Aug 2021 13:15:54 -0700 Subject: [PATCH 4/7] More changes --- .../netfx/src/Microsoft/Data/Common/DbConnectionStringCommon.cs | 2 +- .../ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DbConnectionStringCommon.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DbConnectionStringCommon.cs index 49ebbb1ebf..0e1a941d06 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DbConnectionStringCommon.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DbConnectionStringCommon.cs @@ -705,7 +705,7 @@ internal static string ColumnEncryptionSettingToString(SqlConnectionColumnEncryp internal static bool IsValidAuthenticationTypeValue(SqlAuthenticationMethod value) { - Debug.Assert(Enum.GetNames(typeof(SqlAuthenticationMethod)).Length == 9, "SqlAuthenticationMethod enum has changed, update needed"); + Debug.Assert(Enum.GetNames(typeof(SqlAuthenticationMethod)).Length == 10, "SqlAuthenticationMethod enum has changed, update needed"); return value == SqlAuthenticationMethod.SqlPassword || value == SqlAuthenticationMethod.ActiveDirectoryPassword || value == SqlAuthenticationMethod.ActiveDirectoryIntegrated diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs index 03038393a0..bb3eac9c50 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs @@ -397,7 +397,7 @@ public static void ActiveDirectoryManagedIdentityWithInvalidUserIdMustFail(strin string connStrWithNoCred = DataTestUtility.RemoveKeysInConnStr(DataTestUtility.AADPasswordConnectionString, credKeys) + $"Authentication=Active Directory Managed Identity; User Id={userId}"; - AggregateException e = Assert.Throws(() => ConnectAndDisconnect(connStrWithNoCred)); + Azure.Identity.CredentialUnavailableException e = Assert.Throws(() => ConnectAndDisconnect(connStrWithNoCred)); string expectedMessage = "ManagedIdentityCredential authentication unavailable"; Assert.Contains(expectedMessage, e.GetBaseException().Message); From de5c963a7c2f3901c6869a355bda3662db54a97a Mon Sep 17 00:00:00 2001 From: Cheena Malhotra Date: Tue, 17 Aug 2021 13:51:59 -0700 Subject: [PATCH 5/7] Fix for Unix --- .../ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs index bb3eac9c50..77fc23debd 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs @@ -268,7 +268,10 @@ public static void EmptyCredInConnStrAADPasswordAnyUnix() // connection fails with expected error message. string[] removeKeys = { "User ID", "Password", "UID", "PWD" }; string connStr = DataTestUtility.RemoveKeysInConnStr(DataTestUtility.AADPasswordConnectionString, removeKeys) + "User ID=; Password=;"; - SqlException e = Assert.Throws(() => ConnectAndDisconnect(connStr)); + PlatformNotSupportedException e = Assert.Throws(() => ConnectAndDisconnect(connStr)); + + string expectedMessage = "MSAL cannot determine the username (UPN) of the currently logged in user.For Integrated Windows Authentication and Username/Password flows, please use .WithUsername() before calling ExecuteAsync()."; + Assert.Contains(expectedMessage, e.Message); } [ConditionalFact(nameof(IsAADConnStringsSetup))] From 75471d4ae04b93423f3f72f659c840035bc89e67 Mon Sep 17 00:00:00 2001 From: Cheena Malhotra Date: Tue, 17 Aug 2021 17:20:20 -0700 Subject: [PATCH 6/7] Wrap internal exceptions into SqlException --- .../Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs | 8 +++++++- .../Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs | 5 +++++ .../SQL/ConnectivityTests/AADConnectionTest.cs | 4 ++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs index d8fa6495d7..e01f500536 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs @@ -2444,8 +2444,9 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) || _timeout.MillisecondsRemaining <= sleepInterval) { SqlClientEventSource.Log.TryTraceEvent(" {0}", msalException.ErrorCode); + // Error[0] - SqlErrorCollection sqlErs = new SqlErrorCollection(); + SqlErrorCollection sqlErs = new(); sqlErs.Add(new SqlError(0, (byte)0x00, (byte)TdsEnums.MIN_ERROR_CLASS, ConnectionOptions.DataSource, StringsHelper.GetString(Strings.SQL_MSALFailure, username, ConnectionOptions.Authentication.ToString("G")), ActiveDirectoryAuthentication.MSALGetAccessTokenFunctionName, 0)); // Error[1] @@ -2467,6 +2468,11 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) Thread.Sleep(sleepInterval); sleepInterval *= 2; } + // All other exceptions from MSAL/Azure Identity APIs + catch (Exception e) + { + throw SqlException.CreateException(new() { new(0, (byte)0x00, (byte)TdsEnums.FATAL_ERROR_CLASS, ConnectionOptions.DataSource, e.Message, ActiveDirectoryAuthentication.MSALGetAccessTokenFunctionName, 0) }, "", this, e); + } } Debug.Assert(_fedAuthToken != null, "fedAuthToken should not be null."); diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs index 678978fc17..4189fd875d 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs @@ -2906,6 +2906,11 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) Thread.Sleep(sleepInterval); sleepInterval *= 2; } + // All other exceptions from MSAL/Azure Identity APIs + catch (Exception e) + { + throw SqlException.CreateException(new() { new(0, (byte)0x00, (byte)TdsEnums.FATAL_ERROR_CLASS, ConnectionOptions.DataSource, e.Message, ActiveDirectoryAuthentication.MSALGetAccessTokenFunctionName, 0) }, "", this, e); + } } Debug.Assert(fedAuthToken != null, "fedAuthToken should not be null."); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs index 77fc23debd..e9849cccd9 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs @@ -268,7 +268,7 @@ public static void EmptyCredInConnStrAADPasswordAnyUnix() // connection fails with expected error message. string[] removeKeys = { "User ID", "Password", "UID", "PWD" }; string connStr = DataTestUtility.RemoveKeysInConnStr(DataTestUtility.AADPasswordConnectionString, removeKeys) + "User ID=; Password=;"; - PlatformNotSupportedException e = Assert.Throws(() => ConnectAndDisconnect(connStr)); + SqlException e = Assert.Throws(() => ConnectAndDisconnect(connStr)); string expectedMessage = "MSAL cannot determine the username (UPN) of the currently logged in user.For Integrated Windows Authentication and Username/Password flows, please use .WithUsername() before calling ExecuteAsync()."; Assert.Contains(expectedMessage, e.Message); @@ -400,7 +400,7 @@ public static void ActiveDirectoryManagedIdentityWithInvalidUserIdMustFail(strin string connStrWithNoCred = DataTestUtility.RemoveKeysInConnStr(DataTestUtility.AADPasswordConnectionString, credKeys) + $"Authentication=Active Directory Managed Identity; User Id={userId}"; - Azure.Identity.CredentialUnavailableException e = Assert.Throws(() => ConnectAndDisconnect(connStrWithNoCred)); + SqlException e = Assert.Throws(() => ConnectAndDisconnect(connStrWithNoCred)); string expectedMessage = "ManagedIdentityCredential authentication unavailable"; Assert.Contains(expectedMessage, e.GetBaseException().Message); From f25e4f711f3e9cc07247d4a4c1514312ad285090 Mon Sep 17 00:00:00 2001 From: Cheena Malhotra Date: Mon, 23 Aug 2021 09:59:45 -0700 Subject: [PATCH 7/7] Add comments --- .../src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs | 2 ++ .../src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs index e01f500536..42bfa3bda1 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs @@ -2352,6 +2352,8 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) } else { + // We use Task.Run here in all places to execute task synchronously in the same context. + // Fixes block-over-async deadlock possibilities https://github.com/dotnet/SqlClient/issues/1209 _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken(); _activeDirectoryAuthTimeoutRetryHelper.CachedToken = _fedAuthToken; } diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs index 4189fd875d..68695ae984 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs @@ -2790,6 +2790,8 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) } else { + // We use Task.Run here in all places to execute task synchronously in the same context. + // Fixes block-over-async deadlock possibilities https://github.com/dotnet/SqlClient/issues/1209 fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken(); _activeDirectoryAuthTimeoutRetryHelper.CachedToken = fedAuthToken; }