Reputation: 521
Sometimes you need to know the answer to ask the right question, so I'm not sure if the title of this query is perfect. Anyway here goes.
I've developed an Azure Function App (time trigger based) to connect to Dynamics 365 online and do some work. All good! As this was a POC and I wanted to see what was possible, I wrote the following code.
IServiceManagement<IOrganizationService> orgServiceManagement;
orgServiceManagement = ServiceConfigurationFactory.CreateManagement<IOrganizationService>(new Uri(System.Environment.GetEnvironmentVariable("OrganizationService")));
AuthenticationCredentials authCredentials = new AuthenticationCredentials();
authCredentials.ClientCredentials.UserName.UserName = "[Non-interactive CRM Username here]";
authCredentials.ClientCredentials.UserName.Password = "[Password here]";
AuthenticationCredentials tokenCredentials;
tokenCredentials = orgServiceManagement.Authenticate(authCredentials);
OrganizationServiceProxy organizationProxy = new OrganizationServiceProxy(orgServiceManagement, tokenCredentials.SecurityTokenResponse);
My question... obviously now that the POC works I want to find a way to authenticate the Function App against Azure AD (instead of passing credentials in code) and get an access token that I can use to create my OrganisationServiceProxy, but how do I go about this. I cant seem to find a straight answer out there. Lots of architect-style answers that are way up in the clouds. I need developer-style answers (do this, then do that) :)
I'm sure a lot of newbie azure developers out there will find this useful to know. Thanks in advance.
Note for editors: This question isn't the same as Authenticate with Dynamics 365 from an Azure Function as I'm in the same tenant and subscription, using time triggers and not web hooks. My function app wakes up, connects to CRM, does some calculations, updates CRM and goes back to sleep.
Upvotes: 1
Views: 4162
Reputation: 521
I've managed to secure my credentials using the Azure Key Vault. For those newbies out there who are looking to do the same ... here are the steps.
Add the following using statements to the top of your code.
using Microsoft.Azure.KeyVault;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
If your function app code is in the Azure Portal, then add the following to your project.json file.
{ "frameworks": { "net46": { "dependencies": { "Microsoft.IdentityModel.Clients.ActiveDirectory": "3.13.4", "Microsoft.Azure.KeyVault": "2.0.1-preview", "Microsoft.AspNet.WebApi.Client": "5.2.3", "Microsoft.CrmSdk.CoreAssemblies": "9.0.0.7" } } } }
If you are using Visual Studio, then you will need to ensure that you add the above references to your project.
Please see my original post above to see how I was using credentials in code to how I've changed them now in the code below.
AuthenticationCredentials authCredentials = new AuthenticationCredentials(); authCredentials.ClientCredentials.UserName.UserName = GetKVSecret("Secret1", log); authCredentials.ClientCredentials.UserName.Password = GetKVSecret("Secret2", log);
And now here is the code for the GetKVSecret function.
private static string GetKVSecret(string secretName, TraceWriter log)
{
var adClientId = System.Environment.GetEnvironmentVariable("AppADClientID");
var adKey = System.Environment.GetEnvironmentVariable("AppADKey");
var secret = System.Environment.GetEnvironmentVariable(secretName);
var keyVault = new KeyVaultClient(async (string authority, string resource, string scope) => {
var authContext = new AuthenticationContext(authority);
var credential = new ClientCredential(adClientId, adKey);
var token = await authContext.AcquireTokenAsync(resource, credential);
return token.AccessToken;
});
string returnValue;
try
{
returnValue = keyVault.GetSecretAsync(secret).Result.Value;
log.Info("Secret retrieved from Key Vault");
}
catch (Exception error)
{
log.Error("Unable to get secrets from Azure Key Vault.", error);
throw;
}
return returnValue;
}
Last step, you can see that I'm picking up the AppADClientID and AppADKey from the config. So you will need to create the following entries in your app settings screen.
AppADClientID: the value you got from step 3
AppADKey: the value you got from step 4
secret1: the value you got from step 2
secret2: the value you got from step 2
secret1 and 2 might vary depending on the number of secrets you created.
So there! I hope you find this useful and if you have any queries please post them here, I'll try my best to answer them. I have to end by giving credit to the following resources which helped me along the way.
PS. This has been a pita to post the solution with code. Stackoverflow kept preventing me from submitting saying that I had code in the window that wasnt formatted correctly. However, I later realised it was the 'automatic' bullet formatting on the bullet points that was conflicting with the code inserts. Eitherway I think stack overflow should not prevent a post as it could mean content providers will give up in frustration (we have other paying jobs to do!)
Upvotes: 1