Intellipaat Back

Explore Courses Blog Tutorials Interview Questions
0 votes
2 views
in Web Technology by (45.3k points)
recategorized by

I am implementing reset password functionality on my site by using the in-built UserManager a class that comes with ASP.NET 5.

Everything works fine in my dev environment. However, once I try it in the production site that is running as an Azure website, I get the following exception:

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 how I set up the UserManager instance:

var provider = new Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider(SiteConfig.SiteName);

UserManager.UserTokenProvider = new Microsoft.AspNet.Identity.Owin.DataProtectorTokenProvider<User>(provider.Create(ResetPasswordPurpose));

Then, I generate the token thusly (to be sent to the user in an email so that they can verify that they do indeed want to reset their password):

string token = UserManager.GeneratePasswordResetToken(user.Id);

Unfortunately, when this runs on Azure, I get the exception above.

I've Googled around and found this possible solution

However, it didn't work at all and I still get the same exception.

According to the link, it has something to do with session tokens not working on a web farm like Azure.

1 Answer

0 votes
by (16.8k points)

The DpapiDataProtectionProvider utilizes DPAPI which will not work properly in a web farm/cloud environment since encrypted data can only be decrypted by the machine that encypted it. What you need is a way to encrypt data such that it can be decrypted by any machine in your environment. Unfortunately, ASP.NET Identity 2.0 does not include any other implementation of IProtectionProvider other than DpapiDataProtectionProvider. However, it's not too difficult to roll your own.

One option is to utilize the MachineKey class as follows:

public class MachineKeyProtectionProvider : IDataProtectionProvider

{

    public IDataProtector Create(params string[] purposes)

    {

        return new MachineKeyDataProtector(purposes);

    }

}

public class MachineKeyDataProtector : IDataProtector

{

    private readonly string[] _purposes;

    public MachineKeyDataProtector(string[] purposes)

    {

        _purposes = purposes;

    }

    public byte[] Protect(byte[] userData)

    {

        return MachineKey.Protect(userData, _purposes);

    }

    public byte[] Unprotect(byte[] protectedData)

    {

        return MachineKey.Unprotect(protectedData, _purposes);

    }

}

In order to use this option, there are a couple of steps that you would need to follow.

Step 1

Modify your code to use the MachineKeyProtectionProvider.

using Microsoft.AspNet.Identity.Owin;

// ...

var provider = new MachineKeyProtectionProvider();

UserManager.UserTokenProvider = new DataProtectorTokenProvider<User>(

    provider.Create("ResetPasswordPurpose"));

Step 2

Synchronize the MachineKey value across all the machines in your web farm/cloud environment. This sounds scary, but it's the same step that we've performed countless times before in order to get ViewState validation to work properly in a web farm (it also uses DPAPI).

31k questions

32.8k answers

501 comments

693 users

Browse Categories

...