Sonoma Partners Microsoft CRM and Salesforce Blog

Unable to Login to Dynamics using the SDK?

Today's blog post was written by William "Dibbs" Dibbern, Development Principal at Sonoma Partners.

We recently noticed that we were unable to login to a couple Dynamics 365 Online instances using any of our WPF or Powershell-based tooling that leverages the Microsoft.Xrm.Tooling.Connector NuGet package . We received the error "Unable to Login", which if you've used the Xrm Tooling Connector lib before, you could mean anything. Since nothing had changed recently, we tried it in LINQPad and it worked, mysteriously. You know what that means: let the debugging games begin!

If you'd like to follow our process for solving this then keep reading, otherwise if you just want to know the resolution, skip on down to the end.

Troubleshooting

After inspecting the network traffic during connection using Fiddler, we noticed the failure was occurring during the CONNECT request to the API, and it was failing multiple times. Upon inspecting each request we found that our code was sending out a CONNECT for TLSv1 then failing back to try SSLv3 as you can see in the screenshot below.

Fiddler

Neither TLSv1 nor SSLv3 are supported online now according to this bulletin from the D365 blog: Updates coming to Dynamics 365 Customer Engagement connection securityThat blog post notes two options to resolve any potential issues stemming from the upgraded security, both of which have their pitfalls:

  1. Update your code to leverage .NET 4.6.2+: The update in .NET 4.6 that this alludes to is to try more secure protocols before trying older, less secure, protocols (TLSv1.2 would be tried before TLSv1.1). However, our code was already on .NET 4.6.2 so this suggestion was ultimately unhelpful for us.
  2. Update your registry settings: Potentially a good resolution for some, but we prefer to make as few changes to systems we deploy our apps to as possible, and we were sure there had to be another way around this that we could control from code.

Based on those hurdles, we went back to the drawing board. After a few quick searches, we stumbled upon a couple of very helpful StackOverflow posts.

This question .Net Framework 4.6.1 not defaulting to TLS 1.2 pretty much cut straight to the heart of our predicament. We're on .NET 4.6+, why is it still not working? The most upvoted answer gives the reason. .NET 4.6.2 doesn't have a default set of enabled security protocols it seems, so the default could be different per environment our code could run on.

This led us to making sure that the ServicePointManager.SecurityProtocol setting was set such that TLSv1.2 was in the list of available protocol options, regardless of any default environment settings. We found several posts suggesting we set the value explicitly such that ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;. However, the other StackOverflow post we found had a better answer.

Resolution

In the end, we agreed with the most upvoted answer in the last StackOverflow post we found which recommended only enabling the protocols we actually care about instead of explicitly restricting ourselves to TLSv1.2. This ensures the least potential side effects. System defaults are minimally modified for our execution context, and any future protocols that are added would still be available to use (in theory). As our two troublesome environments in which we originally experience the error had only TLSv1.1 and TLSv1.2 left off of the defaults, we decided to turn them both on. This combined with the update to .NET 4.6.2 ensures that TLSv1.2 is tried before any less secure protocols, but that all are available if needed.

How this is implemented is by adjusting the ServicePointManager.SecurityProtocol setting as needed. As described, we wanted to turn on TLSv1.1 and v1.2, so we added the below line once per application. We inserted it generally right before we initialize our CrmServiceClient object, unless of course we're instantiating multiple. The point is, you only need to do this once if no other code in your execution context is changing this value.

ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

The same principal can be applied in PowerShell, as needed.

Final Thoughts

A couple of fellow devs noted during our research that this doesn't seem to be a problem with Console Applications, and we also noted at the start this wasn't an issue for LINQPad scripts. What's up with that, right? For whatever reason, in those environments, TLS 1.2 is in fact included in the list of available security protocols by default. That said, the point here is that it isn't always enabled by default. So if you cannot be sure where your code is being run, the safest bet is to turn on the protocols you know you need before trying to use them.

Topics: Microsoft Dynamics 365