I created MVC 4 application. In that application If user forgot the password I have method to send an email to user to reset password. I'm using asp.net Identity membership
I'm getting following error message when I deploy this project in web server. Its working perfectly in my localhost mode.
Error Message
Cannot edit this User 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 the forgot password method
[AllowAnonymous]
public ActionResult ForgotPassword()
{
return View();
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
if (model.UserName == null)
{
ModelState.AddModelError("", "Please enter the Username");
}
if (model.Email == null)
{
ModelState.AddModelError("", "Please enter the Email ID");
}
if (model.Email == null & model.UserName == null)
{
ModelState.AddModelError("", "Please enter the Username and Email ID");
}
if(ModelState.IsValid)
{
var username = await UserManager.FindByNameAsync(model.UserName);
var user = await UserManager.FindByEmailAsync(model.Email);
if (user != null && username != null)
{
ApplicationDbContext context = new ApplicationDbContext();
UserStore<ApplicationUser> store = new UserStore<ApplicationUser>(context);
var provider = new Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider("MyProject");
UserManager.UserTokenProvider = new Microsoft.AspNet.Identity.Owin.DataProtectorTokenProvider<ApplicationUser>(provider.Create("EmailConfirmation"));
var code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
System.Net.Mail.MailMessage m = new System.Net.Mail.MailMessage(
new System.Net.Mail.MailAddress("sample#email.lk", "My Application"),
new System.Net.Mail.MailAddress(user.Email));
m.Subject = "Reset your Password";
m.IsBodyHtml = true;
m.Body = string.Format("<img src=\"##IMAGE##\" alt=\"\"><BR/><BR/>Hi {0},<BR/><BR/>Please click the below link to reset your password. <BR/><BR/> Reset Password", user.UserName, Url.Action("ResetPassword", "Account", new { UserId = user.Id, code = code }, Request.Url.Scheme)) + string.Format("<BR/><BR/>Regards,<BR/>We Are <BR/>");
string attachmentPath = Server.MapPath("~/Images/hec-logo.png");
string contentID = Path.GetFileName(attachmentPath).Replace(".", "") + "#zofm";
Attachment inline = new Attachment(attachmentPath);
inline.ContentDisposition.Inline = true;
inline.ContentDisposition.DispositionType = DispositionTypeNames.Inline;
inline.ContentId = contentID;
inline.ContentType.MediaType = "image/png";
inline.ContentType.Name = Path.GetFileName(attachmentPath);
m.Attachments.Add(inline);
// replace the tag with the correct content ID
m.Body = m.Body.Replace("##IMAGE##", "cid:" + contentID);
System.Net.Mail.SmtpClient smtp = new System.Net.Mail.SmtpClient("11.11.11.111");
smtp.Port = 11;
smtp.Credentials = new System.Net.NetworkCredential("sample#email.lk", "8888888");
smtp.EnableSsl = false;
smtp.Send(m);
// Don't reveal that the user does not exist or is not confirmed
}
return View("ForgotPasswordConfirmation");
}
else
{
ModelState.AddModelError("", "The Username or Email ID is invalid.");
}
// If we got this far, something failed, redisplay form
return View(model);
}
I had same issue , then after many research I found out that problem is in IIS deployment
so following this thread I able to fix my issue
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.
Open your IIS Manager
Find out what AppPool your application is using by selecting your App, right-click on it, and Select Manage Application -> Advanced
Settings.
After that, on the top left hand side, select Applications Pools, and go ahead and select the App Pool used by your app.
Right-click on it, and select Advanced Settings, Go to the Process Model Section and Find the “Load User Profile” Option and set it to
true.
Related
First of all, I know there are better ways to make password recovery, I know identity framework has an easier way of doing it. So I'm not interested in all that advice, I just want to get to the bottom of the problem.
Basically this code works when doing a password recovery on the web app, when I test it locally. After I publish it, it doesn't work 9/10 times, but for some reason it still works 1/10 times.
I've traced the problem to my session variables being null even though they are set, this seems to only happen when the code is live on the server, but it works fine locally.
Why are my session variables null most of the time on my webserver? But then once in a while, it works? I can't get to the bottom of it.
Here is my code:
// Reset password view
[HttpGet]
public ActionResult ResetPassword()
{
return View();
}
// Reset password ajax method, sends out an e-mail to confirm password reset.
[HttpPost]
[ValidateAntiForgeryToken]
public string ResetPassword(string email)
{
if (Request.Cookies["tecrom"] == null)
{
var user = db.Users.FirstOrDefault(x => x.Customer.ContactMail == email);
if (user != null)
{
var token = Guid.NewGuid().ToString();
Session["resetuserid"] = user.Id;
Session["resettitle"] = user.Customer.Title;
Session["resetemail"] = email;
Session["resettoken"] = token;
var body = $"Kære {user.Customer.Title}<br><br>Vi har modtaget en anmodning om at genoprette dit password.<br><br>Bekræft venligst dit password reset ved at klikke <a href='https://pdfparser.dk/Home/FinishReset?hash=" + token + "'>her</a>, eller ignorer denne mail hvis du ikke ønsker at fortsætte.<br><br>Mvh x.dk";
EmailHelper.SendMail(email, "Genopret dit password", body);
var myCookie = new HttpCookie("tecrom");
var now = DateTime.Now;
// Set the cookie value.
myCookie.Value = now.ToString();
// Set the cookie expiration date.
myCookie.Expires = now.AddMinutes(15);
// Add the cookie.
Response.Cookies.Add(myCookie);
return "ok";
}
else
{
return "error";
}
}
else
{
return "error2";
}
}
// The final step in the password reset proces
public ActionResult FinishReset(string hash)
{
var token = (string)Session["resettoken"];
if (token == hash)
{
var password = "Tempas" + new Random().Next(100000, 999999);
var userid = (string)Session["resetuserid"];
var mail = (string)Session["resetemail"];
var title = (string)Session["resettitle"];
var um = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
ApplicationUser user = db.Users.Find(userid);
user.PasswordHash = um.PasswordHasher.HashPassword(password);
db.Entry(user).State = EntityState.Modified;
db.SaveChanges();
var body = "Kære "+title+"<br><br>Dit midlertidige password er: "+password+ "<br><br>Log venligst ind på pdfparser.dk og skift dit password hurtigst muligt. Dette kan gøres i menuen oppe i højre hjørne af websitet efter du er logget ind.<br><br>Mvh x.dk";
EmailHelper.SendMail(mail, "Dit midlertidige password", body);
ViewBag.Message = "Et midlertidigt password er sendt til dig, tjek din mail for at fortsætte";
}
else
{
ViewBag.Message = "Noget er desværre gået galt, dit password forbliver uændret";
}
return View();
}
Basically the reset password function checks the db for the user with that e-mail, then sends out a mail with a confirmation token saved in a session variable. When the user clicks the link in the sent out e-mail, it activates the finishreset function, which then creates a temporary password and sends it out to the user via e-mail.
Again I know this isn't the optimal way of doing it, but I'm kinda obsessed with finding out why my session variables are behaving weirdly on my server. Does anyone have a clue as to why it seems so random whether it works or not?
I will almost certainly need session variables in other places in my web app in the future, so I need to make sure they work and behave normally in general. Simply.com is where I have my server if that has any relevance.
As per your code, it should work only when user open that reset password email link from same browser from where they click to Reset password request. Because session maintain within that browser only.
I'm hey one of the most weirdest problems i have seen until now. I have the same peace of code the SMTP client. I have it in a separate class that handles sending emails so this is the constructor`
// Setting the smtp info
smtpClient = new SmtpClient("xxxxxxx", 587);
// Setting the no reply email address
smtpClient.Credentials = new NetworkCredential("xxxxxxxxx", "xxxxx");
FromMailAddress = new MailAddress("xxxxxxxxx", "xxxxxxxx");
// Setting Ssl
smtpClient.EnableSsl = true;`
And this is for sending the Email:
// Setting a new email address for the recver
MailAddress reciver = new MailAddress("xxxxxxxx");
// Creating a new Email message
MailMessage email = new MailMessage();
email.IsBodyHtml = true;
email.To.Add(reciver);
email.From = FromMailAddress;
email.Subject = "Email confomation link";
email.Body = "Please Fonfurm your email by pressing this link: link";
smtpClient.Send(email);
Sorry i really needed to block out some stuff. But this code works in a test application that i made in just simple comandline C# application. Now comes the strange thing when i call it in a simple ActionResult that i created for this it works but when i call it in Register method it fails it says time out, and for the rest it does not give anymore information. Here is the test method i created:
public ActionResult SendTestEmail()
{
new EmailManager().SendEmailConfirmation("xxxxxxxx", "Hello world");
return RedirectToAction("Index");
}
Quite simple and it works but when i put it like this it fails:
public async Task<ActionResult> Register(RegisterViewModel model)
{
// Check if model is valled And if we have a id
if (ModelState.IsValid && !String.IsNullOrEmpty(model.RegisterCode))
{
ApplicationUser user = new ApplicationUser { UserName = model.UserName, Email = model.Email.ToLower() };
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
// Sing in
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
// Add the members role to the user
UserManager.AddToRole(user.Id, "Member");
// Createing a token for email confermation
string emailCode = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
// Createing a URL
string callbackUrl = Url.Action(
"ConfirmEmail",
"Account",
new { userId = user.Id, code = emailCode },
protocol: Request.Url.Scheme
);
// Sending the email
new EmailManager().SendEmailConfirmation(model.Email, callbackUrl);
// delete the registion code form the database
GenerateCodeManager.DeleteFromCodeFromDatabase(model.RegisterCode);
// Return to index
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
return View(model);
}
And than we have a problem it fails. I really dont know why i think this also might the problem why my web server is also not sending emails. i use the SMTP of zoho That is this SMTP smtp.zoho.eu Like i said it works but not in this method.
I'm trying to give my users the ability to change email. I'd like to send a verification email as well, in which they can verify/confirm their email.
I'd just like to know more about the flow of this, and I haven't been able to find reasonable documentation online.
I see the flow like this:
User enters the new email they wish to use
Code/Token is created together with the confirmation email (the new email is not yet applied to the user)
Confirmation email is sent to the new email
User confirms/verifies their new email
New email and code is received in the controller and the UserManager.ChangeEmailAsync(User user, string newEmail, string code) is invoked
Is the new email applied to the user when the ChangeEmailAsync() method is invoked, or do I have to apply the new email before sending the confirmation email (set EmailConfirmed back to false)?
try this:
tring code = await UserManager.GenerateUserTokenAsync("ChangeEmail",userID);
in SendingEmail() to the new email and save the new email in a temporary table
the function when the user confirm the new e-mail:
`
public async Task<IHttpActionResult> ChangeEmail(ChangeEmailModel model)
{
try
{
HttpUtility.UrlEncode(model.Code);
if ( !UserManager.VerifyUserToken(model.UserId, "ChangeEmail", model.Code)) //to verify the code
{
_logger.Error($"token expired");
return ResponseMessage(Request.CreateResponse(HttpStatusCode.BadRequest, new KeyValuePair<String, String>(Messages.ExpiredLink, CommonMessages.ExpiredLink)));
}
else
{
UserDetailsManager userDetailsManager = new UserDetailsManager();
string Email = userDetailsManager.GetNewEmail(model.UserId);//get the new email from the temporary table
var user = await UserManager.FindByIdAsync(model.UserId);
user.Email = Email;//change the email
user.UserName = Email;
result = await UserManager.UpdateAsync(user);
if (!result.Succeeded)
{
foreach (var item in result.Errors)
{
if (item.Contains("already"))
{
_logger.Info("In ChangeEmail user already exists");
return ResponseMessage(Request.CreateResponse(HttpStatusCode.BadRequest, new KeyValuePair<String, String>(Messages.EmailUserExist, CommonMessages.EmailUserExist)));
}
}
}
}
}
}
catch (Exception ex)
{
_logger.Error($"In ChangeEmail Error - {ex.Message} return {HttpStatusCode.InternalServerError}");
return ResponseMessage(Request.CreateResponse(HttpStatusCode.InternalServerError, new KeyValuePair<String, String>(Messages.InternalServerError, CommonMessages.InternalServerError)));
}
_logger.Info($"ChangeEmail end status {HttpStatusCode.OK} ");
return Ok("Success");
}`
this function also Overrides the preoccupation with the confirmEmail
Here is my login code, the problem happens to users redirected to "Profile" after logging in.
protected void UserLogin_Click(object sender, EventArgs e)
{
if (IsValid)
{
var manager = new IdentityModels.UserManager();
IdentityModels.User user = manager.Find(Username.Text, Password.Text);
if (user != null)
{
if (isUserActive(user.PatientId)=="isNotActive")
{
lblError.Text =
"you are no longer active. Please contact your local clinic to find out why.";
return;
}
if (isUserActive(user.PatientId) == "clinicNotActive")
{
lblError.Text =
"Your clinic is no longer active. Please contact your local clinic to find out why.";
return;
}
IdentityModels.IdentityHelper.SignIn(manager, user, RememberMe.Checked);
if (manager.IsInRole(user.Id,"Administrator") || manager.IsInRole(user.Id,"Staff") || manager.IsInRole(user.Id,"Physician"))
{
Response.Redirect("Dashboard");
}
if (Request.QueryString["Profile"] != null)
{
IdentityModels.IdentityHelper.RedirectToReturnUrl(Request.QueryString["Profile"], Response);
}
else
{
Response.Redirect("Profile");
}
}
else
{
ModelState.AddModelError("", "Invalid username or password");
lblError.Text = "Invalid username or password";
}
}
}
here is my page load code on the Profile page:
var manager = new IdentityModels.UserManager();
IdentityModels.User user = manager.FindById(HttpContext.Current.User.Identity.GetUserId());
if (user == null)
{
var ex = new Exception("patient was null, BUT TRIED SIGNING IN NOW" + UserAccess.GetUserId().ToString());
Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
Response.Redirect("Login");
}
Elmah logs show the exception "patient was null, BUT TRIED SIGNING IN NOW 0".
So if my users are signing in successfully, which they must be because they are hitting the profile page, then why do some of them hit this error. Why is the user null?
I just can't figure it out, why it effects some but not all. When I republish the website all users can then login for a few minutes, sometimes a few hours, then it starts again.
Try using User.Identity rather than HttpContext.Current.User.Identity. I've seen some cases where the context (which is based on ASP.NET's session) gets out of sync with Identity's tokens.
OK guys, here is the answer.
Change the session state from InProc, in my case to SQLServer, it's been 22 hours since a login redirect, which hasn't happened before, so I think it's safe to say the problem is solved and that was the answer.
I am working on a windows form application which starts when computer is started. Now i want that when first time a user logins than it must save password somewhere and than next time it
must automatic login when computer is started.
Can Any body help me out in this issue???
Please Help..
Thanks in Advance
If I understand, you want to do this :
At first login :
Properties.Settings.Default["Username"] = "test";
Properties.Settings.Default["Password"] = "password";
And after, just read previous settings :
var user = Properties.Settings.Default["Username"];
var password = Properties.Settings.Default["Password"];
// Then call your login method
Concrete application :
public bool Login()
{
var username = Properties.Settings.Default["Username"];
var password = Properties.Settings.Default["Password"];
if (username == null || password == null)
{
// Ask the user to login
var user = LoginWindow.AskForLogin();
// If user login
if (user != null)
{
username = user.Username;
password = user.Password;
Properties.Settings.Default["Username"] = username;
Properties.Settings.Default["Password"] = password;
}
}
// Log your user
return Authenticate(username, password);
}
For example this answer. And msdn answer.
Also you can write password to registry:
Registry.SetValue(#"HKEY_CURRENT_USER\Software\MyApp\", "Password", password);
And read it:
var password = Registry.GetValye(#"HKEY_CURRENT_USER\Software\MyApp\", "Password", null);