Reputation: 11
I have an Azure Functions application that needs to retrieve a secret to authenticate with the Azure SDK for .Net.
[FunctionName("FunctionName")]
public static async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Function, "POST")] HttpRequestMessage req,
TraceWriter log
)
{
string vaultName, secretName, clientId, clientSecret = string.Empty;
IEnumerable<object> items = null;
try
{
var context = await req.Content.ReadAsAsync<Context>();
clientId = ConfigurationManager.AppSettings["clientId"].ToString();
vaultName = ConfigurationManager.AppSettings["vaultName"].ToString();
secretName = ConfigurationManager.AppSettings["secretName"].ToString();
AzureServiceTokenProvider tokenProvider = new AzureServiceTokenProvider();
try
{
var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(tokenProvider.KeyVaultTokenCallback));
var secret = await keyVaultClient.GetSecretAsync(string.Format("https://{0}.vault.azure.net/secrets/{1}", vaultName, secretName));
clientSecret = secret.Value;
}
catch
{
throw new Exception("Can't get secret.");
}
ServiceClientCredentials serviceCredentials = await ApplicationTokenProvider.LoginSilentAsync(context.cloudTenantId, context.cloudSubscriptionId, clientSecret);
using (ResourceManagementClient client = new ResourceManagementClient(serviceCredentials))
{
items = OtherFunction(client);
}
}
catch (Exception ex)
{
log.Error(ex.Message, ex);
return req.CreateResponse(HttpStatusCode.InternalServerError, ex);
}
return req.CreateResponse(HttpStatusCode.OK, items);
}
When this function executes, it returns a System.IO.FileNotFoundException
with the following stacktrace
at Microsoft.Rest.Azure.Authentication.ApplicationTokenProvider.<LoginSilentAsync>d__12.MoveNext()
at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Start[TStateMachine](TStateMachine& stateMachine)
at Microsoft.Rest.Azure.Authentication.ApplicationTokenProvider.LoginSilentAsync(String domain, String clientId, String secret)
at HcfApi.Src.PRIP1.<DesiredStateConfigCheck>d__0.MoveNext()
and message
Could not load file or assembly 'Microsoft.IdentityModel.Clients.ActiveDirectory, Version=2.28.3.860, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.
I suspect that this is a collision between versions of Microsoft.IdentityModel.Clients.ActiveDirectory
used in ApplicationTokenProvider (>=2.28.3)
and AzureServiceTokenProvider (>= 3.14.2)
.
Is there a way to get around these dependencies?
Update: I have a more detailed output of the exception encountered:
{
"ClassName": "System.IO.FileNotFoundException",
"Message": "Could not load file or assembly 'Microsoft.IdentityModel.Clients.ActiveDirectory, Version=2.28.3.860, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.",
"Data": null,
"InnerException": null,
"HelpURL": null,
"StackTraceString": " at Microsoft.Rest.Azure.Authentication.ApplicationTokenProvider.<LoginSilentAsync>d__12.MoveNext()\r\n at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Start[TStateMachine](TStateMachine& stateMachine)\r\n at Microsoft.Rest.Azure.Authentication.ApplicationTokenProvider.LoginSilentAsync(String domain, String clientId, String secret)\r\n at HcfApi.Src.PRDS1.<StorageEncryptionCheck>d__1.MoveNext()",
"RemoteStackTraceString": null,
"RemoteStackIndex": 0,
"ExceptionMethod": "8\nMoveNext\nMicrosoft.Rest.ClientRuntime.Azure.Authentication, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\nMicrosoft.Rest.Azure.Authentication.ApplicationTokenProvider+<LoginSilentAsync>d__12\nVoid MoveNext()",
"HResult": -2147024894,
"Source": "Microsoft.Rest.ClientRuntime.Azure.Authentication",
"WatsonBuckets": null,
"FileNotFound_FileName": "Microsoft.IdentityModel.Clients.ActiveDirectory, Version=2.28.3.860, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
"FileNotFound_FusionLog": "=== Pre-bind state information ===\r\nLOG: DisplayName = Microsoft.IdentityModel.Clients.ActiveDirectory, Version=2.28.3.860, Culture=neutral, PublicKeyToken=31bf3856ad364e35\n (Fully-specified)\r\nLOG: Appbase = file:///D:/Program Files (x86)/SiteExtensions/Functions/1.0.11959/\r\nLOG: Initial PrivatePath = D:\\Program Files (x86)\\SiteExtensions\\Functions\\1.0.11959\\bin\r\nCalling assembly : Microsoft.Rest.ClientRuntime.Azure.Authentication, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35.\r\n===\r\nLOG: This bind starts in LoadFrom load context.\r\nWRN: Native image will not be probed in LoadFrom context. Native image will only be probed in default load context, like with Assembly.Load().\r\nLOG: Using application configuration file: D:\\Program Files (x86)\\SiteExtensions\\Functions\\1.0.11959\\web.config\r\nLOG: Using host configuration file: D:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\Aspnet.config\r\nLOG: Using machine configuration file from D:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\config\\machine.config.\r\nLOG: Post-policy reference: Microsoft.IdentityModel.Clients.ActiveDirectory, Version=2.28.3.860, Culture=neutral, PublicKeyToken=31bf3856ad364e35\r\nLOG: Attempting download of new URL file:///D:/local/Temporary ASP.NET Files/root/fbd8a7cb/68424d13/Microsoft.IdentityModel.Clients.ActiveDirectory.DLL.\r\nLOG: Attempting download of new URL file:///D:/local/Temporary ASP.NET Files/root/fbd8a7cb/68424d13/Microsoft.IdentityModel.Clients.ActiveDirectory/Microsoft.IdentityModel.Clients.ActiveDirectory.DLL.\r\nLOG: Attempting download of new URL file:///D:/Program Files (x86)/SiteExtensions/Functions/1.0.11959/bin/Microsoft.IdentityModel.Clients.ActiveDirectory.DLL.\r\nLOG: Attempting download of new URL file:///D:/Program Files (x86)/SiteExtensions/Functions/1.0.11959/bin/Microsoft.IdentityModel.Clients.ActiveDirectory/Microsoft.IdentityModel.Clients.ActiveDirectory.DLL.\r\nLOG: Attempting download of new URL file:///D:/local/Temporary ASP.NET Files/root/fbd8a7cb/68424d13/Microsoft.IdentityModel.Clients.ActiveDirectory.EXE.\r\nLOG: Attempting download of new URL file:///D:/local/Temporary ASP.NET Files/root/fbd8a7cb/68424d13/Microsoft.IdentityModel.Clients.ActiveDirectory/Microsoft.IdentityModel.Clients.ActiveDirectory.EXE.\r\nLOG: Attempting download of new URL file:///D:/Program Files (x86)/SiteExtensions/Functions/1.0.11959/bin/Microsoft.IdentityModel.Clients.ActiveDirectory.EXE.\r\nLOG: Attempting download of new URL file:///D:/Program Files (x86)/SiteExtensions/Functions/1.0.11959/bin/Microsoft.IdentityModel.Clients.ActiveDirectory/Microsoft.IdentityModel.Clients.ActiveDirectory.EXE.\r\nLOG: Attempting download of new URL file:///D:/home/site/wwwroot/bin/Microsoft.IdentityModel.Clients.ActiveDirectory.DLL.\r\nWRN: Comparing the assembly name resulted in the mismatch: Major Version\r\nLOG: Attempting download of new URL file:///D:/home/site/wwwroot/bin/Microsoft.IdentityModel.Clients.ActiveDirectory/Microsoft.IdentityModel.Clients.ActiveDirectory.DLL.\r\nLOG: Attempting download of new URL file:///D:/home/site/wwwroot/bin/Microsoft.IdentityModel.Clients.ActiveDirectory.EXE.\r\nLOG: Attempting download of new URL file:///D:/home/site/wwwroot/bin/Microsoft.IdentityModel.Clients.ActiveDirectory/Microsoft.IdentityModel.Clients.ActiveDirectory.EXE.\r\n"}
Project Information: I am using Azure Functions Framework V1 and am targeting .Net 4.6.1
Update 2:
Here is the .csroj
file with assembly versions and project configurations.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net461</TargetFramework>
<AzureFunctionsVersion>v1</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.KeyVault" Version="3.0.0" />
<PackageReference Include="Microsoft.Azure.Management.Compute.Fluent" Version="1.14.0" />
<PackageReference Include="Microsoft.Azure.Management.Redis.Fluent" Version="1.14.0" />
<PackageReference Include="Microsoft.Azure.Management.ResourceManager.Fluent" Version="1.14.0" />
<PackageReference Include="Microsoft.Azure.Management.Sql.Fluent" Version="1.14.0" />
<PackageReference Include="Microsoft.Azure.Services.AppAuthentication" Version="1.0.3" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="1.0.14" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.5.0" />
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
</Project>
Upvotes: 0
Views: 953
Reputation: 11
I'll start by admitting that I over complicated this problem. There was no need to retrieve the secret as I can authenticate using TokenCredentials
object instantiated with a token from MSI.
For further clarification, ServiceClientCredentials
is an abstract class implemented by TokenCredentials
. Thus, Azure SDK management clients can be instantiated with the TokenCredentials
type.
Upvotes: 1