I have a scenario here whereby when a user wants to reset a password, the system will have to send a temporary random generated password to the user by email. I tried storing the temporary password into a new column in the database but I am not really sure about whether this approach works well. Some people recommend using token such as below:
string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
However, I am really new to ASP.NET and I am not familiar with token. How do I compare the temporary generated token with the token in the database?
Another method that I found to implement this is to have a Membership.GeneratePassword function that generates a random string of characters:
model.temppwd = Membership.GeneratePassword(10, 1);
Can anybody provide me an ideal way to implement this functionality with some example? Thank you!
In our project we used
Guid.NewGuid();
and sent the email containing the link to the recover password action (MVC) as a query string: https://yoursite.com/account/reset/?code=your_guid_code
Example:
ResetPassword resetPassword = new resetPassword();
resetPassword.Code = Guid.NewGuid();
string strLink = string.Format("{0}", actionUrl + "?code="+ resetPassword.Code);`
And now you can use the strLink to send with your e-mail. You'll need to store the Guid in a database table alongside with the userId, so that you can implement the resetting procedure. When the user clicks the link from your email he'll get in a form / view that asks for a new password. Also you'll want to add an extra column to that table in order to provide an expiration limit for that code. If the user clicks the link in the e-mail and the code expired you'll have to inform the user and send another e-mail with another code.
Related
First, I am pretty new to C# and sorry for the bad writing, I have a razor page web app with individual accounts authentication type. Now I am working on a UWP app in which users can log in to the UWP app with the username and password provided in the razor app. Users have the same username and password for both applications.
Is there any possible way to log in user to the UWP app and also limit users to access different parts of the app just like razor pages(Role manager)?
Please note that the razor app is on a local server (on-premise), not a cloud, also the UWP app is on the same network so it can access the database.
What is expected to happen is that users must provide a username and password in the UWP app, they have limited access based on their roles, user names and passwords are fetched from the razor page application Db, UWP app doesn't need the ability to create or edit user accounts(it's all managed by razor app)
Update
Please be more specific about your question next time.
if you want to hash the password in UWP apps, you could use HashAlgorithmProvider Class to hash the text. The HashAlgorithmProvider class support MD5,SHA1,SHA256,SHA384,SHA512. You could choose the same way as you choosed in your razor app.
The sample code looks like this:
public string SampleHashMsg()
{
string strAlgName = HashAlgorithmNames.Md5;
string strMsg = "thisistest";
// Convert the message string to binary data.
IBuffer buffUtf8Msg = CryptographicBuffer.ConvertStringToBinary(strMsg, BinaryStringEncoding.Utf8);
// Create a HashAlgorithmProvider object.
HashAlgorithmProvider objAlgProv = HashAlgorithmProvider.OpenAlgorithm(strAlgName);
// Demonstrate how to retrieve the name of the hashing algorithm.
string strAlgNameUsed = objAlgProv.AlgorithmName;
// Hash the message.
IBuffer buffHash = objAlgProv.HashData(buffUtf8Msg);
// Verify that the hash length equals the length specified for the algorithm.
if (buffHash.Length != objAlgProv.HashLength)
{
throw new Exception("There was an error creating the hash");
}
// Convert the hash to a string (for display).
string strHashBase64 = CryptographicBuffer.EncodeToHexString(buffHash);
// Return the encoded string
return strHashBase64;
}
Old
Your post contains many questions. Please focus on question in one post next time.
First, you need to check the document: Use a SQL Server database in a UWP app. This tutorial shows the steps about how to connect to a sql server in UWP apps. Then you will have to write your own logic for checking the input for username and password and verify it with the data in the database.
After that, you might need to create a userinfo class which contains a flag that could indicate the role or the user after you verified the user. Before navigation, you could check the flag do decide if the user could access the page. If not, then cancel the navigation.
I am sending link to email address for password reset functionality and after sometime i want this link to expire. for that i have created a token(which is encrytped using a key) and expire-date and i want to put these as query in my email link but i don't know to do it.
this is how i use token class in forgotPassword Post method.
var tokenModel = new LinkExpire();
tokenModel.ExpiresOn = DateTime.Now.AddSeconds(10);
tokenModel.CreateToken = TokenHelperMethods.GetToken(tokenModel);
this is my link code.
string resetCode = Guid.NewGuid().ToString();
var varifyUrl = "/E_HealthCare_Web/Account/ResetPassword/" + resetCode;
var link = Request.Url.AbsoluteUri.Replace(Request.Url.PathAndQuery, varifyUrl);
and in my email body i am sending link like this
"<br/> <br/> <a href = '" + link +"&expire="+tokenModel.ExpiresOn+"&token="+tokenModel.CreateToken+"'>Reset link</a> <br/><br/>" +
which does not to work as expected. anyone can help me achieve this, also i am not using core, only mvc5.
Edit this is my controller where i am recieving link values
public ActionResult ResetPassword(string id, DateTime expire, string token)
while clicking on link gives A potentially dangerous Request.Path value was detected from the client (&) error.
Here is my suggestion, instead of adding expiration token query parameters with URL manage this at your method action level i.e.
You already have the information that which login is going to this URL. All you have to do is that before sending this URL via email, make a separate temp table that will have user ID, reset password URL path, created date/time column (this column will mange the data/time when you send the URL to the user for password reset) and active/Iactive status column.
Now at code level when this particular URL is hit by user, first get the active row only entry against this URL & user ID and get the created date/time column value.
Check the difference between the active created date/time column and current date/time.
if difference between two dates is more than 24hr send expiration response otherwise change the password.
Mark that entry as inactive.
Know that against each user the active entry in this new table exist only when user request's password reset, otherwise all existing entries are marked as inactive.
You can delete instead of active/inactive as well. this is temp table.
To reset a password we need to know a UserId and pass it to the UserManager.ResetPasswordAsync method. In the Identity 1.0 it was possible to obtain UserId from the UserManager.PasswordResetTokens.Validate method ((UserManager.PasswordResetTokens.Validate(token)).UserId). Now it's gone and all existing examples telling me that I need to ask an user for username or email. This is not user friendly, I don't want my users enter username again if token is valid.
This is already established tradition in ASP.NET Identity - something that worked before is broken in the new release. Of course I can create my own combined token with embedded UserId, but why I need to do extra work? New releases should improve things, not make them worse.
Asp.Net Identity 2.x do not provide a way to find a user by a token created from GeneratePasswordResetTokenAsync method.
You have two options:
1) Add the user id at the url you will send to the user. Ex:
var token = await _userManager.GeneratePasswordResetTokenAsync(applicationUser);
var callbackUrl = $"/reset-password/?user={WebUtility.UrlEncode(applicationUser.Id)}&code={WebUtility.UrlEncode(token)}";
This approach is more user friendly. But I know people that says this is a security issue because anyone with the link could reset the user password.
2) Ask for the user name at the reset password page, as you did. Ex:
public async Task<YourResultModel> ResetPassword(ResetPasswordViewModel vm)
{
// Your password validations...
var user = await _userManager.FindByNameAsync(vm.UserName);
// could be FindByEmailAsync if your app uses the user e-mail to login.
IdentityResult result = await _userManager.ResetPasswordAsync(user, vm.Token, vm.NewPassword);
return YourResultModelFromIdentityResult(result);
}
Before choose between this two approaches you need to think about your specific scenario. For example: If your app uses the user e-mail as username and to intercept the token the "interceptor" needs to access the user e-mail box, remove the user id from reset password link will not improve the security of your app. Because who has the link already knows the e-mail of the user.
I have made custom login control for DNN (DotNetNuke). Now I am trying to implement the forgot password feature. I am able to retrieve password from the database using the code:
UserInfo uInfo = UserController.GetUserByName(this.PortalId, userName);
if (uInfo != null)
{
string password = UserController.GetPassword(ref uInfo, String.Empty);
}
I want to send the retrieved password to the user using DNN.
Any help will be appreciated.
Sending passwords via email is considered as a big security vulnerability and really not recomended.
If you still need this functionality though, I guess you can simply accomplish this by sending email through SendMail or SendEmail methods:
DotNetNuke.Services.Mail.Mail.SendEmail()
DotNetNuke.Services.Mail.Mail.SendMail()
The SendMail method provides more options/parameters than the SendEmail method. The paramters names should be self explanatory enough to use the methods.
The simplest way to send a user their password is to call the DotNetNuke.Services.Mail.Mail.SendMail overload that takes a UserInfo, a MessageType, and PortalSettings. You can pass in the user and MessageType. PasswordReminder and DNN will take care of the rest.
That said, I join the crowd in saying that it would be much better to switch to using hashed passwords and consider this an impossible feature request (that should, instead, be fulfilled with a password reset feature).
I have an ASP.NET App in which want to send an email to a user that presses a Recover Password button that resets the user's password and then sends a link to the user that when followed will log the user in with a new password and bring them to the Change Password page where they must resent their password.
I'm able to reset the password and get the new randomly generated password that I send back to the user in an email. However, when the user follows the link back with the UserName and pw parameters, the system does not seem to log them in,
Here's the code I am using on the load event that does not seem to work:
try
{
string sUserName = Request.QueryString["UserName"].ToString();
string sPw = Request.QueryString["pw"].ToString();
if (Membership.ValidateUser(sUserName, sPw))
{
//Log the user in???
FormsAuthentication.Authenticate(sUserName, sPw);
}
}
catch (Exception r)
{
string sMessage = r.Message;
}
Any help in logging the user in with username and password parameters would be greatly appreciated.
You can use FormsAuthentication.SetAuthCookie() :
if (Membership.ValidateUser(sUserName, sPw))
{
FormsAuthentication.SetAuthCookie(sUserName, true);
}
In your sample code you are retrieving the user name and password from the query string - this is very bad practice as any observer will see it in plain text. At least use a POST for these values and put them in the body (i.e with a form POST) and always use HTTPS at least for your login page.
use the following code.
if (Membership.ValidateUser(sUserName, sPw))
{
FormsAuthentication.SetAuthCookie(sUserName, true);
Response.Redirect("ChangePassword.aspx");
}
FormsAuthentication.Authenticate is almost same as FormsAuthentication.ValidateUser. They just validate user authentication. SetAuthCookie creates the authentication ticket(login).
This is how (IMO) reset password functionality should work:
User clicks button saying "Forgot Password".
In your code store a random GUID in the DB.
Send the user an email, with the GUID as a link in the email, as well as their userid, e.g:
http://yoursite.com/user/reset?guid=a21312738&userid=213123
On the incoming page, read the userid from the QS, and fetch the user from the DB by this value.
Compare the stored GUID from the GUID in the QS. If success, render a form that allows the user to change the password via an HTTPS POST.
In the POST action, change the user's password and sign them in.
You could also go one step further and store an expiration date for the GUID (e.g user must change their password in 24 hours).