Skip to content

Instantly share code, notes, and snippets.

@gotdibbs
Last active January 5, 2018 20:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gotdibbs/d13e3ffdb065504762e9e9e11c0325aa to your computer and use it in GitHub Desktop.
Save gotdibbs/d13e3ffdb065504762e9e9e11c0325aa to your computer and use it in GitHub Desktop.
Unable to Login to Dynamics using the SDK?

We recently noticed that we were unable to use any of our WPF or Powershell which leverage the Microsoft.Xrm.Tooling.Connector NuGet package to login to a couple Dynamics 365 Online instances. We received the error "Unable to Login", which if you've used the Xrm Tooling Connector lib before, you know to be ambiguous. Since nothing had changed recently, we tried it in LINQPad and it worked, mysteriously. 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 occuring 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 TLS1 then failing back to try SSL3. Neither of which are supported online now according to this bulletin from the D365 blog: Updates coming to Dynamics 365 Customer Engagement connection security.

That 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 (TLS 1.2 would be tried before TLS 1.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.

Back to the drawing board we went. 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 TLS 1.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 turning on the protocols we care about, instead of explicitly restricting ourselves to TLS 1.2. This ensures the least potential side effects in our minds. 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 TLS 1.1 and TLS 1.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 TLS 1.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 as needed. As described, we wanted to turn on TLS 1.1 and 1.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 fix (with, of course, a slightly different syntax) can be applied in PowerShell, as needed.

Final Thoughts

A couple of others noted during our research that this doesn't seem to be a problem with LINQPad scripts or Console Applications. 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment