Skip to content

Commit 621dcd6

Browse files
[Hotfix 4.0.2] | Handle NRE on Azure federated authentication (#1625) (#1722)
1 parent f0eaa13 commit 621dcd6

19 files changed

+121
-41
lines changed

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs

+12-17
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@ public void AssertUnrecoverableStateCountIsCorrect()
103103

104104
internal sealed class SqlInternalConnectionTds : SqlInternalConnection, IDisposable
105105
{
106+
// https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/retry-after#simple-retry-for-errors-with-http-error-codes-500-600
107+
internal const int MsalHttpRetryStatusCode = 429;
108+
106109
// CONNECTION AND STATE VARIABLES
107110
private readonly SqlConnectionPoolGroupProviderInfo _poolGroupProviderInfo; // will only be null when called for ChangePassword, or creating SSE User Instance
108111
private TdsParser _parser;
@@ -2421,7 +2424,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
24212424
// Deal with Msal service exceptions first, retry if 429 received.
24222425
catch (MsalServiceException serviceException)
24232426
{
2424-
if (429 == serviceException.StatusCode)
2427+
if (serviceException.StatusCode == MsalHttpRetryStatusCode)
24252428
{
24262429
RetryConditionHeaderValue retryAfter = serviceException.Headers.RetryAfter;
24272430
if (retryAfter.Delta.HasValue)
@@ -2440,9 +2443,15 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
24402443
}
24412444
else
24422445
{
2443-
break;
2446+
SqlClientEventSource.Log.TryTraceEvent("<sc.SqlInternalConnectionTds.GetFedAuthToken.MsalServiceException error:> Timeout: {0}", serviceException.ErrorCode);
2447+
throw SQL.ActiveDirectoryTokenRetrievingTimeout(Enum.GetName(typeof(SqlAuthenticationMethod), ConnectionOptions.Authentication), serviceException.ErrorCode, serviceException);
24442448
}
24452449
}
2450+
else
2451+
{
2452+
SqlClientEventSource.Log.TryTraceEvent("<sc.SqlInternalConnectionTds.GetFedAuthToken.MsalServiceException error:> {0}", serviceException.ErrorCode);
2453+
throw ADP.CreateSqlException(serviceException, ConnectionOptions, this, username);
2454+
}
24462455
}
24472456
// Deal with normal MsalExceptions.
24482457
catch (MsalException msalException)
@@ -2453,21 +2462,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
24532462
{
24542463
SqlClientEventSource.Log.TryTraceEvent("<sc.SqlInternalConnectionTds.GetFedAuthToken.MSALException error:> {0}", msalException.ErrorCode);
24552464

2456-
// Error[0]
2457-
SqlErrorCollection sqlErs = new();
2458-
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));
2459-
2460-
// Error[1]
2461-
string errorMessage1 = StringsHelper.GetString(Strings.SQL_MSALInnerException, msalException.ErrorCode);
2462-
sqlErs.Add(new SqlError(0, (byte)0x00, (byte)TdsEnums.MIN_ERROR_CLASS, ConnectionOptions.DataSource, errorMessage1, ActiveDirectoryAuthentication.MSALGetAccessTokenFunctionName, 0));
2463-
2464-
// Error[2]
2465-
if (!string.IsNullOrEmpty(msalException.Message))
2466-
{
2467-
sqlErs.Add(new SqlError(0, (byte)0x00, (byte)TdsEnums.MIN_ERROR_CLASS, ConnectionOptions.DataSource, msalException.Message, ActiveDirectoryAuthentication.MSALGetAccessTokenFunctionName, 0));
2468-
}
2469-
SqlException exc = SqlException.CreateException(sqlErs, "", this);
2470-
throw exc;
2465+
throw ADP.CreateSqlException(msalException, ConnectionOptions, this, username);
24712466
}
24722467

24732468
SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.SqlInternalConnectionTds.GetFedAuthToken|ADV> {0}, sleeping {1}[Milliseconds]", ObjectID, sleepInterval);

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlUtil.cs

+4
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,10 @@ internal static Exception ActiveDirectoryDeviceFlowTimeout()
510510
return ADP.TimeoutException(Strings.SQL_Timeout_Active_Directory_DeviceFlow_Authentication);
511511
}
512512

513+
internal static Exception ActiveDirectoryTokenRetrievingTimeout(string authenticaton, string errorCode, Exception exception)
514+
{
515+
return ADP.TimeoutException(StringsHelper.GetString(Strings.AAD_Token_Retrieving_Timeout, authenticaton, errorCode, exception?.Message), exception);
516+
}
513517

514518
//
515519
// SQL.DataCommand

src/Microsoft.Data.SqlClient/netcore/src/Resources/Strings.Designer.cs

+11-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Microsoft.Data.SqlClient/netcore/src/Resources/Strings.resx

+4-1
Original file line numberDiff line numberDiff line change
@@ -1932,4 +1932,7 @@
19321932
<data name="SQL_ParameterDirectionInvalidForOptimizedBinding" xml:space="preserve">
19331933
<value>Parameter '{0}' cannot have Direction Output or InputOutput when EnableOptimizedParameterBinding is enabled on the parent command.</value>
19341934
</data>
1935-
</root>
1935+
<data name="AAD_Token_Retrieving_Timeout" xml:space="preserve">
1936+
<value>Connection timed out while retrieving an access token using '{0}' authentication method. Last error: {1}: {2}</value>
1937+
</data>
1938+
</root>

src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs

+11-17
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ public void AssertUnrecoverableStateCountIsCorrect()
105105

106106
sealed internal class SqlInternalConnectionTds : SqlInternalConnection, IDisposable
107107
{
108+
// https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/retry-after#simple-retry-for-errors-with-http-error-codes-500-600
109+
internal const int MsalHttpRetryStatusCode = 429;
108110

109111
// Connection re-route limit
110112
internal const int _maxNumberOfRedirectRoute = 10;
@@ -2859,7 +2861,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
28592861
// Deal with Msal service exceptions first, retry if 429 received.
28602862
catch (MsalServiceException serviceException)
28612863
{
2862-
if (429 == serviceException.StatusCode)
2864+
if (serviceException.StatusCode == MsalHttpRetryStatusCode)
28632865
{
28642866
RetryConditionHeaderValue retryAfter = serviceException.Headers.RetryAfter;
28652867
if (retryAfter.Delta.HasValue)
@@ -2878,9 +2880,15 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
28782880
}
28792881
else
28802882
{
2881-
break;
2883+
SqlClientEventSource.Log.TryTraceEvent("<sc.SqlInternalConnectionTds.GetFedAuthToken.MsalServiceException error:> Timeout: {0}", serviceException.ErrorCode);
2884+
throw SQL.ActiveDirectoryTokenRetrievingTimeout(Enum.GetName(typeof(SqlAuthenticationMethod), ConnectionOptions.Authentication), serviceException.ErrorCode, serviceException);
28822885
}
28832886
}
2887+
else
2888+
{
2889+
SqlClientEventSource.Log.TryTraceEvent("<sc.SqlInternalConnectionTds.GetFedAuthToken.MsalServiceException error:> {0}", serviceException.ErrorCode);
2890+
throw ADP.CreateSqlException(serviceException, ConnectionOptions, this, username);
2891+
}
28842892
}
28852893
// Deal with normal MsalExceptions.
28862894
catch (MsalException msalException)
@@ -2891,21 +2899,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
28912899
{
28922900
SqlClientEventSource.Log.TryTraceEvent("<sc.SqlInternalConnectionTds.GetFedAuthToken.MSALException error:> {0}", msalException.ErrorCode);
28932901

2894-
// Error[0]
2895-
SqlErrorCollection sqlErs = new SqlErrorCollection();
2896-
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));
2897-
2898-
// Error[1]
2899-
string errorMessage1 = StringsHelper.GetString(Strings.SQL_MSALInnerException, msalException.ErrorCode);
2900-
sqlErs.Add(new SqlError(0, (byte)0x00, (byte)TdsEnums.MIN_ERROR_CLASS, ConnectionOptions.DataSource, errorMessage1, ActiveDirectoryAuthentication.MSALGetAccessTokenFunctionName, 0));
2901-
2902-
// Error[2]
2903-
if (!string.IsNullOrEmpty(msalException.Message))
2904-
{
2905-
sqlErs.Add(new SqlError(0, (byte)0x00, (byte)TdsEnums.MIN_ERROR_CLASS, ConnectionOptions.DataSource, msalException.Message, ActiveDirectoryAuthentication.MSALGetAccessTokenFunctionName, 0));
2906-
}
2907-
SqlException exc = SqlException.CreateException(sqlErs, "", this);
2908-
throw exc;
2902+
throw ADP.CreateSqlException(msalException, ConnectionOptions, this, username);
29092903
}
29102904

29112905
SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.SqlInternalConnectionTds.GetFedAuthToken|ADV> {0}, sleeping {1}[Milliseconds]", ObjectID, sleepInterval);

src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlUtil.cs

+5
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,11 @@ static internal Exception ActiveDirectoryDeviceFlowTimeout()
654654
return ADP.TimeoutException(Strings.SQL_Timeout_Active_Directory_DeviceFlow_Authentication);
655655
}
656656

657+
internal static Exception ActiveDirectoryTokenRetrievingTimeout(string authenticaton, string errorCode, Exception exception)
658+
{
659+
return ADP.TimeoutException(StringsHelper.GetString(Strings.AAD_Token_Retrieving_Timeout, authenticaton, errorCode, exception?.Message), exception);
660+
}
661+
657662
//
658663
// SQL.DataCommand
659664
//

src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs

+10-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.de.resx

+3
Original file line numberDiff line numberDiff line change
@@ -4617,4 +4617,7 @@
46174617
<data name="SQL_ParameterDirectionInvalidForOptimizedBinding" xml:space="preserve">
46184618
<value>Der Parameter "{0}" kann keine Ausgaberichtung oder InputOutput aufweisen, wenn EnableOptimizedParameterBinding für den übergeordneten Befehl aktiviert ist.</value>
46194619
</data>
4620+
<data name="AAD_Token_Retrieving_Timeout" xml:space="preserve">
4621+
<value>Timeout bei der Verbindung beim Abrufen eines Zugriffstokens mithilfe der Authentifizierungsmethode "{0}". Letzter Fehler: {1}: {2}</value>
4622+
</data>
46204623
</root>

src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.es.resx

+3
Original file line numberDiff line numberDiff line change
@@ -4617,4 +4617,7 @@
46174617
<data name="SQL_ParameterDirectionInvalidForOptimizedBinding" xml:space="preserve">
46184618
<value>El parámetro “{0}” no puede tener la Dirección de salida ni InputOutput cuando EnableOptimizedParameterBinding está habilitado en el comando primario.</value>
46194619
</data>
4620+
<data name="AAD_Token_Retrieving_Timeout" xml:space="preserve">
4621+
<value>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}</value>
4622+
</data>
46204623
</root>

src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.fr.resx

+3
Original file line numberDiff line numberDiff line change
@@ -4617,4 +4617,7 @@
46174617
<data name="SQL_ParameterDirectionInvalidForOptimizedBinding" xml:space="preserve">
46184618
<value>Le paramètre « {0} » ne peut pas avoir Direction Output ou InputOutput lorsque EnableOptimizedParameterBinding est activé sur la commande parente.</value>
46194619
</data>
4620+
<data name="AAD_Token_Retrieving_Timeout" xml:space="preserve">
4621+
<value>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}</value>
4622+
</data>
46204623
</root>

src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.it.resx

+3
Original file line numberDiff line numberDiff line change
@@ -4617,4 +4617,7 @@
46174617
<data name="SQL_ParameterDirectionInvalidForOptimizedBinding" xml:space="preserve">
46184618
<value>Il parametro '{0}' non può includere Output o InputOutput come valore di Direction quando nel comando padre è abilitato EnableOptimizedParameterBinding.</value>
46194619
</data>
4620+
<data name="AAD_Token_Retrieving_Timeout" xml:space="preserve">
4621+
<value>Timeout della connessione durante il recupero di un token di accesso tramite il metodo di autenticazione '{0}'. Ultimo errore: {1}: {2}</value>
4622+
</data>
46204623
</root>

src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.ja.resx

+3
Original file line numberDiff line numberDiff line change
@@ -4617,4 +4617,7 @@
46174617
<data name="SQL_ParameterDirectionInvalidForOptimizedBinding" xml:space="preserve">
46184618
<value>親コマンドで EnableOptimizedParameterBinding が有効になっている場合、パラメーター '{0}' に Direction 出力または InputOutput は指定できません。</value>
46194619
</data>
4620+
<data name="AAD_Token_Retrieving_Timeout" xml:space="preserve">
4621+
<value>認証方法 '{0}' によるアクセス トークンの取得中に接続がタイムアウトしました。前回のエラー: {1}: {2}</value>
4622+
</data>
46204623
</root>

src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.ko.resx

+3
Original file line numberDiff line numberDiff line change
@@ -4617,4 +4617,7 @@
46174617
<data name="SQL_ParameterDirectionInvalidForOptimizedBinding" xml:space="preserve">
46184618
<value>부모 명령에서 EnableOptimizedParameterBinding을 사용하는 경우 매개 변수 '{0}'에는 Direction Output 또는 InputOutput을 사용할 수 없습니다.</value>
46194619
</data>
4620+
<data name="AAD_Token_Retrieving_Timeout" xml:space="preserve">
4621+
<value>'{0}' 인증 방법을 사용하여 액세스 토큰을 검색하는 동안 연결 시간이 초과되었습니다. 마지막 오류: {1}: {2}</value>
4622+
</data>
46204623
</root>

src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.pt-BR.resx

+3
Original file line numberDiff line numberDiff line change
@@ -4617,4 +4617,7 @@
46174617
<data name="SQL_ParameterDirectionInvalidForOptimizedBinding" xml:space="preserve">
46184618
<value>O parâmetro '{0}' não pode ter a saída de direção ou InputOutput quando EnableOptimizedParameterBinding está habilitado no comando pai.</value>
46194619
</data>
4620+
<data name="AAD_Token_Retrieving_Timeout" xml:space="preserve">
4621+
<value>A conexão expirou ao recuperar um token de acesso usando o método de autenticação '{0}'. Último erro: {1}: {2}</value>
4622+
</data>
46204623
</root>

src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx

+3
Original file line numberDiff line numberDiff line change
@@ -4617,4 +4617,7 @@
46174617
<data name="SQL_ParameterDirectionInvalidForOptimizedBinding" xml:space="preserve">
46184618
<value>Parameter '{0}' cannot have Direction Output or InputOutput when EnableOptimizedParameterBinding is enabled on the parent command.</value>
46194619
</data>
4620+
<data name="AAD_Token_Retrieving_Timeout" xml:space="preserve">
4621+
<value>Connection timed out while retrieving an access token using '{0}' authentication method. Last error: {1}: {2}</value>
4622+
</data>
46204623
</root>

src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.ru.resx

+3
Original file line numberDiff line numberDiff line change
@@ -4617,4 +4617,7 @@
46174617
<data name="SQL_ParameterDirectionInvalidForOptimizedBinding" xml:space="preserve">
46184618
<value>У параметра "{0}" не может быть направления вывода или InputOutput, если EnableOptimizedParameterBinding включен в родительской команде.</value>
46194619
</data>
4620+
<data name="AAD_Token_Retrieving_Timeout" xml:space="preserve">
4621+
<value>Истекло время ожидания подключения при получении маркера доступа с помощью метода проверки подлинности "{0}". Последняя ошибка: {1}: {2}</value>
4622+
</data>
46204623
</root>

src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.zh-Hans.resx

+3
Original file line numberDiff line numberDiff line change
@@ -4617,4 +4617,7 @@
46174617
<data name="SQL_ParameterDirectionInvalidForOptimizedBinding" xml:space="preserve">
46184618
<value>当在父命令上启用 EnableOptimizedParameterBinding 时,参数“{0}”不能具有 Direction Output 或 InputOutput。</value>
46194619
</data>
4620+
<data name="AAD_Token_Retrieving_Timeout" xml:space="preserve">
4621+
<value>使用“{0}”身份验证方法检索访问令牌时连接超时。最后一个错误: {1}: {2}</value>
4622+
</data>
46204623
</root>

src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.zh-Hant.resx

+3
Original file line numberDiff line numberDiff line change
@@ -4617,4 +4617,7 @@
46174617
<data name="SQL_ParameterDirectionInvalidForOptimizedBinding" xml:space="preserve">
46184618
<value>在父命令上啟用 EnableOptimizedParameterBinding 時,參數 '{0}' 不能具有方向輸出或 InputOutput。</value>
46194619
</data>
4620+
<data name="AAD_Token_Retrieving_Timeout" xml:space="preserve">
4621+
<value>使用 '{0}' 驗證方法擷取存取權杖時已逾時。上次錯誤: {1}: {2}</value>
4622+
</data>
46204623
</root>

0 commit comments

Comments
 (0)