Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ActiveDirectoryIntegrated auth in SSMS 19 hits MSAL throttling #1915

Closed
shueybubbles opened this issue Jan 31, 2023 · 12 comments · Fixed by #1925
Closed

ActiveDirectoryIntegrated auth in SSMS 19 hits MSAL throttling #1915

shueybubbles opened this issue Jan 31, 2023 · 12 comments · Fixed by #1925
Assignees
Labels
🐛 Bug! Issues that are bugs in the drivers we maintain.

Comments

@shueybubbles
Copy link

Describe the bug

See https://feedback.azure.com/d365community/idea/b4b0d281-c2a0-ed11-a81b-6045bd8615b0

SSMS creates multiple connections when using Object Explorer. Customers using Active Directory Integrated auth may get blocked by a throttling exception from MSAL.

Exception message:
Failed to authenticate the user NT Authority\Anonymous Logon in Active Directory (Authentication=ActiveDirectoryIntegrated).
Error code 0xinvalid_grant
Your app has been throttled by AAD due to too many requests. To avoid this, cache your tokens see https://aka.ms/msal-net-throttling. (Microsoft SQL Server, Error: 0)
 
My info:
SQL Server Management Studio                        19.0.20196.0+2666cdc9
SQL Server Management Objects (SMO)                        16.200.48035.0+151cabf12d40a9649e575b05b1e409956d432cc9
Microsoft T-SQL Parser                        16.0.22524.0+62eedb15cd3cde34e51c8fbbdf9b06e575ec912e
Microsoft Analysis Services Client Tools                        16.0.19970.0
Microsoft Data Access Components (MDAC)                        10.0.22000.1455
Microsoft MSXML                        3.0 6.0 
Microsoft .NET Framework                        4.0.30319.42000
Operating System                        10.0.22000
 
stack trace:
   at Microsoft.Data.SqlClient.SqlInternalConnectionTds.GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
   at Microsoft.Data.SqlClient.SqlInternalConnectionTds.OnFedAuthInfo(SqlFedAuthInfo fedAuthInfo)
   at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at Microsoft.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
   at Microsoft.Data.SqlClient.SqlInternalConnectionTds.CompleteLogin(Boolean enlistOK)
   at Microsoft.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, Boolean ignoreSniOpenTimeout, TimeoutTimer timeout, Boolean withFailover, Boolean isFirstTransparentAttempt, Boolean disableTnir)
   at Microsoft.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString connectionOptions, SqlCredential credential, TimeoutTimer timeout)
   at Microsoft.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(TimeoutTimer timeout, SqlConnectionString connectionOptions, SqlCredential credential, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance)
   at Microsoft.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, SqlCredential credential, Object providerInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString userConnectionOptions, SessionData reconnectSessionData, ServerCertificateValidationCallback serverCallback, ClientCertificateRetrievalCallback clientCallback, DbConnectionPool pool, String accessToken, SqlClientOriginalNetworkAddressInfo originalNetworkAddressInfo, Boolean applyTransientFaultHandling)
   at Microsoft.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions)
   at Microsoft.Data.ProviderBase.DbConnectionFactory.CreateNonPooledConnection(DbConnection owningConnection, DbConnectionPoolGroup poolGroup, DbConnectionOptions userOptions)
   at Microsoft.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
   at Microsoft.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
   at Microsoft.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
   at Microsoft.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource`1 retry)
   at Microsoft.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry, SqlConnectionOverrides overrides)
   at Microsoft.Data.SqlClient.SqlConnection.Open(SqlConnectionOverrides overrides)
   at Microsoft.Data.SqlClient.SqlConnection.Open()
   at Microsoft.SqlServer.Management.Common.ConnectionManager.InternalConnectImpl()
   at Microsoft.SqlServer.Management.Common.ConnectionManager.InternalConnect()
   at Microsoft.SqlServer.Management.Common.ConnectionManager.Connect()

To reproduce

Use SSMS 19 Object Explorer with Active Directory Integrated

Expected behavior

I'd expect this auth mode to leverage the in-memory cache with AcquireTokenSilent to avoid this exception

Additional context
Add any other context about the problem here.
Please provide a fix for the 3.1 branch.

@lcheunglci lcheunglci added the 🆕 Triage Needed For new issues, not triaged yet. label Jan 31, 2023
@lcheunglci
Copy link
Contributor

Thanks @shueybubbles for bringing this issue to our attention. It does make sense that we should be caching the token to avoid spamming the auth server. I feel like it's related to the enhancement in #1895 but we'll discuss with the team and take a look at it soon.

@shueybubbles
Copy link
Author

I recommend refactoring auth as part of 6.0, at which point you'll hopefully split the entire AAD provider implementation into its own package.
SSMS 19 has a more urgent need for a patch with 3.x to unblock people.

David-Engel added a commit to David-Engel/SqlClient that referenced this issue Feb 7, 2023
@lcheunglci lcheunglci added this to the 5.2.0 milestone Feb 7, 2023
@lcheunglci lcheunglci added 🐛 Bug! Issues that are bugs in the drivers we maintain. and removed 🆕 Triage Needed For new issues, not triaged yet. labels Feb 7, 2023
@lcheunglci
Copy link
Contributor

We'll look into it.

@MikeHNJ
Copy link

MikeHNJ commented Feb 7, 2023

Thanks, @shueybubbles, using AcquireTokenSilent sounds like that would also address my related issue where I'm not seeing throttling, but a lot of extra authentication flows making for a sluggish UI.
https://feedback.azure.com/d365community/idea/4b79c633-81a1-ed11-a81b-6045bd8615b0

@erinstellato-ms
Copy link

erinstellato-ms commented Feb 15, 2023

Hi @lcheunglci and @David-Engel - checking in to see if there is an ETA on when this fix might be available in a MDS 3.x that we could pick up for a SSMS 19 hotfix. We have users stating that SSMS is unusable for them, and we have to recommend they revert back to an 18.x build. Thanks in advance for any information!

@andygjp
Copy link

andygjp commented Mar 3, 2023

I'm using v5.1.0 in my ASP.NET project and I'm getting an error about throttling inside a test project that uses "Active Directory Password":

  Error Message:
   Microsoft.Data.SqlClient.SqlException : Failed to authenticate the user <redacted> in Active Directory (Authentication=ActiveDirectoryPassword).
Error code 0xinvalid_grant
Your app has been throttled by AAD due to too many requests. To avoid this, cache your tokens see https://aka.ms/msal-net-throttling.
  Stack Trace:
     at Microsoft.Data.SqlClient.SqlInternalConnectionTds.GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
   at Microsoft.Data.SqlClient.SqlInternalConnectionTds.OnFedAuthInfo(SqlFedAuthInfo fedAuthInfo)
   at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at Microsoft.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
   at Microsoft.Data.SqlClient.SqlInternalConnectionTds.CompleteLogin(Boolean enlistOK)
   at Microsoft.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, Boolean ignoreSniOpenTimeout, TimeoutTimer timeout, Boolean withFailover)
   at Microsoft.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString connectionOptions, SqlCredential credential, TimeoutTimer timeout)
   at Microsoft.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(TimeoutTimer timeout, SqlConnectionString connectionOptions, SqlCredential credential, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance)
   at Microsoft.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, SqlCredential credential, Object providerInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString userConnectionOptions, SessionData reconnectSessionData, Boolean applyTransientFaultHandling, String accessToken, DbConnectionPool pool)
   at Microsoft.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions)
   at Microsoft.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnectionPool pool, DbConnection owningObject, DbConnectionOptions options, DbConnectionPoolKey poolKey, DbConnectionOptions userOptions)
   at Microsoft.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
   at Microsoft.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
   at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   at Microsoft.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
   at Microsoft.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
   at Microsoft.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
   at Microsoft.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry, SqlConnectionOverrides overrides)
   at Microsoft.Data.SqlClient.SqlConnection.Open(SqlConnectionOverrides overrides)
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerConnection.OpenDbConnection(Boolean errorsExpected)
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternal(Boolean errorsExpected)
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.Open(Boolean errorsExpected)
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerDatabaseCreator.<>c__DisplayClass18_0.<Exists>b__0(DateTime giveUp)
   at Microsoft.EntityFrameworkCore.ExecutionStrategyExtensions.<>c__DisplayClass12_0`2.<Execute>b__0(DbContext _, TState s)
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
   at Microsoft.EntityFrameworkCore.ExecutionStrategyExtensions.Execute[TState,TResult](IExecutionStrategy strategy, TState state, Func`2 operation, Func`2 verifySucceeded)
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerDatabaseCreator.Exists(Boolean retryOnNotExists)
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerDatabaseCreator.Exists()
   at Microsoft.EntityFrameworkCore.Migrations.HistoryRepository.Exists()
   at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(String targetMigration)
   at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.Migrate(DatabaseFacade databaseFacade)

(The api is deployed in Azure and uses "Active Directory Managed Identity" - I haven't noticed an issue there.)

Is there an earlier version I can use as a temporary fix?

@shueybubbles
Copy link
Author

afaik the only workaround for an app is to implement SqlAuthenticationProvider for that auth type, and make the MSAL calls itself. You could copy most of the existing implementation from the sqlclient source code and have your version cache the token or use AcquireTokenSilent appropriately.

I think a fix is coming from sqlclient soon.

@ErikEJ
Copy link
Contributor

ErikEJ commented Mar 4, 2023

Would adding an explicit reference to Azure.Identity 1.8 work?

@David-Engel
Copy link
Contributor

Would adding an explicit reference to Azure.Identity 1.8 work?

No. MDS uses MSAL.NET, not Azure.Identity for AAD Password/Integrated/Interactive auth.

We'll backport the fix for this to other in-support MDS versions.

David-Engel added a commit that referenced this issue Mar 14, 2023
* Address throttling of token requests by calling AcquireTokenSilent in Integrated/Password flows when the account is already cached.

Addresses issue #1915

Co-authored-by: Lawrence Cheung <31262254+lcheunglci@users.noreply.github.com>
Co-authored-by: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com>
lcheunglci added a commit to lcheunglci/SqlClient that referenced this issue Mar 23, 2023
…net#1925)

* Address throttling of token requests by calling AcquireTokenSilent in Integrated/Password flows when the account is already cached.

Addresses issue dotnet#1915

Co-authored-by: Lawrence Cheung <31262254+lcheunglci@users.noreply.github.com>
Co-authored-by: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com>
@lcheunglci lcheunglci removed their assignment Mar 31, 2023
@ErikEJ
Copy link
Contributor

ErikEJ commented Apr 2, 2023

Is this not fixed in 3.1.1?

@David-Engel
Copy link
Contributor

Is this not fixed in 3.1.1?

It's fixed in 3.1.3.

DavoudEshtehari added a commit to DavoudEshtehari/SqlClient that referenced this issue Apr 13, 2023
…net#1925)

* Address throttling of token requests by calling AcquireTokenSilent in Integrated/Password flows when the account is already cached.

Addresses issue dotnet#1915

Co-authored-by: Lawrence Cheung <31262254+lcheunglci@users.noreply.github.com>
Co-authored-by: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com>
# Conflicts:
#	src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ActiveDirectoryAuthenticationProvider.cs
DavoudEshtehari added a commit to DavoudEshtehari/SqlClient that referenced this issue Apr 13, 2023
…net#1925)

* Address throttling of token requests by calling AcquireTokenSilent in Integrated/Password flows when the account is already cached.

Addresses issue dotnet#1915

Co-authored-by: Lawrence Cheung <31262254+lcheunglci@users.noreply.github.com>
Co-authored-by: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com>
# Conflicts:
#	src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ActiveDirectoryAuthenticationProvider.cs
@DavoudEshtehari DavoudEshtehari removed this from the 5.2.0-preview1 milestone Apr 14, 2023
@David-Engel
Copy link
Contributor

This has been fixed in 3.1, 4.0, 5.1, and main branches.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🐛 Bug! Issues that are bugs in the drivers we maintain.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants