3

Overview

I am on Dynamics 2016 on premise.

I have a Business Process Flow in Microsoft Dynamics to handle creation of a new client. When the process finishes, I am attaching a workflow that kicks off an action which calls a plugin to do some custom processing. I am following this article to set up this process. When this plugin is triggered in Dynamics, it appears to run successfully, but does not create the records I am expecting it to create. However, when I profile the plugin and run it through the Plugin Registration Tool/Visual Studio the records are created that I expect to see.

When I added trace logs to my plugin, I noticed that it appears I am receiving a 401 - Unauthorized error from Dynamics when I call the Web API. When I looked at the network traffic while debugging it looks like I receive an initial 401 error, but then a retry successfully gets the records I am trying to get.

Code

This is the section of code I think the 401-Unauthorized error is coming from

private void GetGlobalFieldNameMapsAsync(String url = "ccseq_globalfieldnamemaps?$select=ccseq_system,ccseq_entitytype,ccseq_fieldtype,ccseq_name,ccseq_datatype")
{
    HttpClient client = new HttpClient(new HttpClientHandler() { Credentials = new NetworkCredential("admin", "password", "domain") });
    HttpResponseMessage responseMessage = new HttpResponseMessage();
    try
    {
        client.BaseAddress = new Uri(Helpers.GetSystemUrl(APIConnector.Application.Dynamics));
        client.DefaultRequestHeaders.Clear();
        client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
        client.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
        client.DefaultRequestHeaders.Add("OData-Version", "4.0");    

        responseMessage = client.GetAsync(url).Result;    

        JObject responseData = JObject.Parse(responseMessage.Content.ReadAsStringAsync().Result);

        if (responseData["@odata.nextLink"] != null)
        {
                    GetGlobalFieldNameMapsAsync(Convert.ToString(responseData["@odata.nextLink"]));
        }

        foreach (var v in responseData["value"])
        {
            GlobalFieldNameMap newGFNM = new GlobalFieldNameMap();
            newGFNM.System.Value = Convert.ToInt32(v["ccseq_system"]);
            newGFNM.EntityType.Value = Convert.ToInt32(v["ccseq_entitytype"]);
            newGFNM.FieldType.Value = Convert.ToInt32(v["ccseq_fieldtype"]);
            newGFNM.FieldName.Value = Convert.ToString(v["ccseq_name"]);
            newGFNM.DataType.Value = Convert.ToInt32(v["ccseq_datatype"]);
            FieldNameMap.Add(newGFNM);
        }

    }
    catch (Exception e)
    {
        throw new Exception(e.Message + " - " + responseMessage.Content.ReadAsStringAsync().Result);
    }
}

Network Traffic

Network Traffic

I can't seem to puzzle out how I am seeing the plugin successfully run during debugging, but seeing it fail when running directly in dynamics. The plugin appears to be running under the same user regardless of whether it's running in Dynamics or on my local machine. I'm passing in admin credentials so they should have full permissions to do anything in the system. Any thoughts?

I have asked this question and this question which may be related, but don't quite cover this issue.


Update

I noticed this error message in the trace logs

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<title>IIS 8.5 Detailed Error - 401.1 - Unauthorized</title> 
<style type="text/css"> 
<!-- 
body{margin:0;font-size:.7em;font-family:Verdana,Arial,Helvetica,sans-serif;} 
code{margin:0;color:#006600;font-size:1.1em;font-weight:bold;} 
.config_source code{font-size:.8em;color:#000000;} 
pre{margin:0;font-size:1.4em;word-wrap:break-word;} 
ul,ol{margin:10px 0 10px 5px;} 
ul.first,ol.first{margin-top:5px;} 
fieldset{padding:0 15px 10px 15px;word-break:break-all;} 
.summary-container fieldset{padding-bottom:5px;margin-top:4px;} 
legend.no-expand-all{padding:2px 15px 4px 10px;margin:0 0 0 -12px;} 
legend{color:#333333;;margin:4px 0 8px -12px;_margin-top:0px; 
font-weight:bold;font-size:1em;} 
a:link,a:visited{color:#007EFF;font-weight:bold;} 
a:hover{text-decoration:none;} 
h1{font-size:2.4em;margin:0;color:#FFF;} 
h2{font-size:1.7em;margin:0;color:#CC0000;} 
h3{font-size:1.4em;margin:10px 0 0 0;color:#CC0000;} 
h4{font-size:1.2em;margin:10px 0 5px 0; 
}#header{width:96%;margin:0 0 0 0;padding:6px 2% 6px 2%;font-family:"trebuchet MS",Verdana,sans-serif; 
color:#FFF;background-color:#5C87B2; 
}#content{margin:0 0 0 2%;position:relative;} 
.summary-container,.content-container{background:#FFF;width:96%;margin-top:8px;padding:10px;position:relative;} 
.content-container p{margin:0 0 10px 0; 
}#details-left{width:35%;float:left;margin-right:2%; 
}#details-right{width:63%;float:left;overflow:hidden; 
}#server_version{width:96%;_height:1px;min-height:1px;margin:0 0 5px 0;padding:11px 2% 8px 2%;color:#FFFFFF; 
background-color:#5A7FA5;border-bottom:1px solid #C1CFDD;border-top:1px solid #4A6C8E;font-weight:normal; 
font-size:1em;color:#FFF;text-align:right; 
}#server_version p{margin:5px 0;} 
table{margin:4px 0 4px 0;width:100%;border:none;} 
td,th{vertical-align:top;padding:3px 0;text-align:left;font-weight:normal;border:none;} 
th{width:30%;text-align:right;padding-right:2%;font-weight:bold;} 
thead th{background-color:#ebebeb;width:25%; 
}#details-right th{width:20%;} 
table tr.alt td,table tr.alt th{} 
.highlight-code{color:#CC0000;font-weight:bold;font-style:italic;} 
.clear{clear:both;} 
.preferred{padding:0 5px 2px 5px;font-weight:normal;background:#006633;color:#FFF;font-size:.8em;} 
--> 
</style> 

</head> 
<body> 
<div id="content"> 
<div class="content-container"> 
<h3>HTTP Error 401.1 - Unauthorized</h3> 
<h4>You do not have permission to view this directory or page using the credentials that you supplied.</h4> 
</div> 
<div class="content-container"> 
<fieldset><h4>Most likely causes:</h4> 
<ul> <li>The username supplied to IIS is invalid.</li> <li>The password supplied to IIS was not typed correctly. </li> <li>Incorrect credentials were cached by the browser.</li> <li>IIS could not verify the identity of the username and password provided.</li> <li>The resource is configured for Anonymous authentication, but the configured anonymous account either has an invalid password or was disabled.</li> <li>The server is configured to deny login privileges to the authenticating user or the group in which the user is a member.</li> <li>Invalid Kerberos configuration may be the cause if all of the following are true:</li> <ul> <li>Integrated authentication was used.</li> <li>the application pool identity is a custom account.</li> <li>the server is a member of a domain.</li> </ul> </ul> 
</fieldset> 
</div> 
<div class="content-container"> 
<fieldset><h4>Things you can try:</h4> 
<ul> <li>Verify that the username and password are correct, and are not cached by the browser.</li> <li>Use a different username and password.</li> <li>If you are using a custom anonymous account, verify that the password has not expired.</li> <li>Verify that the authenticating user or the user's group, has not been denied login access to the server.</li> <li>Verify that the account was not locked out due to numerous failed login attempts.</li> <li>If you are using authentication and the server is a member of a domain, verify that you have configured the application pool identity using the utility SETSPN.exe, or changed the configuration so that NTLM is the favored authentication type.</li> <li>Create a tracing rule to track failed requests for this HTTP status code. For more information about creating a tracing rule for failed requests, click <a href="http://go.microsoft.com/fwlink/?LinkID=66439">here</a>. </li> </ul> 
</fieldset> 
</div> 

<div class="content-container"> 
<fieldset><h4>Detailed Error Information:</h4> 
<div id="details-left"> 
<table border="0" cellpadding="0" cellspacing="0"> 
<tr class="alt"><th>Module</th><td>&nbsp;&nbsp;&nbsp;WindowsAuthenticationModule</td></tr> 
<tr><th>Notification</th><td>&nbsp;&nbsp;&nbsp;AuthenticateRequest</td></tr> 
<tr class="alt"><th>Handler</th><td>&nbsp;&nbsp;&nbsp;ExtensionlessUrlHandler-Integrated-4.0</td></tr> 
<tr><th>Error Code</th><td>&nbsp;&nbsp;&nbsp;0xc000006d</td></tr> 

</table> 
</div> 
<div id="details-right"> 
<table border="0" cellpadding="0" cellspacing="0"> 
<tr class="alt"><th>Requested URL</th><td>&nbsp;&nbsp;&nbsp;https://crminternal.cohencpa.com:443/COHEN/api/data/v8.2/ccseq_globalfieldnamemaps?$select=ccseq_system,ccseq_entitytype,ccseq_fieldtype,ccseq_name,ccseq_datatype</td></tr> 
<tr><th>Physical Path</th><td>&nbsp;&nbsp;&nbsp;C:\Program Files\Microsoft Dynamics CRM\CRMWeb\COHEN\api\data\v8.2\ccseq_globalfieldnamemaps</td></tr> 
<tr class="alt"><th>Logon Method</th><td>&nbsp;&nbsp;&nbsp;Not yet determined</td></tr> 
<tr><th>Logon User</th><td>&nbsp;&nbsp;&nbsp;Not yet determined</td></tr> 

</table> 
<div class="clear"></div> 
</div> 
</fieldset> 
</div> 

<div class="content-container"> 
<fieldset><h4>More Information:</h4> 
This error occurs when either the username or password supplied to IIS is invalid, or when IIS cannot use the username and password to authenticate the user. 
<p><a href="http://go.microsoft.com/fwlink/?LinkID=62293&amp;IIS70Error=401,1,0xc000006d,9600">View more information &raquo;</a></p> 
<p>Microsoft Knowledge Base Articles:</p> 
<ul><li>907273</li><li>871179</li><li>896861</li></ul> 

</fieldset> 
</div> 
</div> 
</body> 
</html> 
Tim Hutchison
  • 2,865
  • 5
  • 33
  • 67

2 Answers2

0

I think the answer here is to not use the Web API within a plugin.

Use Dynamics 365 web services

Web API

Use the Web API for any projects that access Dynamics 365 data with code that doesn’t run on the server, including requests from web resources and form scripts that run in Dynamics 365 application clients. At this time you can’t easily use the Web API for code that runs on the server, such as in plug-ins or workflow assemblies.

Organization service

Business logic that runs in plug-ins or workflow assemblies on the server expect to use the Organization service.

As for why you are getting 401 - Unauthorized in your plugin trace logs. I suspect its probably because the you are trying to make CRM call itself, and it simply can't authenticate. In any case plugin Web Access is quite limited in this respect.

The following web access restrictions apply to this sandbox capability.

  • Anonymous authentication is supported and recommended.

In terms of why the plugin works when debugging, I would guess its because the HTTP request is now being sent from your local machine and not the server. I'm assuming the Fiddler log is from your machine.

Finally, the initial 401 followed by success when debugging; I believe the 401 is a credential challenge which is common in many authentication schemes.

Community
  • 1
  • 1
James Wood
  • 16,370
  • 2
  • 39
  • 80
  • Thanks for the feedback! The reason we are using the Web API from a plugin is that the code that uses the Web API is a part of a dll library that is called from the plugin. Within the plugin itself, we are using Web Services for all calls that we make – Tim Hutchison Aug 09 '18 at 15:12
  • Well I would suggest you change your API or create a version to have compatibilty with plugins. – James Wood Aug 09 '18 at 16:11
0

Upon investigating the 401.1 Unauthorized error, I came across this article. Here's the relevant piece:

When you use the fully qualified domain name (FQDN) or a custom host header to browse a local Web site that is hosted on a computer that is running Microsoft Internet Information Services (IIS) 5.1 or a later version, you may receive an error message that resembles the following:

HTTP 401.1 - Unauthorized: Logon Failed

This issue occurs when the Web site uses Integrated Authentication and has a name that is mapped to the local loopback address.

Note You only receive this error message if you try to browse the Web site directly on the server. If you browse the Web site from a client computer, the Web site works as expected.

The article provides several methods for resolving the issue, but here is the one that worked for us (must be done on the server):

  1. Use regedit to navigate to HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\LanmanServer\Parameters and add a value called DisableStrictNameChecking (REG-DWORD, Decimal) with a value of 1
  2. Use regedit to navigate to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0 and add a Multi-String value called BackConnectionHostNames with a value of your hostname of the web api endpoint
  3. Open the command line and type iisreset (must be run as administrator)
  4. Restart the server
Community
  • 1
  • 1
Tim Hutchison
  • 2,865
  • 5
  • 33
  • 67