extensions: KeyVault 2.2 nuget: Could not load file or assembly 'Microsoft.IdentityModel.Clients.ActiveDirectory.Platform'

Describe the bug

I utilize one library that requires Microsoft.IdentityModel.Clients.ActiveDirectory >= 4.5.0, however starting with version >= 4 of that library, the dependency namespace ‘Microsoft.IdentityModel.Clients.ActiveDirectory.Platform’ is no longer listed.

The Microsoft.Extensions.Configuration.AzureKeyVault v2.2.0 nuget package requires Microsoft.IdentityModel.Clients.ActiveDirectory >= 3.14.x which does have the required dependency namespace ‘Microsoft.IdentityModel.Clients.ActiveDirectory.Platform’

Microsoft.Extensions.Configuration.AzureKeyVault v2.2.0 crashes on not finding the ‘Microsoft.IdentityModel.Clients.ActiveDirectory.Platform’ dependency because in my solution I am using Microsoft.IdentityModel.Clients.ActiveDirectory v4.5.0.

I cannot downgrade Microsoft.IdentityModel.Clients.ActiveDirectory to 3.19.8 as alot of posts have suggested because my other dependency requires >= 4.5.0.

To Reproduce

Steps to reproduce the behavior:

  1. Use version ‘2.2.0’ of package ‘Microsoft.Extensions.Configuration.AzureKeyVault’
  2. Use version ‘4.4.3’ of package ‘Microsoft.Bot.Builder’
  3. Run this StatelessService code in a .net core project:
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
    return new ServiceInstanceListener[]
    {
        new ServiceInstanceListener(serviceContext =>
            new KestrelCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
            {
                ServiceEventSource.Current.ServiceMessage(serviceContext, $"Starting Kestrel on {url}");
                return WebHost.CreateDefaultBuilder()
                    .ConfigureAppConfiguration((context, config) =>
                    {
                            var keyVaultName = "<KEYVAULT NAME>";
                            var azureServiceTokenProvider = new AzureServiceTokenProvider();
                            var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
                            config.AddAzureKeyVault(keyVaultName, keyVaultClient, new DefaultKeyVaultSecretManager());
                    })
                    .ConfigureServices(
                        services => services
                            .AddSingleton<StatelessServiceContext>(serviceContext))
                    .UseStartup<Startup>()
                    .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
                    .UseUrls(url)
                    .Build();
            })),
    };
}

Expected behavior

Service starts up and runs.

Failing behavior is that FileNotFoundException is thrown with error Could not load file or assembly ‘Microsoft.IdentityModel.Clients.ActiveDirectory.Platform’

Additional context

Add any other context about the problem here.

$ dotnet --info
Zestaw .NET Core SDK (odzwierciedlenie dowolnego pliku global.json):
 Version:   2.2.106
 Commit:    aa79b139a8

Srodowisko uruchomieniowe:
 OS Name:     Windows
 OS Version:  10.0.17763
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\2.2.106\

Host (useful for support):
  Version: 2.2.4
  Commit:  f95848e524

.NET Core SDKs installed:
  1.0.0-preview2-003131 [C:\Program Files\dotnet\sdk]
  1.0.0 [C:\Program Files\dotnet\sdk]
  1.0.4 [C:\Program Files\dotnet\sdk]
  1.1.0 [C:\Program Files\dotnet\sdk]
  2.1.101 [C:\Program Files\dotnet\sdk]
  2.1.202 [C:\Program Files\dotnet\sdk]
  2.1.402 [C:\Program Files\dotnet\sdk]
  2.1.403 [C:\Program Files\dotnet\sdk]
  2.1.500 [C:\Program Files\dotnet\sdk]
  2.1.502 [C:\Program Files\dotnet\sdk]
  2.1.505 [C:\Program Files\dotnet\sdk]
  2.2.106 [C:\Program Files\dotnet\sdk]

.NET Core runtimes installed:
  Microsoft.AspNetCore.All 2.1.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.2.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.App 2.1.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.2.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 1.0.1 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 1.0.4 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 1.0.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 1.1.1 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 1.1.2 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.0.6 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.0.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.4 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.6 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.2.4 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 21 (1 by maintainers)

Most upvoted comments

I don’t think that’s an option for me as I’m running on dotnet core 3.1 and the 3.14.2 DLL isn’t compatible with that from what I understand.

Moreover, I’m interested in a response from the ASPNet team on the proper fix for this.

Just ran into this as well. The problem is sinister because .Platform it isn’t listed as a direct dependency of anything other than AppAuth. However, forcing AppAuth to 1.4 doesn’t help as something in the configuration extensions IS referencing platform without stating it’s dependency as direct.

Even if this wasn’t breaking, this should be fixed to help customers align various dependency chains where possible.

https://www.nuget.org/packages/Microsoft.Azure.Services.AppAuthentication/1.4.0 has been released

Can we get an update on when Microsoft.Extensions.Configuration.AzureKeyVault will be modified to use it?

I am seeing the same issue with 3.1.1 on netCore3.1. I am trying to build with following references.

<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.1" />
<PackageReference Include="Microsoft.ServiceFabric.AspNetCore.Kestrel" Version="4.0.464" />
<PackageReference Include="Microsoft.Bot.Builder.Integration.AspNet.Core" Version="4.7.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.1" />

We’ve got a complete update to our Azure Integration packages like this (as well as DataProtection) coming soon (as part of the 3.1 series of packages). The newer Azure SDK packages include breaking changes so these will be introduced as new packages rather than an update to the existing ones. However, the API is the same (the “breaking change” is that they bring in the new Azure SDK, which may be breaking to your app if you are using the SDK directly somewhere).

FYI: The 2.2 packages are end-of-life and 3.0 is not far behind it. I’d suggest moving to 3.1 when these new packages are released (I’ll update this thread when that happens). See the full .NET Core support policy for more information.

Same issue as @dotnetcanuck and @Mdub28. Using a certificate to authorize with key vault. Found that using client secret works, but that’s not really a solution, at best a temporary fix if the cert issue is getting fixed.

Anyways, implementing the keyvault client your self seems to work fine…

public class ShitfixKeyVaultClient : KeyVaultClient
{
    private static readonly TokenCache tokenCache = new TokenCache();
    private static Dictionary<string,X509Certificate2> certificates = new Dictionary<string, X509Certificate2>();

    public ShitfixKeyVaultClient(string clientId, string thumbprint) 
        : base((authority, resource, scope) => GetAccessTokenAsync(clientId, thumbprint, authority, resource, scope))
    {
    }

    public static async Task<string> GetAccessTokenAsync(string clientId, string thumbprint, string authority, string resource, string scope)
    {
        var pfx = FindCertificateByThumbprint(thumbprint, StoreLocation.CurrentUser);

        AuthenticationContext authContext = new AuthenticationContext(authority, tokenCache);
        var credentials = new ClientAssertionCertificate(clientId, pfx);
        var authToken = await authContext.AcquireTokenAsync(resource, credentials);
        return authToken.AccessToken;
    }

    private static X509Certificate2 FindCertificateByThumbprint(string findValue, StoreLocation location)
    {
        if (certificates.ContainsKey(findValue))
            return certificates[findValue];

        X509Store store = new X509Store(StoreName.My, location);
        try
        {
            store.Open(OpenFlags.ReadOnly);
            X509Certificate2Collection col = store.Certificates.Find(X509FindType.FindByThumbprint, findValue, false);
            if (col == null || col.Count == 0)
                return null;

            certificates[findValue] = col[0];
            return col[0];
        }
        finally
        {
            store.Close();
        }
    }
}

And can be used like

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((ctx, configBuilder) =>
        {
            var config = configBuilder.Build();
            var client = new ShitfixKeyVaultClient(config["AzureAd:ClientId"], config["AzureAd:CertThumprint"]);
            configBuilder.AddAzureKeyVault("https://myvault.vault.azure.net", client, new DefaultKeyVaultSecretManager());
        })
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        });

Probably gonne be a better way to do this, but after a day of 🤔 😕 😖 😭 😠 🤔 i’m not gonne spend more time on this 😛

@Pilchie Regarding the last few comments, is this something we should update? (I believe I only sent the PR last time while helping Nate get things working.)

@MattSFT This is still an issue even with using AppAuth v1.3.0. Regardless of which version of AppAuth I use, Microsoft.Extensions.Configuration.AzureKeyVault requires Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll to exist. In fact, for my app using cert auth into keyvault, AppAuth isn’t even being used and the reference to Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll seems to be directly from AzureKeyVault. I was able to get my app to work by manually including the missing dll, without having to reference AppAuth at all. Seems like this is an issue that needs to be fixed with AzureKeyVault as it has an implicit dependency on Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll and one that is outdated as the dll is no longer packaged in later versions. If any other dependency requires higher version of ActiveDirectory, then you will be unable to run your app without manually referencing a downloaded Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll.

My code usage:

        return WebHost.CreateDefaultBuilder(args)
           .UseSetting(WebHostDefaults.DetailedErrorsKey, "true")
           .ConfigureAppConfiguration((context, builder) =>
           {
               builder.AddDMServiceConfiguration(context);
               var builtConfig = builder.Build();
               using (var store = new X509Store(StoreName.My,StoreLocation.CurrentUser))
               {
                   store.Open(OpenFlags.ReadOnly);
                   var certs = store.Certificates
                       .Find(X509FindType.FindByThumbprint, builtConfig["ApplicationIdentity:CertThumbprint"], false);

                   builder.AddAzureKeyVault(
                       $"https://{builtConfig["KeyVault:Name"]}.vault.azure.net/",
                       builtConfig["ApplicationIdentity:AppId"],
                       certs.OfType<X509Certificate2>().Single());

                   store.Close();
               }
           })
           .ConfigureServices((context, serviceCollection) =>
           {
               serviceCollection.AddDMLogging(context);
           });