2
votes

I'm trying to authenticate to our online Dynamics CRM to use the available APIs.

The only official documentation on doing this I can find is: https://docs.microsoft.com/en-us/dynamics365/customer-engagement/developer/connect-customer-engagement-web-services-using-oauth this however uses 'AquireToken' which no longer exists in ADAL V3, with it having been replaced with 'AcquireTokenAsync'.

This is my first time dealing with ADAL and trying to authenticate, previously only having dealt with 'HttpWebRequest' custom APIs.

I'm currently just trying to have the code run without any errors, using what is on docs.microsoft.com I've tried changing 'AcquireToken' to 'AcquireTokenAsync'.

public void authenticateToCRM()
        {
            // TODO Substitute your correct CRM root service address,   
            string resource = "https://qqqqqqqqq.crm4.dynamics.com";

            // TODO Substitute your app registration values that can be obtained after you  
            // register the app in Active Directory on the Microsoft Azure portal.  
            string clientId = "******-****-*******-*****-****";
            string redirectUrl = "https://qqqqqqqqq.azurewebsites.net";

            // Authenticate the registered application with Azure Active Directory.  
            AuthenticationContext authContext = new AuthenticationContext("https://login.windows.net/common", false);
            AuthenticationResult result = authContext.AcquireTokenAsync(resource, clientId, new Uri(redirectUrl));
        }

This results in an error for the 'clientId' string variable in 'AcquireToken' the error being...

"Argument 2: cannot convert from 'string' to 'Microsoft.IdentityModel.Clients.ActiveDirectory.ClientCredentials"

and error on the 3rd variable 'new Uri(redirectUrl)', of...

"Argument 3: cannot convert from 'System.Uri' to 'Microsoft.IdentityModel.Clients.ActiveDirectory.UserAssertion"

Looking at the documentation for 'AuthenticationContext' Class and the usage of 'AcquireTokenAsync' many have a string as the 2nd argument: https://docs.microsoft.com/en-us/dotnet/api/microsoft.identitymodel.clients.activedirectory.authenticationcontext?view=azure-dotnet

I do not know how to translate the usage for authentication with 'AcquireToken' shown in the ms docs to use with 'AcquireTokenAsync'

1
The CRM SDK samples use ADAL 2.x which allows for passing username and password credentials. This was removed in ADAL 3.x. It is fine to continue to use the 2.x generation library. The answer below requires that you specify a client secret in your app registration and is an example more applicable to a server-to-server scenario.described here: docs.microsoft.com/en-us/dynamics365/customer-engagement/…Jim Daly -MSFT-

1 Answers

4
votes
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Data;
using System.Data.SqlClient;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace MYFORM_Form.Controllers
{
    public class MYController : Controller
    {
        string organizationUrl = "https://yourcrm.dynamics.com";
        string appKey = "*****";
        string aadInstance = "https://login.microsoftonline.com/";
        string tenantID = "myTenant.onmicrosoft.com";
        string clientId = "UserGUID****";
        public Task<String> SendData()
        {
            return AuthenticateWithCRM();
        }

        public async Task<String> AuthenticateWithCRM()
        {
            ClientCredential clientcred = new ClientCredential(clientId, appKey);
            AuthenticationContext authenticationContext = new AuthenticationContext(aadInstance + tenantID);
            AuthenticationResult authenticationResult = await authenticationContext.AcquireTokenAsync(organizationUrl, clientcred);
            using (HttpClient httpClient = new HttpClient())
                {
                    httpClient.BaseAddress = new Uri(organizationUrl);
                    httpClient.Timeout = new TimeSpan(0, 2, 0);  // 2 minutes  
                    httpClient.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
                    httpClient.DefaultRequestHeaders.Add("OData-Version", "4.0");
                    httpClient.DefaultRequestHeaders.Accept.Add(
                    new MediaTypeWithQualityHeaderValue("application/json"));
                    httpClient.DefaultRequestHeaders.Authorization =
                    new AuthenticationHeaderValue("Bearer", authenticationResult.AccessToken);
                    JObject myContact = new JObject
                        {
                            {"[EntityFieldname]", "[ValueToBeAdded]"}
                        };

                        HttpResponseMessage CreateResponse = await SendAsJsonAsync(httpClient, HttpMethod.Post, "api/data/v8.2/[EntityName]", myContact);

                        Guid applicationID = new Guid();
                        if (CreateResponse.IsSuccessStatusCode)
                        {
                            string applicationUri = CreateResponse.Headers.GetValues("OData-EntityId").FirstOrDefault();
                            if (applicationUri != null)
                                applicationID = Guid.Parse(applicationUri.Split('(', ')')[1]);
                            Console.WriteLine("Account created Id=", applicationID);
                            return applicationID.ToString();
                        }
                        else
                            return null;
                }

        }

        public static Task<HttpResponseMessage> SendAsJsonAsync<T>(HttpClient client, HttpMethod method, string requestUri, T value)
        {
            var content = value.GetType().Name.Equals("JObject") ?
                value.ToString() :
                JsonConvert.SerializeObject(value, new JsonSerializerSettings() { DefaultValueHandling = DefaultValueHandling.Ignore });

            HttpRequestMessage request = new HttpRequestMessage(method, requestUri) { Content = new StringContent(content) };
            request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
            request.Headers.Add("User-Agent", "User-Agent-Here");
            return  client.SendAsync(request);
        }
    }
}