Skip to content

Commit

Permalink
[Hotfix 4.1.1] | Handle NRE on Azure federated authentication (#1625) (
Browse files Browse the repository at this point in the history
  • Loading branch information
DavoudEshtehari committed Aug 23, 2022
1 parent 9e4bdaa commit ea6e14c
Show file tree
Hide file tree
Showing 19 changed files with 121 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand All @@ -2440,9 +2443,15 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
}
else
{
break;
SqlClientEventSource.Log.TryTraceEvent("<sc.SqlInternalConnectionTds.GetFedAuthToken.MsalServiceException error:> Timeout: {0}", serviceException.ErrorCode);
throw SQL.ActiveDirectoryTokenRetrievingTimeout(Enum.GetName(typeof(SqlAuthenticationMethod), ConnectionOptions.Authentication), serviceException.ErrorCode, serviceException);
}
}
else
{
SqlClientEventSource.Log.TryTraceEvent("<sc.SqlInternalConnectionTds.GetFedAuthToken.MsalServiceException error:> {0}", serviceException.ErrorCode);
throw ADP.CreateSqlException(serviceException, ConnectionOptions, this, username);
}
}
// Deal with normal MsalExceptions.
catch (MsalException msalException)
Expand All @@ -2453,21 +2462,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
{
SqlClientEventSource.Log.TryTraceEvent("<sc.SqlInternalConnectionTds.GetFedAuthToken.MSALException error:> {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("<sc.SqlInternalConnectionTds.GetFedAuthToken|ADV> {0}, sleeping {1}[Milliseconds]", ObjectID, sleepInterval);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -1932,4 +1932,7 @@
<data name="SQL_ParameterDirectionInvalidForOptimizedBinding" xml:space="preserve">
<value>Parameter '{0}' cannot have Direction Output or InputOutput when EnableOptimizedParameterBinding is enabled on the parent command.</value>
</data>
</root>
<data name="AAD_Token_Retrieving_Timeout" xml:space="preserve">
<value>Connection timed out while retrieving an access token using '{0}' authentication method. Last error: {1}: {2}</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand All @@ -2878,9 +2880,15 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
}
else
{
break;
SqlClientEventSource.Log.TryTraceEvent("<sc.SqlInternalConnectionTds.GetFedAuthToken.MsalServiceException error:> Timeout: {0}", serviceException.ErrorCode);
throw SQL.ActiveDirectoryTokenRetrievingTimeout(Enum.GetName(typeof(SqlAuthenticationMethod), ConnectionOptions.Authentication), serviceException.ErrorCode, serviceException);
}
}
else
{
SqlClientEventSource.Log.TryTraceEvent("<sc.SqlInternalConnectionTds.GetFedAuthToken.MsalServiceException error:> {0}", serviceException.ErrorCode);
throw ADP.CreateSqlException(serviceException, ConnectionOptions, this, username);
}
}
// Deal with normal MsalExceptions.
catch (MsalException msalException)
Expand All @@ -2891,21 +2899,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
{
SqlClientEventSource.Log.TryTraceEvent("<sc.SqlInternalConnectionTds.GetFedAuthToken.MSALException error:> {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("<sc.SqlInternalConnectionTds.GetFedAuthToken|ADV> {0}, sleeping {1}[Milliseconds]", ObjectID, sleepInterval);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
//
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -4617,4 +4617,7 @@
<data name="SQL_ParameterDirectionInvalidForOptimizedBinding" xml:space="preserve">
<value>Der Parameter "{0}" kann keine Ausgaberichtung oder InputOutput aufweisen, wenn EnableOptimizedParameterBinding für den übergeordneten Befehl aktiviert ist.</value>
</data>
<data name="AAD_Token_Retrieving_Timeout" xml:space="preserve">
<value>Timeout bei der Verbindung beim Abrufen eines Zugriffstokens mithilfe der Authentifizierungsmethode "{0}". Letzter Fehler: {1}: {2}</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -4617,4 +4617,7 @@
<data name="SQL_ParameterDirectionInvalidForOptimizedBinding" xml:space="preserve">
<value>El parámetro “{0}” no puede tener la Dirección de salida ni InputOutput cuando EnableOptimizedParameterBinding está habilitado en el comando primario.</value>
</data>
<data name="AAD_Token_Retrieving_Timeout" xml:space="preserve">
<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>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -4617,4 +4617,7 @@
<data name="SQL_ParameterDirectionInvalidForOptimizedBinding" xml:space="preserve">
<value>Le paramètre « {0} » ne peut pas avoir Direction Output ou InputOutput lorsque EnableOptimizedParameterBinding est activé sur la commande parente.</value>
</data>
<data name="AAD_Token_Retrieving_Timeout" xml:space="preserve">
<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>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -4617,4 +4617,7 @@
<data name="SQL_ParameterDirectionInvalidForOptimizedBinding" xml:space="preserve">
<value>Il parametro '{0}' non può includere Output o InputOutput come valore di Direction quando nel comando padre è abilitato EnableOptimizedParameterBinding.</value>
</data>
<data name="AAD_Token_Retrieving_Timeout" xml:space="preserve">
<value>Timeout della connessione durante il recupero di un token di accesso tramite il metodo di autenticazione '{0}'. Ultimo errore: {1}: {2}</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -4617,4 +4617,7 @@
<data name="SQL_ParameterDirectionInvalidForOptimizedBinding" xml:space="preserve">
<value>親コマンドで EnableOptimizedParameterBinding が有効になっている場合、パラメーター '{0}' に Direction 出力または InputOutput は指定できません。</value>
</data>
<data name="AAD_Token_Retrieving_Timeout" xml:space="preserve">
<value>認証方法 '{0}' によるアクセス トークンの取得中に接続がタイムアウトしました。前回のエラー: {1}: {2}</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -4617,4 +4617,7 @@
<data name="SQL_ParameterDirectionInvalidForOptimizedBinding" xml:space="preserve">
<value>부모 명령에서 EnableOptimizedParameterBinding을 사용하는 경우 매개 변수 '{0}'에는 Direction Output 또는 InputOutput을 사용할 수 없습니다.</value>
</data>
<data name="AAD_Token_Retrieving_Timeout" xml:space="preserve">
<value>'{0}' 인증 방법을 사용하여 액세스 토큰을 검색하는 동안 연결 시간이 초과되었습니다. 마지막 오류: {1}: {2}</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -4617,4 +4617,7 @@
<data name="SQL_ParameterDirectionInvalidForOptimizedBinding" xml:space="preserve">
<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>
</data>
<data name="AAD_Token_Retrieving_Timeout" xml:space="preserve">
<value>A conexão expirou ao recuperar um token de acesso usando o método de autenticação '{0}'. Último erro: {1}: {2}</value>
</data>
</root>
3 changes: 3 additions & 0 deletions src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -4617,4 +4617,7 @@
<data name="SQL_ParameterDirectionInvalidForOptimizedBinding" xml:space="preserve">
<value>Parameter '{0}' cannot have Direction Output or InputOutput when EnableOptimizedParameterBinding is enabled on the parent command.</value>
</data>
<data name="AAD_Token_Retrieving_Timeout" xml:space="preserve">
<value>Connection timed out while retrieving an access token using '{0}' authentication method. Last error: {1}: {2}</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -4617,4 +4617,7 @@
<data name="SQL_ParameterDirectionInvalidForOptimizedBinding" xml:space="preserve">
<value>У параметра "{0}" не может быть направления вывода или InputOutput, если EnableOptimizedParameterBinding включен в родительской команде.</value>
</data>
<data name="AAD_Token_Retrieving_Timeout" xml:space="preserve">
<value>Истекло время ожидания подключения при получении маркера доступа с помощью метода проверки подлинности "{0}". Последняя ошибка: {1}: {2}</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -4617,4 +4617,7 @@
<data name="SQL_ParameterDirectionInvalidForOptimizedBinding" xml:space="preserve">
<value>当在父命令上启用 EnableOptimizedParameterBinding 时,参数“{0}”不能具有 Direction Output 或 InputOutput。</value>
</data>
<data name="AAD_Token_Retrieving_Timeout" xml:space="preserve">
<value>使用“{0}”身份验证方法检索访问令牌时连接超时。最后一个错误: {1}: {2}</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -4617,4 +4617,7 @@
<data name="SQL_ParameterDirectionInvalidForOptimizedBinding" xml:space="preserve">
<value>在父命令上啟用 EnableOptimizedParameterBinding 時,參數 '{0}' 不能具有方向輸出或 InputOutput。</value>
</data>
<data name="AAD_Token_Retrieving_Timeout" xml:space="preserve">
<value>使用 '{0}' 驗證方法擷取存取權杖時已逾時。上次錯誤: {1}: {2}</value>
</data>
</root>
Loading

0 comments on commit ea6e14c

Please sign in to comment.