4

I have my web application deployed on Microsoft Azure. However when I want to generate a PasswordResetToken with:

var token = await _userManager.GeneratePasswordResetTokenAsync(user.Id);

I get the following 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.

How do I get this to work on Azure?

Or is there an other way to reset a password without knowing the old password?

This is my UserManager class. Mabey there is an error in it.

public class ApplicationUserManager : UserManager<ApplicationIdentityUser>
{
    private static IUnitOfWork _unitOfWork;
    private readonly IRepository<ApplicationIdentityUser> _userRepository;


    public ApplicationUserManager(IUserStore<ApplicationIdentityUser> store, IRepository<ApplicationIdentityUser> userRepository)
        : base(store)
    {
        if (userRepository == null) throw new ArgumentNullException("userRepository");

        _userRepository = userRepository;

        if (bool.Parse(ConfigurationManager.AppSettings["RunningInAzure"]))
            UserTokenProvider = new EmailTokenProvider<ApplicationIdentityUser, string>();
        else
        {
            var provider = new Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider("TopRijden");
            UserTokenProvider = new DataProtectorTokenProvider<ApplicationIdentityUser, string>(provider.Create("Password Reset"));
        }
    }


    public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
    {
        if (options == null) throw new ArgumentNullException("options");
        if (context == null) throw new ArgumentNullException("context");

        try
        {
            _unitOfWork = ObjectFactory.GetInstance<IUnitOfWork>();
            var userRepository = ObjectFactory.GetInstance<IRepository<ApplicationIdentityUser>>();

            var manager = new ApplicationUserManager(new UserStore<ApplicationIdentityUser>(_unitOfWork.Session), userRepository);

            // Configure validation logic for usernames
            manager.UserValidator = new UserValidator<ApplicationIdentityUser>(manager)
            {
                AllowOnlyAlphanumericUserNames = false,
                RequireUniqueEmail = true
            };

            // Configure validation logic for passwords
            manager.PasswordValidator = new PasswordValidator
            {
                RequiredLength = 6,
                RequireNonLetterOrDigit = true,
                RequireDigit = true,
                RequireLowercase = true,
                RequireUppercase = true,
            };

            // Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user
            // You can write your own provider and plug in here.
            manager.RegisterTwoFactorProvider("PhoneCode", new PhoneNumberTokenProvider<ApplicationIdentityUser>
            {
                MessageFormat = "Your security code is: {0}"
            });

            manager.RegisterTwoFactorProvider("EmailCode", new EmailTokenProvider<ApplicationIdentityUser>
            {
                Subject = "Security Code",
                BodyFormat = "Your security code is: {0}"
            });

            var dataProtectionProvider = options.DataProtectionProvider;
            if (dataProtectionProvider != null)
            {
                manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationIdentityUser>(dataProtectionProvider.Create("ASP.NET Identity"));
            }

            return manager;
        }
        catch (Exception ex)
        {
            ex.Process(MethodBase.GetCurrentMethod().DeclaringType, MethodBase.GetCurrentMethod().Name);

            return null;
        }
    }      
}

}

  • Are you talking about something like this? http://www.asp.net/identity/overview/features-api/account-confirmation-and-password-recovery-with-aspnet-identity – jbutler483 Sep 09 '14 at 08:44

2 Answers2

5

I found a working solution for my own problem based on the answer of trailmax.

In stead of the EmailTokenProvider I use the TotpSecurityStampBasedTokenProvider

public UserManager() : base(new UserStore<ApplicationUser>(new MyDbContext()))
{
    // other setup
    this.UserTokenProvider = new TotpSecurityStampBasedTokenProvider<ApplicationUser, string>();
}

For more information about TotpSecurityStampBasedTokenProvider: http://msdn.microsoft.com/en-us/library/dn613297(v=vs.108).aspx

1

Use EmailTokenProvider in UserManager

public UserManager() : base(new UserStore<ApplicationUser>(new MyDbContext()))
{
    // other setup
    this.UserTokenProvider = new EmailTokenProvider<ApplicationUser, string>();
}

I've blogged about it recently.

trailmax
  • 34,305
  • 22
  • 140
  • 234
  • unfortunately it's not working. I edited my question with my UserManager class. Mabey there is an error in in. – DeVliegendeBeer Sep 10 '14 at 06:59
  • I also get the following error when i use the EmailTokenProvider: System.NotSupportedException: No IUserTokenProvider is registered. – DeVliegendeBeer Sep 10 '14 at 07:05
  • I think you have too many options where you token provider can be registered. Simplify your user manager creation, make sure you have only one 2FA provider registered, only one place to set `UserTokenProvider`. At the moment, even if you set email token provider in constructor, it can be overwritten in static `Create` method. – trailmax Sep 10 '14 at 09:17
  • I simplified the user manager so that only one time the UserTokenProvider is assigned, but I still get the exception :(. The EmailTokenProvider doesn't work on my local IIS enviroment. – DeVliegendeBeer Sep 10 '14 at 13:15