Azure / azure-functions-core-tools

Command line tools for Azure Functions
MIT License
1.29k stars 426 forks source link

Host crashes due to dependency on System.IdentityModel.Tokens.Jwt 6.35.0 #3770

Open scottrudy opened 1 month ago

scottrudy commented 1 month ago

Version

PS C:\source> func --version 4.0.5907 PS C:\source> dotnet --info .NET SDK: Version: 8.0.303 Commit: 29ab8e3268 Workload version: 8.0.300-manifests.7ccdde63 MSBuild version: 17.10.4+10fbfbf2e

Runtime Environment: OS Name: Windows OS Version: 10.0.22631 OS Platform: Windows RID: win-x64 Base Path: C:\Program Files\dotnet\sdk\8.0.303\

.NET workloads installed: [aspire] Installation Source: SDK 8.0.300 Manifest Version: 8.0.2/8.0.100 Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.aspire\8.0.2\WorkloadManifest.json Install Type: FileBased

Host: Version: 8.0.7 Architecture: x64 Commit: 2aade6beb0

.NET SDKs installed: 8.0.303 [C:\Program Files\dotnet\sdk]

.NET runtimes installed: Microsoft.AspNetCore.App 8.0.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.NETCore.App 6.0.32 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 8.0.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.WindowsDesktop.App 8.0.7 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Description

My application worked fine about two weeks ago. I'm not sure if it was the most recent .Net SDK update or the last AFCT update, but now I have an application, which uses the Microsoft.GraphClient, that no longer runs locally despite no code updates due to the following error:

[2024-07-16T01:10:54.847Z] An unhandled host error has occurred.
[2024-07-16T01:10:54.848Z] System.Private.CoreLib: Exception has been thrown by the target of an invocation. Microsoft.AspNetCore.Authentication.JwtBearer: Could not load file or assembly 'System.IdentityModel.Tokens.Jwt, Version=6.35.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. The system cannot find the file specified.

My first thought was to update all of the libraries to the latest, which I have done, but the issue persists. I read a SO answer that mentioned there was a change in that library from v6 to v7 that deals with a migration off of Newtonsoft, which I am not using. I tried the suggestion of explicitly using 7.6.3 of the OpenId Connect library, but no luck. My csproj is as follows:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <AzureFunctionsVersion>v4</AzureFunctionsVersion>
    <OutputType>Exe</OutputType>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <ItemGroup>
    <FrameworkReference Include="Microsoft.AspNetCore.App" />
    <PackageReference Include="Azure.Identity" Version="1.12.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.22.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.2.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore" Version="1.3.2" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.17.4" />
    <PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.22.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.ApplicationInsights" Version="1.2.0" />
    <PackageReference Include="Microsoft.Graph" Version="5.56.0" />
  </ItemGroup>
  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
  </ItemGroup>
  <ItemGroup>
    <Using Include="System.Threading.ExecutionContext" Alias="ExecutionContext" />
  </ItemGroup>
</Project>

My Program.cs looks like this:

using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection;

var host = new HostBuilder()
    .ConfigureFunctionsWebApplication()
    .ConfigureServices(services => {
        services.AddApplicationInsightsTelemetryWorkerService();
        services.ConfigureFunctionsApplicationInsights();
        services.AddLogging();
        services.AddHttpClient();
    })
    .Build();

host.Run();

Lastly my function looks like this:

using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using My.Client.Models;
using System.Text.Json;
using Microsoft.Graph;
using Azure.Identity;
using Microsoft.Graph.Models;
using Microsoft.Graph.Users.Item.SendMail;

namespace My.Client;

public class AppointmentRequest(ILogger<AppointmentRequest> logger, IHttpClientFactory httpClientFactory)
{
    private readonly ILogger<AppointmentRequest> _logger = logger;
    private readonly HttpClient _client = httpClientFactory.CreateClient();

    [Function("AppointmentRequest")]
    public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequest req)
    {
        string requestBody = await new StreamReader(req.Body).ReadToEndAsync().ConfigureAwait(false);
        Appointment data;

        try {
            data = JsonSerializer.Deserialize<Appointment>(requestBody) ?? new Appointment();
        } catch (JsonException) {
            return new BadRequestResult();
        }

        var userId = Environment.GetEnvironmentVariable("userId", EnvironmentVariableTarget.Process);
        var email = Environment.GetEnvironmentVariable("email", EnvironmentVariableTarget.Process);

        GraphServiceClient graphServiceClient = GetGraphServiceClient();

        var easternTime = TimeZoneInfo.ConvertTimeFromUtc(DateTimeOffset.UtcNow.DateTime,
            TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"));

        await graphServiceClient.Users[userId]
            .SendMail
            .PostAsync(new SendMailPostRequestBody {
                Message = new Message {
                    Subject = "Appointment Request",
                    Body = new ItemBody {
                        ContentType = BodyType.Html,
                        Content = $@""
                    },
                    ToRecipients = new List<Recipient> {
                        new Recipient {
                            EmailAddress = new EmailAddress {
                                Address = email
                            }
                        }
                    }
                },
                SaveToSentItems = false
            }).ConfigureAwait(false);
        _logger.LogInformation("mail appointment");

        return new StatusCodeResult(StatusCodes.Status201Created);
    }

    private static GraphServiceClient GetGraphServiceClient() {
        var clientId = Environment.GetEnvironmentVariable("clientId", EnvironmentVariableTarget.Process);
        var clientSecret = Environment.GetEnvironmentVariable("clientSecret", EnvironmentVariableTarget.Process);
        var tenantId = Environment.GetEnvironmentVariable("tenantId", EnvironmentVariableTarget.Process);

        var scopes = new string[] { "https://graph.microsoft.com/.default" };

        var options = new ClientSecretCredentialOptions
        {
            AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
        };

        var clientSecretCredential = new ClientSecretCredential(tenantId, clientId, clientSecret, options);

        var graphServiceClient = new GraphServiceClient(clientSecretCredential, scopes);   

        return graphServiceClient;
    }    
}

Steps to reproduce

Run func start Invoke the endpoint

scottrudy commented 1 month ago

This issue is definitely related to Azure Function Core Tools version 4.0.5907. Rolling back to 4.0.5858 is a confirmed workaround. Note that C:\Program Files\Microsoft\Azure Functions Core Tools\System.IdentityModel.Tokens.Jwt.dll is not present in 4.0.5907, but is in 4.0.5858. Seems it could be related to issue #3715 and PR #3724

winget uninstall Microsoft.Azure.FunctionsCoreTools
winget uninstall Microsoft.DotNet.SDK.8
winget install Microsoft.DotNet.SDK.8 --version 8.0.107
winget install Microsoft.Azure.FunctionsCoreTools --version 4.0.5858
rm bin
rm obj
func start

Confirmed everything is working

winget upgrade Microsoft.DotNet.SDK.8
rm bin
rm obj
func start

Confirmed everything is working

winget upgrade Microsoft.Azure.FunctionsCoreTools
rm bin
rm obj
func start

The error returns

winget uninstall Microsoft.Azure.FunctionsCoreTools
winget install Microsoft.Azure.FunctionsCoreTools --version 4.0.5858
rm bin
rm obj
func start

Confirmed everything is working

kshyju commented 1 month ago

The host has a reference to this package - https://github.com/Azure/azure-functions-host/blob/4c01fca2f46095421be5f9a51146a8f3ea835031/src/WebJobs.Script.WebHost/WebJobs.Script.WebHost.csproj#L86

I will investigate your repro and see what is going on. Thanks!

dungarDot commented 1 month ago

Just dropping by to say i'm being hit with the same error. Things still seem to run but it just spams the error out and I haven't bothered to let it run long enough to see if my timer trigger fires.

I'm using F# ,but package wise it's just

open Microsoft.Extensions.Hosting open Microsoft.Azure.Functions.Worker open Microsoft.Extensions.DependencyInjection

In the main and

open System open Microsoft.Azure.Functions.Worker open Microsoft.Extensions.Logging

in the timer.

Literally just setup by running the dotnet new func --lang F# followed by dotnet new timer --lang F# and some mild tweaking to those templates, and you'll get the error.

Only started after I updated my azure core tools today.

Edit-

Tested just the raw timer trigger set to fire every minute. It does execute, so might be possible to still run your code depending on use case, but obviously you'll flood with errors.

image

aishwaryabh commented 3 weeks ago

Hi I'm trying to repro this issue with core tools version 4.0.5907 and I'm not able to repro this issue. Can I get a step by step repro if possible?

scottrudy commented 3 weeks ago

I created a new azure function using the CLI tools along with VS Code. The code above indicates the nuget packages I used in my project. Once in place, run or F5 debug and the error appears.