domaindrivendev / Swashbuckle.AspNetCore

Swagger tools for documenting API's built on ASP.NET Core
MIT License
5.26k stars 1.31k forks source link

[Bug]: Swagger tofile doesn't work when the api needs authentication #3124

Open jerryxu1234 opened 1 week ago

jerryxu1234 commented 1 week ago

Describe the bug

in my azure pipeline, When running swagger tofile myapi.dll swagger.json, authentication exception was thrown out. From the trace, problem happens as it can't access our azure keyvault. however, I already passed spn into azure cli task and it and the identity defined in azureSubscription arlready have access to keyvault (as we use same identity for other purpose in the same pipeline and there it has no problem to access the keyvault)

Expected behavior

the identity should be passed to keyvault

Actual behavior

exception was thrown out

Steps to reproduce

No response

Exception(s) (if any)

Unhandled exception. Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProviderException: Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net,/ Authority: https://login.microsoftonline.com/xxxx. Exception Message: Tried the following 3 methods to get an access token, but none of them worked. Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net,/ Authority: https://login.microsoftonline.com/xxxx. Exception Message: Tried to get token using Managed Service Identity. Access token could not be acquired. MSI ResponseCode: BadRequest, Response: {"error":"invalid_request","error_description":"Identity not found"} Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net,/ Authority: https://login.microsoftonline.com/82f41f1b-d00f-4f7b-a740-e0fd8515f272. Exception Message: Tried to get token using Visual Studio. Access token could not be acquired. Visual Studio Token provider file not found at "C:\Users\VssAdministrator\AppData\Local.IdentityService\AzureServiceAuth\tokenprovider.json" Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net,/ Authority: https://login.microsoftonline.com/82f41f1b-d00f-4f7b-a740-e0fd8515f272. Exception Message: Tried to get token using Azure CLI. Access token could not be acquired. 'az' is not recognized as an internal or external command, operable program or batch file.

at Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProvider.GetAccessTokenAsyncImpl(String authority, String resource, String scope) at Microsoft.Azure.KeyVault.KeyVaultCredential.PostAuthenticate(HttpResponseMessage response) at Microsoft.Azure.KeyVault.KeyVaultCredential.ProcessHttpRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken) at Microsoft.Azure.KeyVault.KeyVaultClient.GetSecretsWithHttpMessagesAsync(String vaultBaseUrl, Nullable1 maxresults, Dictionary2 customHeaders, CancellationToken cancellationToken) at Microsoft.Azure.KeyVault.KeyVaultClientExtensions.GetSecretsAsync(IKeyVaultClient operations, String vaultBaseUrl, Nullable1 maxresults, CancellationToken cancellationToken) at Microsoft.Extensions.Configuration.AzureKeyVault.AzureKeyVaultConfigurationProvider.LoadAsync() at Microsoft.Extensions.Configuration.AzureKeyVault.AzureKeyVaultConfigurationProvider.Load() at Microsoft.Extensions.Configuration.ConfigurationRoot..ctor(IList1 providers) at Microsoft.Extensions.Configuration.ConfigurationBuilder.Build() at Microsoft.Extensions.Hosting.HostBuilder.InitializeAppConfiguration() at Microsoft.Extensions.Hosting.HostBuilder.Build() at FE.Thunder.Api.Program.Main(String[] args) in D:\a\1\s\FE.Thunder.DataApi\Program.cs:line 17 at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor) at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr) --- End of stack trace from previous location --- at Microsoft.Extensions.Hosting.HostFactoryResolver.HostingListener.CreateHost() in /_/src/Swashbuckle.AspNetCore.Cli/HostFactoryResolver.cs:line 276 at Microsoft.Extensions.Hosting.HostFactoryResolver.<>c__DisplayClass8_0.b_0(String[] args) in //src/Swashbuckle.AspNetCore.Cli/HostFactoryResolver.cs:line 75

Swashbuckle.AspNetCore version

latest

.NET Version

net8.0

Anything else?

No response

martincostello commented 1 week ago

The context in which Swashbuckle runs your app to retrieve the OpenAPI document(s) isn't able to see the az CLI on the path:

'az' is not recognized as an internal or external command, operable program or batch file

The tool should inherit any environment variables from the parent process that invokes it. The tool can't add any special handling for things like Azure, AWS, Google Cloud, etc. services for credentials or any other tools.

You'll need to debug why the environment information isn't getting through to your app, or if it is, why your app code when invoked by Swashbuckle isn't seeing the information.

There's not anything we can do for you here.

jerryxu1234 commented 1 week ago

Hi, I don't think that is what the problem is. the azure identity nuget package tries 3 different method to authenticate

  1. Manged identity
  2. Visual studio identity
  3. AZ identity When no identity can be found, it will throw exception. The exception we see here shows that no identity can be found after trying 3.

The biggest problem is your code uses reflection to run the web API's program.cs. I don't believe this would pass the identity to the refelected code

martincostello commented 1 week ago

I don't believe this would pass the identity to the refelected code

It doesn't no, but why would it need to? And if it did, how would it ever do that without special-casing exactly what your specific use case needs?

The stack trace also shows that it isn't failing to find any identity because:

  1. There's no managed identity;
  2. It can't find C:\Users\VssAdministrator\AppData\Local.IdentityService\AzureServiceAuth\tokenprovider.json;
  3. It can't find az to acquire a credential through other means.

You'll need to debug why the environment information isn't getting through to your app, or if it is, why your app code when invoked by Swashbuckle isn't seeing the information.

There's nothing actionable for us to do here - you need to dig into your code and pipeline and work out why the code can't see these things.

Alternatively, change your code to detect that it's being run in the context of the Swashbuckle CLI, and skip trying to interact with Key Vault (or anything else you can't access/use in that context) at all, then your app should start up enough to be able to generate the OpenAPI document.

jerryxu1234 commented 1 week ago

hi, it can't see these things because you used reflection to call the api? that is the reason.

martincostello commented 1 week ago

That's irrelevant - how would using reflection affect the ability for the code to see C:\Users\VssAdministrator\AppData\Local.IdentityService\AzureServiceAuth\tokenprovider.json or az?