Tip #1058: Connect to version 9 in your code

This tip is courtesy of Matt “SDK Deity” Barbour to make sure that we (developers) can stay connected to our beloved instances regardless of the version. Before copying the write-up almost verbatim, short version:

tl;dr

TLS 1.2 is now enforced so, for seamless connections to your version 9 instances, use the latest SDK tools and rebuild your projects with .NET 4.6.2+.

Matt has the mic

(Matt works at Microsoft so from this point forward “I” == Matt and “we” == Dynamics 365 team)

This is a bit long and detailed, however I believe it will be worth the read if your building for, or supporting folks that are building for, the crm\xrm platform.

With the release of the v9 platform we are now enforcing the use of the TLS ( Transport Layer Security) 1.2 + Only.

We made notice of this here and here.

Its important to note that TLS 1.2 is not a ‘new’ thing. We have been supporting TLS 1.0, 1.1 and 1.2 since v7 of the platform, the change we are making in v9 is that we will drop support for TLS 1.0 and 1.1, requiring all connections to connect to us using TLS 1.2 + only. Why we are enforcing this is covered in the blog with external links and such, so I encourage you to dig though that. The short of it is: its to improve security.

Now the rub 🙂

Our tools and platforms though v8 have been based on .net 4.5.2, which defaults to TLS 1.0 for security. What this means is that CRM and Dynamics Tools shipped up though v8 will not seamlessly connect to v9. When this shows up it always manifests as an auth failure. Looking at the logs, you will see a message that looks like this:

In 8.1 connectors :

Microsoft.Xrm.Tooling.CrmConnectControl Information: 8 : Login Status in Connect is = Validating connection to Microsoft Dynamics CRM...
Microsoft.Xrm.Tooling.Connector.CrmServiceClient Error: 2 : ERROR REQUESTING Token FROM THE Authentication context
Microsoft.Xrm.Tooling.Connector.CrmServiceClient Error: 2 : Source : mscorlib
Method : ThrowIfExceptional
Date : 1/19/2018
Time : 10:23:27 AM
Error : One or more errors occurred.
Stack Trace : at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
at System.Threading.Tasks.Task`1.get_Result()
at Microsoft.Xrm.Tooling.Connector.CrmWebSvc.ExecuteAuthenticateServiceProcess(Uri serviceUrl, ClientCredentials clientCredentials, UserIdentifier user, String clientId, Uri redirectUri, PromptBehavior promptBehavior, String tokenCachePath, Boolean isOnPrem, String authority, Uri& targetServiceUrl, AuthenticationContext& authContext, String& resource)
======================================================================================================================
Inner Exception Level 1 :
Source : Microsoft.IdentityModel.Clients.ActiveDirectory
Method : Close
Date : 1/19/2018
Time : 10:23:27 AM
Error : Object reference not set to an instance of an object.
Stack Trace : at Microsoft.IdentityModel.Clients.ActiveDirectory.HttpWebResponseWrapper.Close()
at Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationParameters.d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationParameters.d__8.MoveNext()
======================================================================================================================

In the bits on nuget now the error looks like this:

Inner Exception Level 1 :
Source : System
Method : GetResponse
Date : 1/16/2018
Time : 4:37:46 PM
Error : The underlying connection was closed: An unexpected error occurred on a send.
Stack Trace : at System.Net.HttpWebRequest.GetResponse()
at System.ServiceModel.Description.MetadataExchangeClient.MetadataLocationRetriever.DownloadMetadata(TimeoutHelper timeoutHelper)
at System.ServiceModel.Description.MetadataExchangeClient.MetadataRetriever.Retrieve(TimeoutHelper timeoutHelper)
======================================================================================================================
Inner Exception Level 2 :
Source : System
Method : Read
Date : 1/16/2018
Time : 4:37:46 PM
Error : Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
Stack Trace : at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.FixedSizeReader.ReadPacket(Byte[] buffer, Int32 offset, Int32 count)
at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
======================================================================================================================
Inner Exception Level 3 :

Errors like this, in conjunction with trying to connect to a new trial or a v9 instance is a dead giveaway that it’s a TLS Problem.

How to deal with this

There are a few ways to deal with this,

For tools we ( Microsoft ) provide

the most simple and easy way to deal with it is to use the current SDK tools.. Now, in our effort to help keep folks up to date, we have made getting the SDK tools a bit more complicated but we did it for good reasons. Historically, we would post a point in time copy of all the tools and samples into a massive download, the problem is that to get all that together, it required a number of teams to work together to put a package together to post, this slowed down pushing updates. Most folks have noticed that we do not have the 9.x SDK posted that way. If you have not noticed yet … We are not using a Single download anymore 🙂

We have moved over to Nuget to provide the current SDK bits. This allows us to quickly patch and update SDK assemblies and tools.
We talked about this here. To help with the SDK Download and to keep you current, Jim Daly wrote up a handy powershell script in the documentation to help you get and keep current the SDK, its one link off the central dev page bug for reference its here. Using that script will always keep you current going forward with tools.

For Code built with our SDK

The most simple and easy way to deal with this is to recompile your code with .net 4.6.2+. if your code is already compiled with .net 4.6.2+ then your good to go. EXCEPT if you started with VS and a project that started with .4.5.2 :). There is a quirk in VS which causes it to run in 4.5.2 mode even after you have changed the build version. The simple way to deal with this is to clean your project after you change the .net version , close VS and delete the bin directory ( You need to get rid of the .vhost. files ) then restart VS and reload your project. That should kick it into using the .net 4.6.+ runtime. *note: this does not impact the binaries, only on the debug experience in VS.

For existing code that cannot be recompiled

We cover a registry setting in the blog articles that can be applied that will force .net to use TLS 1.2, I want to stress caution with this though as this is very much the sledgehammer approach as it forces all .net software on the machine to use TLS 1.2 +.

For non .net software

Check with your vendor on how to enabled TLS, for most languages it can be done with a simple config entry

One important note for .net based apps

Its really attractive to use the command: ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; I cannot discourage you from using this enough… this forces the TLS 1.2 protocol all the time. While this seems great, if you ship software that lives more than a year or so, when the next security protocol appears and is adopted by the industry, your application with be at risk.

For Powershell

With regard to PowerShell scripts however, You will need to add [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 to your Powershell Script BEFORE you call Get-CrmConnection.

Tîpp Jäår

Wow, that’s one comprehensive write up, not much to add. You’ve been warned, folks!

(Our cover image – the one you see on facebook or twitter – is by Igor Ovsyannykov on Unsplash)

5 thoughts on “Tip #1058: Connect to version 9 in your code

  1. William Dibbern says:

    A few important discrepancies to note:

    1. Updating to .NET 4.6+ is NOT enough to fix the problem everywhere. .NET does NOT control which Security Protocols are enabled on your machine. Update the .NET version only ensures that more secure protocols are tried before the less secure ones. Example: I can create a fresh .NET 4.6.2 Console Application and still have the issue with TLS 1.2. This is because TLS 1.2 isn’t listed in the defaults on my computer. See the explanation on the docs: “Note that no default value is listed for this property, on purpose.” https://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.securityprotocol(v=vs.110).aspx

    2. You note correctly for .NET that you should enable TLS 1.2 by adding it to the list of available protocols, but for Powershell you explicitly restrict it to TLS 1.2. Admittedly, I haven’t played with Powershell to much regarding this issue, but I believe the same fix applies. Assuming so, the line should actually be: [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor [System.Net.SecurityProtocolType]::Tls12

    We’ve blogged about this as well on the Sonoma Partners blog if you need more info to back up the above.

  2. […] Microsoft hasn’t released version of Report Authoring Extension that supports both v9.0 and enforced TLS 1.2. This post will help people who develops reports for latest Dynamics 365 v9.0 using SQL Server Data […]

  3. […] NOTE 1: There is a possibility that you may not be able to connect with Dynamics 365 and “Could not connect to DataSource” or “can’t use cached credentials to sign in to microsoft dynamics 365” errors will come. In this case please follow this link and do the needful. This is because Microsoft hasn’t released version of Report Authoring Extensionthat supports both v9.0 and enforced TLS 1.2. […]

  4. Mike McGuinness says:

    I couldn’t find any way to compile code for .NET 4.6.2. 4.6.1 and 4.7.1 were my options (even with framework 4.6.2 installed), but I still got the same error trying to connect to CRM either way.

    The trick for me was explicitly setting ServicePointManager.SecurityProtocol to TLS 1.2 before calling the CRM service. I.e.

    using System.Net;

    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

Leave a Reply

Your email address will not be published. Required fields are marked *