Register Site User and Send Email - c#

What is the best way to register the user for the website and send a link with user name and password?
Admin will create the user by entering user name but not password
The password needs to be generated and stored as a hash text in database and send the same to user's email with link and user name. (Here I cant reverse the hash text back to plain text and send to in email) :(
How can i achieve this? I stored some random text in a hashed format in database. Not sure how I will email to the user, whenever admin create a new user.
Any idea/articles or suggestion?

Personally I don't like the sending passwords in plain text. However I can understand why it is sometimes required. For example an admin creating an account for a user.
Sending the initial email with credentials
When the user is registered with the website. Save the email address and randomly generated password (hashed) to the database. On successful INSERT send the email to the user with the original randomly generated password (not the hashed one).
If the email fails
If the email fails to send or reach the recipient, or they delete it, then they've lost the password. Your site will need a forgotten password section where the user can request it to be reset. On performing this action your script will create another random generated password, store the hashed version to the database and send the unhashed version to the user.
It's a good idea to separate the reset password from the main account details in case it wasn't the owner who tried to reset it. Otherwise when they come to login their known password will no longer work because the reset password would have overwritten it.
Change password on login
In both scenarios the user should be forced to change password on login.
Additional Options
If you wanted you could store a timestamp along with the account credentials for how long they have to reset or login for the first time. If the login request with the emailed credentials is within that time then you allow them access. If it is not then you say sorry credentials expired and allow them to reset again.

You can use authentication for admin login and giving him authority to create new logins.
You can get help about authentication and authorizations over here>>
http://msdn.microsoft.com/en-IN/library/eeyk640h%28v=vs.100%29.aspx
and
http://www.codeproject.com/Articles/98950/ASP-NET-authentication-and-authorization
And you can simply use this function to send Email>>
public int sendMail(string to,string cc,string bcc,string subject,string body)
{
try
{
SmtpMail.SmtpServer="your_server_address";
MailMessage msg = new MailMessage();
msg.From = "your_email_id";
msg.To = to;
msg.Cc = cc;
msg.Bcc = bcc;
msg.Subject = subject;
msg.Body = body;
SmtpMail.Send(msg);
return(1);
}
catch
{
return (0);
}
}
On SendEmail Button Click>>
private void Button1_ServerClick(object sender, System.EventArgs e)
{
String to = “to_email_id”;
String cc = “cc_email_id”;
String bcc = “bcc_email_id”;
String subject = “your subject goes here”;
String body = “your body text goes here”;
int status = sendMail(to,cc,bcc,subject,body);
if(status == 1)
Response.Write("your mail has been sent successfully");
else
Response.Write("sorry! your mail could not be sent”);
}
Hope its helpful.

Related

Altering the message sent by asp:PasswordRecovery email without loosing the password/username

I have an ASP PasswordRecovery control on my web application which was sending an email upon a successful password rest containing a short piece of text and then the username and newly reset password.
I needed to make the short piece of text bilingual so I added the following to the code behind:
protected void PasswordRecovery1_SendingMail(object sender, MailMessageEventArgs e)
{
e.Message.IsBodyHtml = false;
string body = "translated text" + Environment.NewLine + "english text";
e.Message.Body = body;
e.Message.Subject = ConfigurationManager.AppSettings["Subject"];
}
What happened then was the translated text came through but the username and password were now missing.
So I tried adding this to my body:
string pw = Membership.GetUser(PasswordRecovery1.UserName).GetPassword(PasswordRecovery1.Answer);
string p = PasswordRecovery1.UserName;
And I got this message:
This Membership Provider has not been configured to support password
retrieval.
So I added this to the control:
enablePasswordRetrieval="true"
But I still got the same message. What am I doing wrong?
If your Membership is configured to be hashed, then password retrieval is disabled.
A ConfigurationException will be thrown if enablePasswordRetrieval is set to true and passwordFormat is set to Hashed in the Web.config file for the ASP.NET application.
https://msdn.microsoft.com/en-us/library/2x0c6sfa%28v=vs.110%29.aspx
If this is the case, you should store the new password in a string, and then save this to the database using the ChangePassword() function.
I have this working like the below:
MembershipUser user = Membership.GetUser("username"); // or however you want to retrieve the MembershipUser object
string password = Membership.GeneratePassword(12, 0); // generate a new password
bool changePasswordSucceeded = user.ChangePassword(user.ResetPassword(), password); // reset the password
if(changePasswordSucceeded)
{
// email logic here
}
I had overcomplicated this massively.
As per Damien's comment you can easily solve this by creating your own PasswordReset.txt file, something like:
Translated Message
Translated word for UserName: <%UserName%> Translated word for
Password: <%Password%>
English Message
User Name: <%UserName%> Password: <%Password%>
Then just go to the PasswordRecovery Properties box and point MailDefinition-BodyFileName at your file.
As long as you have the tags as per above, the control will swap out the user name and password for you.
No need to mess around with the sending mail event in the code behind.
Hope this helps someone.

ASP.NET MVC and Identity - Reset password doesn't work

I have problem with resetting password for user account. I am using Microsoft way to do it, but it's just not working. Here is the code that I use to generate reset password token
var resetPasswordToken = new ResetPasswordToken
{
Id = Guid.NewGuid().ToString(),
Token = UserManager.GeneratePasswordResetToken(user.Id),
User = user,
ValidFrom = DateTime.Now,
ValidTo = DateTime.Now.AddMinutes(ApplicationConstants.SettingsResetPasswordTokensValidTimeInMinutes)
};
_resetPasswordTokensRepository.Insert(resetPasswordToken);
_resetPasswordTokensRepository.Save();
var email = new ResetPasswordEmailModel
{
ResetPasswordToken = resetPasswordToken,
User = user
};
IUserMailer mailer = new UserMailer();
mailer.ResetPassword(email).Send();
That works fine, I have the token in database and I send it to user via email. Then user has to click the link. Here is how I generate new password and replace old password with the new one in database.
var resetPasswordToken = _resetPasswordTokensRepository.GetByEmailAndToken(email, code);
var newPassword = Membership.GeneratePassword(10, 2);
var result = await UserManager.ResetPasswordAsync(user.Id, resetPasswordToken.Token, newPassword);
if (result.Succeeded)
{
_resetPasswordTokensRepository.Remove(resetPasswordToken);
_usersRepository.Save();
var model = new NewPasswordEmailModel
{
User = user,
Password = newPassword
};
IUserMailer mailer = new UserMailer();
mailer.NewPassword(model).Send();
}
And this also works. I mean it changes password in database and sends it to user via email. The problem is user can not login with the new password or with the old password.
I did not show it here, but I check if both token and user exist in database.
What am I doing wrong?
Despite that you already found the issue, I'll try to point in a better direction.
What you describe is not a "Microsoft" way. First time I see something like that. Is this part of a template? Open Visual Studio 2013 and create a new MVC project with Individual Accounts - this will give you the "Microsoft" way.
You save the token in you DB. No need for that. Token should be emailed to a user as a link and then clicked by user and this way the token will be passed to the controller where you reset the email.
You generate a new password for user. Don't do that - let users pick their own password. And you use Membership for that - bad practice to mix Identity and MembershipProvider. MebershipProvider is very invasive and tries to take over when it can. Possibly it can cause issues later down the lifetime.
You email the password to a user. Very bad security practice. Email is not a secure channel. Let the user pick their new password on your web-page and don't ever email the passwords.
Highly recommended article by Troy Hunt about password resetting - a very worthy reading if you work with passwords.

How to allow Unauthenticated users to reset password?

Please see Update Below:
I am using ASP.NET SQL Membership Provider.
So far I am able to allow users to change their password but only if they are authenticated or logged into the application.
What I really need is for users to be able to get a link in an email. They can click this link and reset their password.
Example: Lets say a user forgets his or her password, they can visit a page which they can either enter security question and answer; or their email address on file. They will then get an email with a link to reset their password.
All I have so far is this: Which allows only authenticated users to reset their passwords:
I do not want to use the Recovery Control which generates a password.
public void ChangePassword_OnClick(object sender, EventArgs args)
{
MembershipUser user = Membership.GetUser(User.Identity.IsAuthenticated);
try
{
if (user.ChangePassword(OldPasswordTextbox.Text, PasswordTextbox.Text))
{
Msg.Text = "Password changed.";
}
else
{
Msg.Text = "Password change failed. Please re-enter your values and try again.";
}
}
catch (Exception e)
{
Msg.Text = "An exception occurred: " + Server.HtmlEncode(e.Message) + ".
try again.";
}
}
I can create the store procedure and the email using a String Builder but I do not know how to get the un-authenticated user to change password. Is there a way for the user to be Authenticated when they click the link. I am not sure how to even ask this.
Thanks for reading:
Update:
Okay I managed to get the password to Reset using this code:
protected void btnResetPassword_Click(object sender, EventArgs e)
{
string username = "ApplePie12";
MembershipUser currentUser = Membership.GetUser(username);
currentUser.ChangePassword(currentUser.ResetPassword(), txtResetPassword.Text);
}
Here is my plan:
Make this page public so that it is access by Un-Authenticated Users but only via email link.
Create a Stored Procedure that verifies a user Exists either by the UserName they enter or by the Security Question/Answer.
If they exists, they are sent a link containing a token/GUID
Lastly when they click the link they will land on this page asking them to change password. *The Link Expires as soon as it is used.
My only question is: Doing all of the above requires turning off using security Question/Answer in the Web Config file.
I really would love to have the Security question as an option for the user to either verify by email or security question. If this is not possible, I'll have to create some kind of account number or userid (not membership user id) as an alternative.
My answer is not specific to Membership Provider, but hopefully will point you in the right direction. Typically the way to approach this is to generate a very long random string, called a token. You send them a link that includes this token as a parameter, something like:
http://foo.bar/reset?token=asldkfj209jfpkjsaofiu029j3rjs-09djf09j1pjkfjsodifu091jkjslkhfao
Inside your application you keep track of tokens you have generated. If you receive a request containing that token, you authenticate it as if it was that user.
A couple notes:
The token generated should be random and effectively unguessable in a short period of time.
The token should only work for a short period of time after being generated, ideally shorter than the time required to guess it.
The token should only be usable once. Once a user has changed their password using it, remove it from the system.
Chris has given definitely the correct solution.
You can use the sql table for token management. the token may be UserId or Email that are unique. the link used for reset email like http://test.com/reset?id=sfksdfh-24204_23h7823.
The id in the url is encrypted Userid or Email as you like.
Fetch the detail from table on the basis of id in Url. if id contain in database. then reset the password for user. and remove that token from DB.

WebMatrix.WebData.WebSecurity - How can I get UserName by only having PasswordResetToken

I just wanted to ask for help to get my scenario work? I want to get the UserName using a PasswordResetToken.
This is my scenario.
I have a forgot password feature in my website that would send a passwordresettoken email a change password to the user.
I wanted to send just the passwordresettoken string only.
When the user clicks the link. I will just query the request["token"] to get the username and and then will allow the user to change password and autologin.
this is my code below:
public ActionResult ChangePassword()
{
ChangePasswordModel model = new ChangePasswordModel();
string token=string.Empty;
try
{
token = Request["token"].ToString();
int userId = WebSecurity.GetUserIdFromPasswordResetToken(token);
if (userId > 0)
{
//Get the user object by (userid)
//???????????????????
//???????????????????
}
else
{
throw new Exception("The change password token has expired. Please go to login page and click forgot password again.");
}
}
catch
{
model.HasError = true;
ModelState.AddModelError("", "The change password token has expired. Please go to login page and click forgot password again.");
}
return View(model);
}
Thank you in advance.
Look at the remark at the end of this article: WebSecurity.GeneratePasswordResetToken Method.
I'll copy the relevant part for your convenience:
If users have forgotten their password, they can request a new one. To
provide a new password, do the following:
Create a password-reset page that has a field where users can enter their email address.
When a user has entered his or her email address in the password-reset page, verify that the email address represents a valid
user. If it does, generate a password reset token by calling the
GeneratePasswordResetToken(String, Int32) method.
Create a hyperlink that points to a confirmation page in your site and that includes the token as a query-string parameter in the link's
URL.
Send the link to a user in an email message. When the user receives the email message, he or she can click the link to invoke the
confirmation page.
Create a confirmation page that extracts the token from the URL parameter and that lets the user enter a new password.
When the user submits the new password, call the ResetPassword(String, String) method and pass the password reset token
and the new password. If the token is valid, the password will be
reset. If the token is not valid (for example, it has expired),
display an error message.
Highlighting is mine. Basically you do not need the user name. The framework does all the heavy lifting for you.
Addressing your comment, I would not recommend automatically logging the user in. It's a good practice for them to log manually to check that this password changing thingie has actually worked, and not to discover that it did not only next time around.
Anyway, you can do this:
SimpleMembershipProvider provider = (SimpleMembershipProvider)Membership.Provider;
string username = provider.GetUserNameFromId(userId);
Reference: GetUserNameFromId.
I think the WebSecurity.GetUserIdFromPasswordResetToken(string token) method do what you want.
More info here.
Update:
Sorry but I didn't saw that you were already using that method... So if you want get the username and you are using code first migrations of Entity Framework, you can get the username with the following LINQ expression:
string username = yourDbContext.UserProfiles.FirstOrDefault(up=>up.UserId == userId).Username;

C# Rollback sendemail

I wrote a code to recover passwrod in my website.The user enter his email address and we send a new password to him.In additcion,we also change his password in DB to newest password.
Problem:
If code for send mail fails,i cant change his password in DB,and if code to change password fails i cant send mail.
Take a look:
public bool RecoverPassword(string email)
{
try
{
SceLoginMail sceEmail = new SceLoginMail(email, "Recuperação de senha", 5);
ChangeUserPassword(sceEmail.NovaSenha, email);
sceEmail.SendEmail();
sceUsers.CommitOrRollBack(true);
return true;
}
catch (Exception ex)
{
sceUsers.CommitOrRollBack(false);
return false;
}
}
I try to rollback in DB if an exceptions occurs in SendEmail method.But,i cant "RollBack" the SendMail method if an exceptions throws in CommitOrRollback method.If so,system will send the mail and wont change it on DB.
Any ideias?
Don't send the email until after the database transaction (and anything else that affects the validity of the new password) has completed. That way, if it throws an exception, the SendEmail() call never gets executed.
Doesn't matter much if you assign a new password and it doesn't get sent for some reason. The user already doesn't know his/her password. The email won't show up, and they will request it again. So commit the DB, and do a send, in that order.
Instead of resetting the password in response to the "I lost my password" request, send the user an email with a unique, single-use, time-bounded reset URL. Only reset the password if that URL is visited within the allowed time.
This has two benefits:
The password is only reset if the email is successfully sent and received.
If someone other than the person the account belongs performs the "I lost my password" request (whether by accident or on purpose), the legitimate account-holder doesn't have his/her password unexpectedly become invalid.
See, the action to request for password change and request to get email for the changed password is separate phenomenon.
When user requests the change of password, you just invoke the statement to update the database with the new password. After its updated, try sending the mail.
It is better to have a Mail Outbox in. So that when the email sending fails, it is stored in the database table outbox and which you should periodically try out after a Threshold time.
This would ensure that you keep trying sending that mail to the user.

Categories