Resolving Cryptography issues with the Dynamics CRM SDK in Azure Web Apps

Jared Johnson, 18 December 2015

When attempting to run applications that use the Dynamics CRM SDK in Azure Web Apps, you can get an exception when the app is trying to connect to CRM that looks like this:

“ERROR: System.Security.Cryptography.CryptographicException: The data protection operation was unsuccessful. This may have been caused by not having the user profile loaded for the current thread's user context, which may be the case when the thread is impersonating.”

This is due to the DataProtectionScope of the cryptography being used being set to CurrentUser, and by default Azure WebApps is configured to not load user profile.

However although we cannot access IIS in Azure WebApps to configure this setting like in a regular web server, we can still configure this. Simply create an Application Setting called WEBSITE_LOAD_USER_PROFILE and set it to 1.

image

However this will only work on the non-shared pricing tiers, (the Free and Shared tiers will not be affected by this setting.) This means that the minimum required tier is the B1 Basic tier.

image

The other option is to modify the DeviceIdManager class to no longer require the User Profile. To do this find and replace DataProtectionScope.CurrentUser => DataProtectionScope.LocalMachine, there should be 2 instances of it in the class. The Local Machine scope is less secure then Current User as it means any process running can potentially access the data even if it is running under a different user, but this is less of a concern in a server environment like this.

Secondly you have to change the code that saves the code that saves the LiveDevice xml file. As the code tries to save this file into the Users document folder this will not work if we have not loaded the user profile. We will instead change this to the base directory of our app. To do this we need to change:

public static readonly string LiveDeviceFileNameFormat = Path.Combine( Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "LiveDeviceID"), "LiveDevice{0}.xml");

To

public static readonly string LiveDeviceFileNameFormat = Path.Combine( System.AppDomain.CurrentDomain.BaseDirectory, "LiveDevice{0}.xml");

With this changes a connection to CRM will succeed even when running under the Free pricing tier, which is quite handy for creating small internal applications or for development.