From ea6e14c9ff2dd546f39571601db1f5194fee01cc Mon Sep 17 00:00:00 2001 From: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> Date: Tue, 23 Aug 2022 12:53:30 -0700 Subject: [PATCH] [Hotfix 4.1.1] | Handle NRE on Azure federated authentication (#1625) (#1710) --- .../SqlClient/SqlInternalConnectionTds.cs | 29 +++++++--------- .../src/Microsoft/Data/SqlClient/SqlUtil.cs | 4 +++ .../netcore/src/Resources/Strings.Designer.cs | 13 +++++-- .../netcore/src/Resources/Strings.resx | 5 ++- .../SqlClient/SqlInternalConnectionTds.cs | 28 ++++++--------- .../src/Microsoft/Data/SqlClient/SqlUtil.cs | 5 +++ .../netfx/src/Resources/Strings.Designer.cs | 11 +++++- .../netfx/src/Resources/Strings.de.resx | 3 ++ .../netfx/src/Resources/Strings.es.resx | 3 ++ .../netfx/src/Resources/Strings.fr.resx | 3 ++ .../netfx/src/Resources/Strings.it.resx | 3 ++ .../netfx/src/Resources/Strings.ja.resx | 3 ++ .../netfx/src/Resources/Strings.ko.resx | 3 ++ .../netfx/src/Resources/Strings.pt-BR.resx | 3 ++ .../netfx/src/Resources/Strings.resx | 3 ++ .../netfx/src/Resources/Strings.ru.resx | 3 ++ .../netfx/src/Resources/Strings.zh-Hans.resx | 3 ++ .../netfx/src/Resources/Strings.zh-Hant.resx | 3 ++ .../src/Microsoft/Data/Common/AdapterUtil.cs | 34 +++++++++++++++++-- 19 files changed, 121 insertions(+), 41 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 484e2233a9..ae988e34bf 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 @@ -103,6 +103,9 @@ public void AssertUnrecoverableStateCountIsCorrect() internal sealed class SqlInternalConnectionTds : SqlInternalConnection, IDisposable { + // https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/retry-after#simple-retry-for-errors-with-http-error-codes-500-600 + internal const int MsalHttpRetryStatusCode = 429; + // CONNECTION AND STATE VARIABLES private readonly SqlConnectionPoolGroupProviderInfo _poolGroupProviderInfo; // will only be null when called for ChangePassword, or creating SSE User Instance private TdsParser _parser; @@ -2421,7 +2424,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) // Deal with Msal service exceptions first, retry if 429 received. catch (MsalServiceException serviceException) { - if (429 == serviceException.StatusCode) + if (serviceException.StatusCode == MsalHttpRetryStatusCode) { RetryConditionHeaderValue retryAfter = serviceException.Headers.RetryAfter; if (retryAfter.Delta.HasValue) @@ -2440,9 +2443,15 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) } else { - break; + SqlClientEventSource.Log.TryTraceEvent(" Timeout: {0}", serviceException.ErrorCode); + throw SQL.ActiveDirectoryTokenRetrievingTimeout(Enum.GetName(typeof(SqlAuthenticationMethod), ConnectionOptions.Authentication), serviceException.ErrorCode, serviceException); } } + else + { + SqlClientEventSource.Log.TryTraceEvent(" {0}", serviceException.ErrorCode); + throw ADP.CreateSqlException(serviceException, ConnectionOptions, this, username); + } } // Deal with normal MsalExceptions. catch (MsalException msalException) @@ -2453,21 +2462,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) { SqlClientEventSource.Log.TryTraceEvent(" {0}", msalException.ErrorCode); - // Error[0] - 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] - string errorMessage1 = StringsHelper.GetString(Strings.SQL_MSALInnerException, msalException.ErrorCode); - sqlErs.Add(new SqlError(0, (byte)0x00, (byte)TdsEnums.MIN_ERROR_CLASS, ConnectionOptions.DataSource, errorMessage1, ActiveDirectoryAuthentication.MSALGetAccessTokenFunctionName, 0)); - - // Error[2] - if (!string.IsNullOrEmpty(msalException.Message)) - { - sqlErs.Add(new SqlError(0, (byte)0x00, (byte)TdsEnums.MIN_ERROR_CLASS, ConnectionOptions.DataSource, msalException.Message, ActiveDirectoryAuthentication.MSALGetAccessTokenFunctionName, 0)); - } - SqlException exc = SqlException.CreateException(sqlErs, "", this); - throw exc; + throw ADP.CreateSqlException(msalException, ConnectionOptions, this, username); } SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, sleeping {1}[Milliseconds]", ObjectID, sleepInterval); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlUtil.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlUtil.cs index 522092b988..bd6d6bbd6c 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlUtil.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlUtil.cs @@ -510,6 +510,10 @@ internal static Exception ActiveDirectoryDeviceFlowTimeout() return ADP.TimeoutException(Strings.SQL_Timeout_Active_Directory_DeviceFlow_Authentication); } + internal static Exception ActiveDirectoryTokenRetrievingTimeout(string authenticaton, string errorCode, Exception exception) + { + return ADP.TimeoutException(StringsHelper.GetString(Strings.AAD_Token_Retrieving_Timeout, authenticaton, errorCode, exception?.Message), exception); + } // // SQL.DataCommand 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 f33751fb08..9f3d2fec91 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Resources/Strings.Designer.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Resources/Strings.Designer.cs @@ -19,7 +19,7 @@ namespace System { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Strings { @@ -60,6 +60,15 @@ internal Strings() { } } + /// + /// Looks up a localized string similar to Connection timed out while retrieving an access token using '{0}' authentication method. Last error: {1}: {2}. + /// + internal static string AAD_Token_Retrieving_Timeout { + get { + return ResourceManager.GetString("AAD_Token_Retrieving_Timeout", resourceCulture); + } + } + /// /// Looks up a localized string similar to Specified parameter name '{0}' is not valid.. /// @@ -941,7 +950,7 @@ internal static string Data_InvalidOffsetLength { return ResourceManager.GetString("Data_InvalidOffsetLength", resourceCulture); } } - + /// /// Looks up a localized string similar to Internal error occurred when retrying the download of the HGS root certificate after the initial request failed. Contact Customer Support Services.. /// diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Resources/Strings.resx b/src/Microsoft.Data.SqlClient/netcore/src/Resources/Strings.resx index bfe5559389..433c6a7684 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Resources/Strings.resx +++ b/src/Microsoft.Data.SqlClient/netcore/src/Resources/Strings.resx @@ -1932,4 +1932,7 @@ Parameter '{0}' cannot have Direction Output or InputOutput when EnableOptimizedParameterBinding is enabled on the parent command. - \ No newline at end of file + + Connection timed out while retrieving an access token using '{0}' authentication method. Last error: {1}: {2} + + 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 623ce80d93..520c624714 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 @@ -105,6 +105,8 @@ public void AssertUnrecoverableStateCountIsCorrect() sealed internal class SqlInternalConnectionTds : SqlInternalConnection, IDisposable { + // https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/retry-after#simple-retry-for-errors-with-http-error-codes-500-600 + internal const int MsalHttpRetryStatusCode = 429; // Connection re-route limit internal const int _maxNumberOfRedirectRoute = 10; @@ -2859,7 +2861,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) // Deal with Msal service exceptions first, retry if 429 received. catch (MsalServiceException serviceException) { - if (429 == serviceException.StatusCode) + if (serviceException.StatusCode == MsalHttpRetryStatusCode) { RetryConditionHeaderValue retryAfter = serviceException.Headers.RetryAfter; if (retryAfter.Delta.HasValue) @@ -2878,9 +2880,15 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) } else { - break; + SqlClientEventSource.Log.TryTraceEvent(" Timeout: {0}", serviceException.ErrorCode); + throw SQL.ActiveDirectoryTokenRetrievingTimeout(Enum.GetName(typeof(SqlAuthenticationMethod), ConnectionOptions.Authentication), serviceException.ErrorCode, serviceException); } } + else + { + SqlClientEventSource.Log.TryTraceEvent(" {0}", serviceException.ErrorCode); + throw ADP.CreateSqlException(serviceException, ConnectionOptions, this, username); + } } // Deal with normal MsalExceptions. catch (MsalException msalException) @@ -2891,21 +2899,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) { SqlClientEventSource.Log.TryTraceEvent(" {0}", msalException.ErrorCode); - // Error[0] - SqlErrorCollection sqlErs = new SqlErrorCollection(); - 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] - string errorMessage1 = StringsHelper.GetString(Strings.SQL_MSALInnerException, msalException.ErrorCode); - sqlErs.Add(new SqlError(0, (byte)0x00, (byte)TdsEnums.MIN_ERROR_CLASS, ConnectionOptions.DataSource, errorMessage1, ActiveDirectoryAuthentication.MSALGetAccessTokenFunctionName, 0)); - - // Error[2] - if (!string.IsNullOrEmpty(msalException.Message)) - { - sqlErs.Add(new SqlError(0, (byte)0x00, (byte)TdsEnums.MIN_ERROR_CLASS, ConnectionOptions.DataSource, msalException.Message, ActiveDirectoryAuthentication.MSALGetAccessTokenFunctionName, 0)); - } - SqlException exc = SqlException.CreateException(sqlErs, "", this); - throw exc; + throw ADP.CreateSqlException(msalException, ConnectionOptions, this, username); } SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, sleeping {1}[Milliseconds]", ObjectID, sleepInterval); diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlUtil.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlUtil.cs index 3bc5591b3e..ab1d3fe1f7 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlUtil.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlUtil.cs @@ -654,6 +654,11 @@ static internal Exception ActiveDirectoryDeviceFlowTimeout() return ADP.TimeoutException(Strings.SQL_Timeout_Active_Directory_DeviceFlow_Authentication); } + internal static Exception ActiveDirectoryTokenRetrievingTimeout(string authenticaton, string errorCode, Exception exception) + { + return ADP.TimeoutException(StringsHelper.GetString(Strings.AAD_Token_Retrieving_Timeout, authenticaton, errorCode, exception?.Message), exception); + } + // // SQL.DataCommand // 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 bfaf7407be..f7fc54bd04 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs @@ -19,7 +19,7 @@ namespace System { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Strings { @@ -60,6 +60,15 @@ internal Strings() { } } + /// + /// Looks up a localized string similar to Connection timed out while retrieving an access token using '{0}' authentication method. Last error: {1}: {2}. + /// + internal static string AAD_Token_Retrieving_Timeout { + get { + return ResourceManager.GetString("AAD_Token_Retrieving_Timeout", resourceCulture); + } + } + /// /// Looks up a localized string similar to Data adapter mapping error.. /// diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.de.resx b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.de.resx index 1cce66ef3b..7d9ff022d3 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.de.resx +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.de.resx @@ -4617,4 +4617,7 @@ Der Parameter "{0}" kann keine Ausgaberichtung oder InputOutput aufweisen, wenn EnableOptimizedParameterBinding für den übergeordneten Befehl aktiviert ist. + + Timeout bei der Verbindung beim Abrufen eines Zugriffstokens mithilfe der Authentifizierungsmethode "{0}". Letzter Fehler: {1}: {2} + \ No newline at end of file diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.es.resx b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.es.resx index 2bd80b50ef..cd9fac0d6e 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.es.resx +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.es.resx @@ -4617,4 +4617,7 @@ El parámetro “{0}” no puede tener la Dirección de salida ni InputOutput cuando EnableOptimizedParameterBinding está habilitado en el comando primario. + + Se agotó el tiempo de espera de la conexión al recuperar un token de acceso mediante el método de autenticación "{0}". Último error: {1}: {2} + \ No newline at end of file diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.fr.resx b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.fr.resx index fbfa2141eb..27052d932f 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.fr.resx +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.fr.resx @@ -4617,4 +4617,7 @@ Le paramètre « {0} » ne peut pas avoir Direction Output ou InputOutput lorsque EnableOptimizedParameterBinding est activé sur la commande parente. + + La connexion a expiré lors de la récupération d’un jeton d’accès à l’aide de '{0}' méthode d’authentification. Dernière erreur : {1} : {2} + \ No newline at end of file diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.it.resx b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.it.resx index 832d356758..4b37b78d8f 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.it.resx +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.it.resx @@ -4617,4 +4617,7 @@ Il parametro '{0}' non può includere Output o InputOutput come valore di Direction quando nel comando padre è abilitato EnableOptimizedParameterBinding. + + Timeout della connessione durante il recupero di un token di accesso tramite il metodo di autenticazione '{0}'. Ultimo errore: {1}: {2} + \ No newline at end of file diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.ja.resx b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.ja.resx index e65c5b4e8b..cf16e69a6d 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.ja.resx +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.ja.resx @@ -4617,4 +4617,7 @@ 親コマンドで EnableOptimizedParameterBinding が有効になっている場合、パラメーター '{0}' に Direction 出力または InputOutput は指定できません。 + + 認証方法 '{0}' によるアクセス トークンの取得中に接続がタイムアウトしました。前回のエラー: {1}: {2} + \ No newline at end of file diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.ko.resx b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.ko.resx index 2dff8da10f..dc997ae08a 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.ko.resx +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.ko.resx @@ -4617,4 +4617,7 @@ 부모 명령에서 EnableOptimizedParameterBinding을 사용하는 경우 매개 변수 '{0}'에는 Direction Output 또는 InputOutput을 사용할 수 없습니다. + + '{0}' 인증 방법을 사용하여 액세스 토큰을 검색하는 동안 연결 시간이 초과되었습니다. 마지막 오류: {1}: {2} + \ No newline at end of file diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.pt-BR.resx b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.pt-BR.resx index eed81de659..32d6ed95e5 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.pt-BR.resx +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.pt-BR.resx @@ -4617,4 +4617,7 @@ O parâmetro '{0}' não pode ter a saída de direção ou InputOutput quando EnableOptimizedParameterBinding está habilitado no comando pai. + + A conexão expirou ao recuperar um token de acesso usando o método de autenticação '{0}'. Último erro: {1}: {2} + \ No newline at end of file diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx index acf6a6beff..ccc7fa15c3 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx @@ -4617,4 +4617,7 @@ Parameter '{0}' cannot have Direction Output or InputOutput when EnableOptimizedParameterBinding is enabled on the parent command. + + Connection timed out while retrieving an access token using '{0}' authentication method. Last error: {1}: {2} + diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.ru.resx b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.ru.resx index 97a4a9acef..45887165f2 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.ru.resx +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.ru.resx @@ -4617,4 +4617,7 @@ У параметра "{0}" не может быть направления вывода или InputOutput, если EnableOptimizedParameterBinding включен в родительской команде. + + Истекло время ожидания подключения при получении маркера доступа с помощью метода проверки подлинности "{0}". Последняя ошибка: {1}: {2} + \ No newline at end of file diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.zh-Hans.resx b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.zh-Hans.resx index 691824651b..edbc5e8e18 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.zh-Hans.resx +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.zh-Hans.resx @@ -4617,4 +4617,7 @@ 当在父命令上启用 EnableOptimizedParameterBinding 时,参数“{0}”不能具有 Direction Output 或 InputOutput。 + + 使用“{0}”身份验证方法检索访问令牌时连接超时。最后一个错误: {1}: {2} + \ No newline at end of file diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.zh-Hant.resx b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.zh-Hant.resx index 73b2ee5153..8cd49b8c5e 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.zh-Hant.resx +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.zh-Hant.resx @@ -4617,4 +4617,7 @@ 在父命令上啟用 EnableOptimizedParameterBinding 時,參數 '{0}' 不能具有方向輸出或 InputOutput。 + + 使用 '{0}' 驗證方法擷取存取權杖時已逾時。上次錯誤: {1}: {2} + \ No newline at end of file diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs index f7e3715ccc..cb8c4cdecf 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs @@ -24,6 +24,7 @@ using Microsoft.Data.SqlClient.Server; using Microsoft.Win32; using IsolationLevel = System.Data.IsolationLevel; +using Microsoft.Identity.Client; namespace Microsoft.Data.Common { @@ -188,9 +189,9 @@ internal static OverflowException Overflow(string error, Exception inner) return e; } - internal static TimeoutException TimeoutException(string error) + internal static TimeoutException TimeoutException(string error, Exception inner = null) { - TimeoutException e = new(error); + TimeoutException e = new(error, inner); TraceExceptionAsReturnValue(e); return e; } @@ -390,7 +391,34 @@ internal static ArgumentException InvalidArgumentLength(string argumentName, int => Argument(StringsHelper.GetString(Strings.ADP_InvalidArgumentLength, argumentName, limit)); internal static ArgumentException MustBeReadOnly(string argumentName) => Argument(StringsHelper.GetString(Strings.ADP_MustBeReadOnly, argumentName)); - #endregion + + internal static Exception CreateSqlException(MsalException msalException, SqlConnectionString connectionOptions, SqlInternalConnectionTds sender, string username) + { + // Error[0] + 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] + string errorMessage1 = StringsHelper.GetString(Strings.SQL_MSALInnerException, msalException.ErrorCode); + sqlErs.Add(new SqlError(0, (byte)0x00, (byte)TdsEnums.MIN_ERROR_CLASS, + connectionOptions.DataSource, errorMessage1, + ActiveDirectoryAuthentication.MSALGetAccessTokenFunctionName, 0)); + + // Error[2] + if (!string.IsNullOrEmpty(msalException.Message)) + { + sqlErs.Add(new SqlError(0, (byte)0x00, (byte)TdsEnums.MIN_ERROR_CLASS, + connectionOptions.DataSource, msalException.Message, + ActiveDirectoryAuthentication.MSALGetAccessTokenFunctionName, 0)); + } + return SqlException.CreateException(sqlErs, "", sender); + } + +#endregion #region CommandBuilder, Command, BulkCopy ///