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

native aot deployment error using Microsoft Entra authentication with Azure SQL #2742

Closed
guillermoright opened this issue Jul 31, 2024 · 11 comments

Comments

@guillermoright
Copy link

guillermoright commented Jul 31, 2024

Native Aot

using native AOT with ASP.NET Core, minimal api, with azure sql server with Microsoft Entra authentication with Azure SQL,

this is the connection string for Microsoft Entra MFA Serve authentication:
{servername};Authentication=Active Directory Interactive;Database={databaseName}

when we deploy the aplication dotnet publish -r win-x64 -c Release, we are getting this error , seems the microsoft entra authentication is not supported,

Exception message:
Stack trace:

 Connection id "0HN5HAGUR6598", Request id "0HN5HAGUR6598:00000001": An unhandled exception was thrown by the application.
      Microsoft.Data.SqlClient.SqlException (0x80131904): A type initializer threw an exception. To determine which type, inspect the InnerException's StackTrace property.
       ---> System.TypeInitializationException: A type initializer threw an exception. To determine which type, inspect the InnerException's StackTrace property.
       ---> System.Configuration.ConfigurationErrorsException: Configuration system failed to initialize
       ---> System.MissingMethodException: No parameterless constructor defined for type 'System.Configuration.ClientConfigurationHost'.
         at System.ActivatorImplementation.CreateInstance(Type, Boolean) + 0x119
         at System.Configuration.Internal.ConfigSystem.System.Configuration.Internal.IConfigSystem.Init(Type, Object[]) + 0x43
         at System.Configuration.ClientConfigurationSystem..ctor() + 0x47
         at System.Configuration.ConfigurationManager.EnsureConfigurationSystem() + 0x56
         --- End of inner exception stack trace ---
         at System.Configuration.ConfigurationManager.PrepareConfigSystem() + 0x35
         at System.Configuration.ConfigurationManager.GetSection(String) + 0x18
         at System.Runtime.Caching.MemoryCacheStatistics.InitializeConfiguration(NameValueCollection) + 0x2c
         at System.Runtime.Caching.MemoryCacheStatistics..ctor(MemoryCache, NameValueCollection) + 0x4a
         at System.Runtime.Caching.MemoryCache.InitDisposableMembers(NameValueCollection) + 0xf1
         at Microsoft.Data.SqlClient.ActiveDirectoryAuthenticationProvider..cctor() + 0x8c
         at System.Runtime.CompilerServices.ClassConstructorRunner.EnsureClassConstructorRun(StaticClassConstructionContext*) + 0xb9
         --- End of inner exception stack trace ---
         at System.Runtime.CompilerServices.ClassConstructorRunner.EnsureClassConstructorRun(StaticClassConstructionContext*) + 0x14a
         at System.Runtime.CompilerServices.ClassConstructorRunner.CheckStaticClassConstructionReturnGCStaticBase(StaticClassConstructionContext*, Object) + 0xd
         at Microsoft.Data.SqlClient.ActiveDirectoryAuthenticationProvider.<AcquireTokenAsync>d__19.MoveNext() + 0x4c4
      --- End of stack trace from previous location ---
         at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x20
         at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xb2
         at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x4b
         at Microsoft.Data.SqlClient.SqlInternalConnectionTds.<>c__DisplayClass148_1.<<GetFedAuthToken>b__1>d.MoveNext() + 0xc8
      --- End of stack trace from previous location ---
         at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x20
         at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xb2
         at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x4b
         at Microsoft.Data.SqlClient.SqlInternalConnectionTds.GetFedAuthToken(SqlFedAuthInfo) + 0x3b8
         at Microsoft.Data.SqlClient.SqlInternalConnectionTds.GetFedAuthToken(SqlFedAuthInfo) + 0xb0a
         at Microsoft.Data.SqlClient.SqlInternalConnectionTds.OnFedAuthInfo(SqlFedAuthInfo) + 0x30f
         at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior, SqlCommand, SqlDataReader, BulkCopySimpleResultSet, TdsParserStateObject, Boolean&) + 0xa31
         at Microsoft.Data.SqlClient.TdsParser.Run(RunBehavior, SqlCommand, SqlDataReader, BulkCopySimpleResultSet, TdsParserStateObject) + 0x43
         at Microsoft.Data.SqlClient.SqlInternalConnectionTds.CompleteLogin(Boolean) + 0x34
         at Microsoft.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo, String, SecureString, TimeoutTimer, Boolean) + 0x18a
         at Microsoft.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(ServerInfo, String, SecureString, Boolean, SqlConnectionString, SqlCredential, TimeoutTimer) + 0x5b8
         at Microsoft.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(TimeoutTimer, SqlConnectionString, SqlCredential, String, SecureString, Boolean) + 0x1c6
         at Microsoft.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity, SqlConnectionString, SqlCredential, Object, String, SecureString, Boolean, SqlConnectionString, SessionData, Boolean, String, DbConnectionPool, Func`3) + 0x4c6
         at Microsoft.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions, DbConnectionPoolKey, Object, DbConnectionPool, DbConnection, DbConnectionOptions) + 0x30e
         at Microsoft.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnectionPool, DbConnection, DbConnectionOptions, DbConnectionPoolKey, DbConnectionOptions) + 0x40
         at Microsoft.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection, DbConnectionOptions, DbConnectionInternal) + 0x270
         at Microsoft.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection, DbConnectionOptions, DbConnectionInternal) + 0x5e
         at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection, UInt32, Boolean, Boolean, DbConnectionOptions, DbConnectionInternal&) + 0x4be
         at Microsoft.Data.ProviderBase.DbConnectionPool.WaitForPendingOpen() + 0x156
      --- End of stack trace from previous location ---
         at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x20
         at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xb2
         at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x4b
         at Microsoft.Data.SqlClient.SqlRetryLogicProvider.<ExecuteAsync>d__7.MoveNext() + 0x138
      --- End of stack trace from previous location ---
         at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x20
         at Microsoft.Data.SqlClient.SqlRetryLogicProvider.<ExecuteAsync>d__7.MoveNext() + 0x3cd
      --- End of stack trace from previous location ---
         at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x20
         at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xb2
         at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x4b
@arellegue arellegue added 🆕 Triage Needed For new issues, not triaged yet. ℹ️ Needs more Info Issues that have insufficient information to pursue investigations labels Jul 31, 2024
@arellegue
Copy link
Contributor

Thank you for reporting this issue.

We tried to reproduce the issue by creating test application using the template ASP.NET Core WebAPI (native AOT). We then tried to add connection string with Authentication=Active Directory Interactive. The test run succeeded. We then tried to publish using
dotnet publish -r win-x64 -c Release. However, we were not able to reproduce the issue you reported.

Could you provide an example reproduction code, please? This will help us to investigate this issue further.

@guillermoright
Copy link
Author

guillermoright commented Jul 31, 2024

Thank you for reporting this issue.

We tried to reproduce the issue by creating test application using the template ASP.NET Core WebAPI (native AOT). We then tried to add connection string with Authentication=Active Directory Interactive. The test run succeeded. We then tried to publish using dotnet publish -r win-x64 -c Release. However, we were not able to reproduce the issue you reported.

Could you provide an example reproduction code, please? This will help us to investigate this issue further.

native.zip

this an example you can use to reproduce the errorr , i just added small code to open a database connection ,
I use Azure Hyperscale at work. You should replace the databaseserver and databasename parameters with the ones you'll use.
you need to publish the api dotnet publish -r win-x64 and then call the get endpoint

The web API works in development mode, but once deployed, it throws an error.

in development mode when trying to connect to the server, a browser session opens to enter your credentials. However, after deployment, this process no longer works an throw an error

Can you send me your example so I can review it?

@arellegue
Copy link
Contributor

Thank you for the repro. I tried the provided repro and identified that the issue happens when using MDS version 5.2.1.

A hotfix is scheduled to be release within the first 2 weeks of August. We'll let you know when it becomes available.

@arellegue arellegue removed ℹ️ Needs more Info Issues that have insufficient information to pursue investigations 🆕 Triage Needed For new issues, not triaged yet. labels Aug 1, 2024
@guillermoright
Copy link
Author

any update ??

@DavoudEshtehari
Copy link
Contributor

@guillermoright Can you verify the fix in MDS 5.2.2?

@guillermoright
Copy link
Author

guillermoright commented Aug 28, 2024

NativeApi.zip

@guillermoright Can you verify the fix in MDS 5.2.2?

@DavoudEshtehari The fix in version 5.2.2 does not resolve the issue; we are still encountering the same error when releasing the application using dotnet publish -r win-x64 -c Release. If you go to the publish folder (bin\Release\net8.0\win-x64\publish) and execute NativeApi.exe, it throws the same error reported earlier, but in development mode works well

In the example application, you need to replace the values of "database name" and "database server" with real ones.
in this line " Repository.Test("{ //here use real database server }", "{ //here use real database name }"); " to connect using Microsoft Entra MFA Server authentication

then go to the browser /weatherforecast

Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "0HN678PMD990A", Request id "0HN678PMD990A:00000001": An unhandled exception was thrown by the application.
Microsoft.Data.SqlClient.SqlException (0x80131904): A type initializer threw an exception. To determine which type, inspect the InnerException's StackTrace property.
---> System.TypeInitializationException: A type initializer threw an exception. To determine which type, inspect the InnerException's StackTrace property.
---> System.Configuration.ConfigurationErrorsException: Configuration system failed to initialize
---> System.MissingMethodException: No parameterless constructor defined for type 'System.Configuration.ClientConfigurationHost'.
at System.ActivatorImplementation.CreateInstance(Type, Boolean) + 0x119
at System.Configuration.Internal.ConfigSystem.System.Configuration.Internal.IConfigSystem.Init(Type, Object[]) + 0x43
at System.Configuration.ClientConfigurationSystem..ctor() + 0x47
at System.Configuration.ConfigurationManager.EnsureConfigurationSystem() + 0x56
--- End of inner exception stack trace ---
at System.Configuration.ConfigurationManager.PrepareConfigSystem() + 0x35
at System.Configuration.ConfigurationManager.GetSection(String) + 0x18
at System.Runtime.Caching.MemoryCacheStatistics.InitializeConfiguration(NameValueCollection) + 0x2c
at System.Runtime.Caching.MemoryCacheStatistics..ctor(MemoryCache, NameValueCollection) + 0x4a
at System.Runtime.Caching.MemoryCache.InitDisposableMembers(NameValueCollection) + 0xf1
at Microsoft.Data.SqlClient.ActiveDirectoryAuthenticationProvider..cctor() + 0x8c
at System.Runtime.CompilerServices.ClassConstructorRunner.EnsureClassConstructorRun(StaticClassConstructionContext*) + 0xb9
--- End of inner exception stack trace ---
at System.Runtime.CompilerServices.ClassConstructorRunner.EnsureClassConstructorRun(StaticClassConstructionContext*) + 0x14a
at System.Runtime.CompilerServices.ClassConstructorRunner.CheckStaticClassConstructionReturnGCStaticBase(StaticClassConstructionContext*, Object) + 0xd
at Microsoft.Data.SqlClient.ActiveDirectoryAuthenticationProvider.d__19.MoveNext() + 0x4c4
--- End of stack trace from previous location ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x20
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xb2
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x4b
at Microsoft.Data.SqlClient.SqlInternalConnectionTds.<>c__DisplayClass148_1.<b__1>d.MoveNext() + 0xc8
--- End of stack trace from previous location ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x20
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xb2
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x4b
at Microsoft.Data.SqlClient.SqlInternalConnectionTds.GetFedAuthToken(SqlFedAuthInfo) + 0x3b8
at Microsoft.Data.SqlClient.SqlInternalConnectionTds.GetFedAuthToken(SqlFedAuthInfo) + 0xb0a
at Microsoft.Data.SqlClient.SqlInternalConnectionTds.OnFedAuthInfo(SqlFedAuthInfo) + 0x30f
at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior, SqlCommand, SqlDataReader, BulkCopySimpleResultSet, TdsParserStateObject, Boolean&) + 0xa31
at Microsoft.Data.SqlClient.TdsParser.Run(RunBehavior, SqlCommand, SqlDataReader, BulkCopySimpleResultSet, TdsParserStateObject) + 0x43
at Microsoft.Data.SqlClient.SqlInternalConnectionTds.CompleteLogin(Boolean) + 0x34
at Microsoft.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo, String, SecureString, TimeoutTimer, Boolean) + 0x18a
at Microsoft.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(ServerInfo, String, SecureString, Boolean, SqlConnectionString, SqlCredential, TimeoutTimer) + 0x5b8
at Microsoft.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(TimeoutTimer, SqlConnectionString, SqlCredential, String, SecureString, Boolean) + 0x1c6
at Microsoft.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity, SqlConnectionString, SqlCredential, Object, String, SecureString, Boolean, SqlConnectionString, SessionData, Boolean, String, DbConnectionPool, Func3) + 0x4c6 at Microsoft.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions, DbConnectionPoolKey, Object, DbConnectionPool, DbConnection, DbConnectionOptions) + 0x30e at Microsoft.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnectionPool, DbConnection, DbConnectionOptions, DbConnectionPoolKey, DbConnectionOptions) + 0x40 at Microsoft.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection, DbConnectionOptions, DbConnectionInternal) + 0x270 at Microsoft.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection, DbConnectionOptions, DbConnectionInternal) + 0x5e at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection, UInt32, Boolean, Boolean, DbConnectionOptions, DbConnectionInternal&) + 0x4be at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection, TaskCompletionSource1, DbConnectionOptions, DbConnectionInternal&) + 0xc0
at Microsoft.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection, TaskCompletionSource1, DbConnectionOptions, DbConnectionInternal, DbConnectionInternal&) + 0x11e at Microsoft.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection, DbConnectionFactory, TaskCompletionSource1, DbConnectionOptions) + 0x118
at Microsoft.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource1, SqlConnectionOverrides) + 0x24c at Microsoft.Data.SqlClient.SqlConnection.Open(SqlConnectionOverrides) + 0x1ed at NativeApi.Repository.Test(String, String) + 0x211 at Program.<>c__DisplayClass0_0.<Main>b__2() + 0x1d at Microsoft.AspNetCore.Http.Generated.<GeneratedRouteBuilderExtensions_g>FF19069A447510870CDDB625AC2BDBA4994CB0D29ABA3059A7673F4741B94F7CB__GeneratedRouteBuilderExtensionsCore.<>c__DisplayClass3_0.<MapGet1>g__RequestHandler|4(HttpContext httpContext) + 0x18 at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext) + 0x299 at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext) + 0x38d at Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware.Invoke(HttpContext context) + 0x109 at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.<ProcessRequests>d__2381.MoveNext() + 0x36f
ClientConnectionId:a06399bb-9689-4f86-98a7-0c32b113baa4

@arellegue
Copy link
Contributor

@guillermoright How are you publishing the application? Have you tried a Deployment Mode of Self Contained? Is there a reason why you would not deploy using Deployment mode Self Contained?

@guillermoright
Copy link
Author

guillermoright commented Aug 28, 2024

@guillermoright How are you publishing the application? Have you tried a Deployment Mode of Self Contained? Is there a reason why you would not deploy using Deployment mode Self Contained?

@arellegue It is Native Aot , just like self-contained apps, using this instruccion "PublishAot true PublishAot" so when i run dotnet publish -r win-x64 -c Release , the app include all required runtime libraries

@github-project-automation github-project-automation bot moved this from Under Investigation to Closed in SqlClient Triage Board Aug 28, 2024
@arellegue
Copy link
Contributor

@guillermoright I see that the issue was closed. Could you try to reference the MDS 6.0-preview1 to see if it fixes the issue, please?

@guillermoright
Copy link
Author

@guillermoright I see that the issue was closed. Could you try to reference the MDS 6.0-preview1 to see if it fixes the issue, please?

@arellegue The MDS 6.0-preview1 dosent solve the issue , it is imposible to connect to azure SQL Database HyperScale, for an application when it is released

@steveberdy
Copy link

steveberdy commented Dec 6, 2024

I resolved this issue a couple months ago with my ASP.NET backend by creating a custom auth provider implementation. The issue here is that ActiveDirectoryAuthenticationProvider uses a MemoryCache internally and can't construct it when AOT-compiled. You want to pass your own MemoryCache instead of relying on the provider to try to construct one.

To do that, you'll need a custom auth provider implementation, as there isn't a constructor available for overriding the internal memory cache yet. Copy the code from ActiveDirectoryAuthenticationProvider.cs, and adjust it as necessary, such as setting the tenant ID, etc. I don't have my custom provider source code on hand, as I'm not currently working at the company where I resolved this issue, but it's really easy to make the code work.

Once you have your provider, add a constructor accepting a MemoryCache, such as MyActiveDirectoryAuthenticationProvider(MemoryCache accountPwCache) and set s_accountPwCache to the accountPwCache. Note that s_accountPwCache can't be static anymore in our custom implementation.

Then you'll create an instance of your provider before running your app. Use app.Services.GetRequiredService<IMemoryCache>() and pass the cache into your provider's constructor. Note that you should have builder.Services.AddMemoryCache() in your startup.

Now that you have your provider constructed, call SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryDefault, myProvider) to override the SQL authentication provider for Microsoft Entra authentication. When the app runs, it should use your provider when authenticating with Microsoft Entra.

I hope this helps. I might make an API proposal to add constructors accepting MemoryCache's to providers that use them internally.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Development

No branches or pull requests

4 participants