Creating Sitefinity User Password Hash - c#

I am seeking some help on a telerik sitefinity backend feature. I'm creating users from a custom radgrid programatically. The code that I'm using to create a sitefinity user is as follows:
public MembershipCreateStatus AddUser(UserModel model, Role role)
{
var userManager = UserManager.GetManager();
var profileManager = UserProfileManager.GetManager()
var roleManager = RoleManager.GetManager("AppRoles");
MembershipCreateStatus status;
userManager.Provider.SuppressSecurityChecks = true;
var user = userManager.CreateUser(model.UserName, model.Password, model.Email,
model.SecretQuestion, model.SecretAnswer, true, null, out status);
if(status == MembershipCreateStatus.Success)
{
roleManager.AddUserToRole(user, role);
roleManager.SaveChanges();
var profile = profileManager.CreateProfile(user, Guid.NewGuid(),
typeof(SitefinityProfile)) as SitefinityProfile;
if (profile != null)
{
profile.FirstName = model.FirstName;
profile.LastName = model.LastName;
//Set any Data Extended Properties below
}
profileManager.RecompileItemUrls(profile);
profileManager.SaveChanges();
userManager.SaveChanges();
}
return status
}
This will let me create a sitefinity user and I can see that the user is stored in the sf_users table. The problem that I'm having is I need a way to lookup and send a user their password if they forget the password. The password is hashed and saved in an encrypted format in the table in the database. I've looked for documentation on how to change the password format to clear text or something of the sort but I've been unsuccessful in finding anything useful yet.
If anyone knows how to accomplish this so that I can save the password as clear text in the database then that would be really great.

Sitefinity Membership Provider is designed to work in similar way as the SQL Membership Provider. It supports three modes - Hashed (default), Encrypted and Clear. The Hashed format is default one. More information here: http://www.sitefinity.com/documentation/documentationarticles/developers-guide/deep-dive/security/users/password-format.
Hashed passwords are irreversible and you cannot achieve what you want using a hashed password format. Instead you can achieve this by either using the Clear (strongly not recommended) or the Encrypted (also not a good security practice).
However the CMS allows you to have reset password functionality or retrieve. Reset if Hashed format is used and retrieve if Encrypted is used. This article explains both approaches: http://www.sitefinity.com/developer-network/knowledge-base/configuring-password-recovery-in-sitefinity.

I don't know how SiteFinity works but it seems to use MembershipProvider. So the password format setting depends of the provider used and can be changed in the web.config file.
For example (http://msdn.microsoft.com/en-us/library/system.web.security.sqlmembershipprovider.aspx)
<system.web>
<membership defaultProvider="SqlProvider">
<providers>
<add
name="SqlProvider"
type="System.Web.Security.SqlMembershipProvider"
passwordFormat="Clear" />
</providers>
</membership>
</system.web>
Anyway, storing password in clear way is not a good practice. Instead you should provide users an interface to reset their password. At least you should generate a new password and send them the new password (of course they must be able to change it). This way the password can be hashed before saving it in the database.

Related

Best practice to send a member their forgotten password

I am building a login/registration section for our members area in Umbraco 7.1.7.
I would like to send a user their password in plain text via email.
The idea is, if the user forgets their password, they can simply enter their email address (which also serves as their username) and clicks the button:
Now, I know Umbraco uses the ASP.NET Membership Provider and hashes passwords, which is nice but I need to access the plaintext version to send in the email.
I have changed my web.config to include this:
<membership defaultProvider="UmbracoMembershipProvider" userIsOnlineTimeWindow="15">
<providers>
<clear />
<add name="UmbracoMembershipProvider"
type="Umbraco.Web.Security.Providers.MembersMembershipProvider, Umbraco"
minRequiredNonalphanumericCharacters="0"
minRequiredPasswordLength="0"
useLegacyEncoding="true"
enablePasswordRetrieval="true"
enablePasswordReset="true"
requiresQuestionAndAnswer="false"
defaultMemberTypeAlias="Member"
passwordFormat="clear" />
and my Controller Action method looks like this:
// Forgot password logic to send email
[ActionName("MvcMemberForgot")]
public ActionResult MvcMemberForgot(MvcMemberForgotModel model)
{
string emailaddress = model.Email.ToString(); // The users entered email address.
var member = Services.MemberService.GetByEmail(emailaddress);
var sb = new StringBuilder(); // To build the message.
sb.Append("Here is the password you chose for this email address: ");
sb.Append(password); // I need a password value here...
// Send the email.
library.SendMail("noreply#company.co.uk", emailaddress, "Password", sb.ToString(), true);
return CurrentUmbracoPage();
}
I can use var x = member.RawPasswordValue; to return the hashed password, is there a way to get the password the user typed in when they registered in a similar way?
I wouldn't send the emails to people in plain text, that's very poor security practice. The way I approached this recently was to do the following:
add a property to the member (a label) for storing a reset timestamp
have a reset request form that validates the user by email address, and then sets the label to a timestamp set 30 minutes to the future
send the member an email with a link to another form page, passing in their email and timestamp
on the form, get the email and timestamp, verify that the email exists, and that the timestamp hasn't expired
if they pass those tests, give them the option to enter and confirm a new password that you then save against the user (clearing the timestamp from the label at the same time)
My approach was based on the code from this example repo: https://github.com/warrenbuckley/CWS-Umbraco-Standard-Membership which contains a lot of useful examples of working with members!

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.

Change User Password in ASP.NET Forms Authentication

I code in C# (ASP.NET) and am using Forms authentication.
I would like to know which is the best method to change a user password without using the asp:ChangePassword control.
I dont want to use the reset password method.
I just want to grab the password i have inside my textbox and replace it with my older password.
Please note that the PasswordFormat I use is passwordFormat="Hashed"
Some code snippets would be helpful
Edit:
In my web.config, I have set enablePasswordRetrieval="false"
I used the following method
var myUser = Membership.GetUser(userID);
bool isChangeSuccess = myUser.ChangePassword(
myUser.GetPassword(),
ActivateUserPasswordText.Text.Trim());
It gives me the error,
This Membership Provider has not been
configured to support password
retrieval.
What could be done to solve these issues?
I would really like my PasswordFormat to be hash itself.
Regards,
Naveen Jose
Got it solved. Thanks to my fellow developer.
var myUser = Membership.GetUser(userID);
bool isChangeSuccess = myUser.ChangePassword(
myUser.ResetPassword(),
ActivateUserPasswordText.Text.Trim());
Cant say I liked it much though.
I thought ResetPassword() would be returning a bool.
Assuming you are using the ASP.NET security thingies.
System.Web.Security.MembershipProvider.ChangePassword method
Only the Hash value for the passwords are usually stored by the asp.net membership provider, so it is not possible to retrieve the original password. It is possible to change this behavior by configuration, but it is not recommended.
Simply ask the user to enter the old password also while changing the password. You can use the old password entered by the user in the User.ChangePassword method and it should work fine.
This Membership Provider has not been configured to support password retrieval.
The above message is displayed because of your password format will be salt and so that you can't get the password of the user. If you want to do this change the password format and try again.
On the off chance someone is using the ApplicationUser and not the Membership - as I was because I did not want to set a Membership Provider - you can change the password this way:
Dim manager = New UserManager()
Dim userChange As ApplicationUser = manager.FindById(IDUser)
userChange.PasswordHash = manager.PasswordHasher.HashPassword(newPassword.Value)
Dim val As Object = manager.Update(userChange)
Hope this helps someone

What is a quick way I can add simple authentication to a few ASP.NET MVC routes, without implementing the whole Membership provider jazz?

I've created a demo website for my boss and one of the requirements is I need to add some simple authentication to his 3 admin views/routes.
What is the simplest, quickest way I can do this without implementing a whole membership provider? I honestly don't even care if the user/pass is hardcoded on the server side, I just need it so they can't access those 3 views without having authenticated in some way.
I would go this route.
Add this to your web.config (could omit the SHA1 and use a plain text password if you want):
<authentication mode="Forms">
<forms loginUrl="~/admin" timeout="2880">
<credentials passwordFormat="SHA1">
<user name="admin" password="4f3fc98f8d95160377022c5011d781b9188c7d46"/>
</credentials>
</forms>
</authentication>
Create a simple view for username and password and in the action method that receives the username and password go with this...
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult LogOn(string username, string password)
{
if (FormsAuthentication.Authenticate(username, password))
{
FormsAuthentication.SetAuthCookie(username, false);
return RedirectToAction("Index", "Home");
}
else
{
ViewData["LastLoginFailed"] = true;
return View();
}
}
FormsAuthentication.Authenticate() automatically checks the username and password against the credentials node we created earlier. If it matches it creates your auth cookie with a "Remember Me" value of false and redirects you to the index view of your home controller. If it doesn't match it returns to the login page with ViewData["LastLoginFailed"] set to true so you can handle that in your view.
PS - Now that you have an easy way of authorizing don't forget to put the [Authorize] filter over the actions or controllers you want to protect.
easiest would be to select the menu [project] followed by [ASP.NET Configuration] in Visual Studio.
It'll set up a membership db for you. then add a couple of roles and users in the configuration manager that pops up.
that's it! Then simply decorate your actions/controllers with [Authorise] and check for some rights based on the user name. <= hard coded for the demo

FormsAuthentication after login

Ok, i have simple scenario:
have two pages:
login and welcome pages.
im using FormsAuthentication with my own table that has four columns: ID, UserName, Password, FullName
When pressed login im setting my username like:
FormsAuthentication.SetAuthCookie(userName, rememberMe ?? false);
on the welcome page i cant use:
Page.User.Identity.Name
to provide to user which user currently logged, BUT i dont user username like at all examples in http://asp.net web site i want to user FullName field
i think that always go to db and request fullname when page loads its crazy and dont like to user Sessions or Simple Cookie mayby FormsAuth provider has custom fields for this
I would store the user's full name in the session cookie after your call to FormsAuth
FormsAuth.SetAuthCookie(userName, rememberme);
// get the full name (ex "John Doe") from the datbase here during login
string fullName = "John Doe";
Response.Cookies["FullName"].Value = fullName;
Response.Cookies["FullName"].expires = DateTime.Now.AddDays(30);
and then retrieve it in your view pages via:
string fullName = HttpContext.Current.Request.Cookies["FullName"].Value
Forms authentication works using cookies. You could construct your own auth cookie and put the full name in it, but I think I would go with putting it into the session. If you use a cookie of any sort, you'll need to extract the name from it each time. Tying it to the session seems more natural and makes it easy for you to access. I agree that it seems a waste to go back to the DB every time and I would certainly cache the value somewhere.
Info on constructing your own forms authentication cookie can be found here.
Sorry I'm a little late to the party, but here's how you can do this without storing the value anywhere else :)
var authCookieKey = FormsAuthentication.FormsCookieName;
var responseCookies = HttpContext.Current.Response.Cookies;
var requestCookies = HttpContext.Current.Request.Cookies;
var aspxAuthCookieInResponse = responseCookies.AllKeys.Contains(authCookieKey) ? responseCookies[authCookieKey] : null;
var aspxAuthCookieInRequest = requestCookies.AllKeys.Contains(authCookieKey) ? requestCookies[authCookieKey] : null;
// Take ASPXAUTH cookie from either response or request.
var cookie = aspxAuthCookieInResponse ?? aspxAuthCookieInRequest;
var authTicket = FormsAuthentication.Decrypt(cookie.Value); // Todo: Check for nulls.
// Using the name!
var userName = authTicket.Name;
There are no custom fields for forms authentication. You'll just have to use session. That's what it's there for you know. ;) Just don't forget - forms authentication cookie and session are two independant things. They even each have their own timeouts. So the session won't be reset when a user logs out unless you do so yourself.
What about using Profiles to store the extra info with the User?
The simplest option is to use the session. By default session state is stored in memory and will be lost when the ASP.NET worker process recycles, however you can configure it to use state service instead, which retains session info in a separate process:
http://msdn.microsoft.com/en-us/library/ms178586.aspx
Another option would be to use profiles. As it sounds like you already have 'profile' information stored in your own tables, you'd probably have to write a custom provider for it so it's a more complex solution.

Categories