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;
}
}
}
}
I found a working solution for my own problem based on the answer of trailmax.
In stead of the EmailTokenProvider I use the TotpSecurityStampBasedTokenProvider
For more information about TotpSecurityStampBasedTokenProvider: http://msdn.microsoft.com/en-us/library/dn613297(v=vs.108).aspx
Use
EmailTokenProvider
in UserManagerI've blogged about it recently.