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:
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.
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.
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.
Wow, that’s one comprehensive write up, not much to add. You’ve been warned, folks!