For Integrating CRM with outside world you might want to off load some of your work to Azure App services.
Azure Active Directory is one of the options for securing your Azure services so that they can be accessed only from Clients with Authentication credentials and Authorization to access the service.
There are a number a steps you need to follow in order to setup AAD and access them from CRM:
- First step is to Register the App Service in the same Tenant as your CRM Online instance
- This will generate 4 Authentication keys/ config items :
- ClientId – To identify the App
- Audience – Also known as the App Id URL, must be unique within your AAD
- Tenant – Same as your CRM Online Tenant
- Secret – More of a password
- This will generate 4 Authentication keys/ config items :
- Enable CORS in your Azure application
- Enable CORS in the browser in case you would be accessing the service from Javascript.
- Register your Client Application as a Web Application in same AAD. Give access to the Service we Registered in the 1st step.
Now let us see some code for accessing Azure services from Javascript and Plugins:
Here’s the javascript code:
$.ajax({ type: "POST", contentType: "application/x-www-form-urlencoded", datatype: "json", data: { "grant_type": "client_credentials", "client_id": {clientId}, "client_secret": {secret}, "resource": {resource} }, crossDomain: true, url: "https://login.windows.net/" + tenant + "/oauth2/token", success: function (data, textStatus, xhr) { debugger; //alert(data.access_token); var access_token = data.access_token; contactId = contactId.toString().substring(1, contactId.toString().length - 1); var url = { Service URL}; url = url + "/{End Point}; $.ajax({ type: "GET", data: "{}", cache: false, contentType: "application/json; charset=utf-8", datatype: "json", url: url, async: true, beforeSend: function (xhr) { xhr.setRequestHeader("Accept", "application/json"); xhr.setRequestHeader("Authorization", 'Bearer ' + access_token); }, success: function (data, textStatus, xhr) { if (onSuccessCallback != null) { onSuccessCallback(returnValue, textStatus); } }, error: function (xhr, textStatus, errorThrown) { if (onErrorCallback != null) { onErrorCallback(errorThrown, textStatus); } } }); }, error: function (xhr, textStatus, errorThrown) { // alert("failure"); } });
Plugin/C# code:
var t = token.Result; using (WebClientEx client = new WebClientEx()) { client.Timeout = 5 * 1000 * 60; client.Headers.Set("Content-Type", "application/xml"); client.Headers.Set("Authorization", "Bearer " + t.access_token); var byteArray = Encoding.UTF8.GetBytes(transformedMessage); response = client.UploadData(baseUrl + "api/"+ endPoint + "/", "POST", byteArray); responseString = Encoding.UTF8.GetString(response); }
public static class AzureUtility { public async static Task<AzureAccessToken> CreateOAuthAuthorizationToken1(string clientId, string clientSecret, string resourceId, string tenant) { AzureAccessToken token = null; string oauthUrl = string.Format("https://login.microsoftonline.com/{0}/oauth2/token", tenant); string reqBody = string.Format("grant_type=client_credentials&client_id={0}&client_secret={1}&resource={2}", Uri.EscapeDataString(clientId), Uri.EscapeDataString(clientSecret), Uri.EscapeDataString(resourceId)); HttpClient client = new HttpClient(); HttpContent content = new StringContent(reqBody); content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded"); using (HttpResponseMessage response = await client.PostAsync(oauthUrl, content).ConfigureAwait(false)) { if (response.IsSuccessStatusCode) { DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(AzureAccessToken)); Stream json = await response.Content.ReadAsStreamAsync(); token = (AzureAccessToken)serializer.ReadObject(json); } } return token; } }
public partial class Startup { // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864 public void ConfigureAuth(IAppBuilder app) { app.UseWindowsAzureActiveDirectoryBearerAuthentication( new WindowsAzureActiveDirectoryBearerAuthenticationOptions { Tenant = ConfigurationManager.AppSettings["Tenant"], TokenValidationParameters = new TokenValidationParameters { ValidAudience = ConfigurationManager.AppSettings["Audience"] }, }); } }
You would also have to configure your App service to use Windows Azure Active Directory as Authentication mechanism:
public partial class Startup { // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864 public void ConfigureAuth(IAppBuilder app) { app.UseWindowsAzureActiveDirectoryBearerAuthentication( new WindowsAzureActiveDirectoryBearerAuthenticationOptions { Tenant = ConfigurationManager.AppSettings["Tenant"], TokenValidationParameters = new TokenValidationParameters { ValidAudience = ConfigurationManager.AppSettings["Audience"] }, }); } }