Migrating from SqlMembershipProvider to Custom Provider - asp.net

Here's the scenario:
I have used default SqlMembershipProvider to implement membershp on a website. Now I'd like to migrate to my custom membership provider. (FYI the provide I use is CodeFirst Membership Provider.
The problem is, the provider uses a custom encryption/hash algorithm to store passwords in db and I don't want to generate new passwords for every user and mail them the new password.
How can I implement default membership password hashing/encryption in my provider. I used reflector/googled and tried the following code which seems to be the default implementation in SqlMembershipProvider:
internal static string GenerateSalt()
{
byte[] buf = new byte[16];
(new RNGCryptoServiceProvider()).GetBytes(buf);
return Convert.ToBase64String(buf);
}
internal string EncodePassword(string pass, string salt)
{
byte[] bIn = Encoding.Unicode.GetBytes(pass);
byte[] bSalt = Convert.FromBase64String(salt);
byte[] bAll = new byte[bSalt.Length + bIn.Length];
byte[] bRet = null;
Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);
HashAlgorithm s = HashAlgorithm.Create("SHA1");
bRet = s.ComputeHash(bAll);
return Convert.ToBase64String(bRet);
}
And used it in my ValidateUser method:
string salt = GenerateSalt();
string pass = EncodePassword(enteredPassword, salt);
bool verificationSucceeded = pass == user.Password;
But the pass returned from EncodePassword is different from the one that the default SqlMembershipProvider has put into database before switching to custom membership. How can I implement the exact password validation/generation like Default SqlMembershipProvider?
Note: since I have not defined any machinekey in my web.config, I'm sure the default provider used Hashed Password Format, not Encrypted or Clear.
Thank you.

Found the solution:
in ValidateUser method, we have to get PasswordSalt from aspnet_Membership table, not generating it!
Dummy question. :|

Related

Password (hash) doesn't match when re-using existing Microsoft Identity user tables

We have an existing SQL database with Microsoft Identity tables, originally generated by a ASP.NET Core app.
We also have an ASP.NET 4 app, which also uses Microsoft Identity.
We'd like the ASP.NET 4 app to be able to validate logins using the same database as the original .NET Core app.
However, when we try to validate passwords, they don't match.
I'm just guessing that the password hashes generated by the .NET Core app cannot be validated by the ASP.NET 4 app, but I'm not sure where to go from here. :)
There's no custom password hashing in the .NET Core app, and I'm struggling to find any config that might affect hashing?
Any help or pointer is greatly appreciated!
Edit: It seems this may be caused by different hashing algorithms in Identity V2/V3. Not sure how to mimic the V3 hashing algorithm in the ASP.NET 4 app, though.
As per the documentation located: https://github.com/aspnet/Identity/blob/a8ba99bc5b11c5c48fc31b9b0532c0d6791efdc8/src/Microsoft.AspNetCore.Identity/PasswordHasher.cs
/* =======================
* HASHED PASSWORD FORMATS
* =======================
*
* Version 2:
* PBKDF2 with HMAC-SHA1, 128-bit salt, 256-bit subkey, 1000 iterations.
* (See also: SDL crypto guidelines v5.1, Part III)
* Format: { 0x00, salt, subkey }
*
* Version 3:
* PBKDF2 with HMAC-SHA256, 128-bit salt, 256-bit subkey, 10000 iterations.
* Format: { 0x01, prf (UInt32), iter count (UInt32), salt length (UInt32), salt, subkey }
* (All UInt32s are stored big-endian.)
*/
At one point, identity used a different hashing algorithm - maybe it's using the version 2 format in one, and the version 3 format in the other?
The constructor of the class takes in options, you can try tweaking that to get the correct hash?
public PasswordHasher(IOptions<PasswordHasherOptions> optionsAccessor = null)
EDIT:
I found the Identity v2.0 source here: https://aspnetidentity.codeplex.com/ and git repo: https://git01.codeplex.com/aspnetidentity
Looking through source, you come across its hashing method.
Crypto.HashPassword.cs
public static string HashPassword(string password)
{
if (password == null)
{
throw new ArgumentNullException("password");
}
// Produce a version 0 (see comment above) text hash.
byte[] salt;
byte[] subkey;
using (var deriveBytes = new Rfc2898DeriveBytes(password, SaltSize, PBKDF2IterCount))
{
salt = deriveBytes.Salt;
subkey = deriveBytes.GetBytes(PBKDF2SubkeyLength);
}
var outputBytes = new byte[1 + SaltSize + PBKDF2SubkeyLength];
Buffer.BlockCopy(salt, 0, outputBytes, 1, SaltSize);
Buffer.BlockCopy(subkey, 0, outputBytes, 1 + SaltSize, PBKDF2SubkeyLength);
return Convert.ToBase64String(outputBytes);
}
Compared to v2 in aspnet identity core:
private static byte[] HashPasswordV2(string password, RandomNumberGenerator rng)
{
const KeyDerivationPrf Pbkdf2Prf = KeyDerivationPrf.HMACSHA1; // default for Rfc2898DeriveBytes
const int Pbkdf2IterCount = 1000; // default for Rfc2898DeriveBytes
const int Pbkdf2SubkeyLength = 256 / 8; // 256 bits
const int SaltSize = 128 / 8; // 128 bits
// Produce a version 2 (see comment above) text hash.
byte[] salt = new byte[SaltSize];
rng.GetBytes(salt);
byte[] subkey = KeyDerivation.Pbkdf2(password, salt, Pbkdf2Prf, Pbkdf2IterCount, Pbkdf2SubkeyLength);
var outputBytes = new byte[1 + SaltSize + Pbkdf2SubkeyLength];
outputBytes[0] = 0x00; // format marker
Buffer.BlockCopy(salt, 0, outputBytes, 1, SaltSize);
Buffer.BlockCopy(subkey, 0, outputBytes, 1 + SaltSize, Pbkdf2SubkeyLength);
return outputBytes;
}
Identity v2 hashing and identity core v2 hashing seem pretty similar, now compared to identity core v3 hash:
private static byte[] HashPasswordV3(string password, RandomNumberGenerator rng, KeyDerivationPrf prf, int iterCount, int saltSize, int numBytesRequested)
{
// Produce a version 3 (see comment above) text hash.
byte[] salt = new byte[saltSize];
rng.GetBytes(salt);
byte[] subkey = KeyDerivation.Pbkdf2(password, salt, prf, iterCount, numBytesRequested);
var outputBytes = new byte[13 + salt.Length + subkey.Length];
outputBytes[0] = 0x01; // format marker
WriteNetworkByteOrder(outputBytes, 1, (uint)prf);
WriteNetworkByteOrder(outputBytes, 5, (uint)iterCount);
WriteNetworkByteOrder(outputBytes, 9, (uint)saltSize);
Buffer.BlockCopy(salt, 0, outputBytes, 13, salt.Length);
Buffer.BlockCopy(subkey, 0, outputBytes, 13 + saltSize, subkey.Length);
return outputBytes;
}
I'm not going to pretend to understand what's going on in these methods, but from identity v2, and identity core, we went from a parameterless constructor to one that takes in configuration options. V2 uses SHA1, V3 uses SHA256 (among other things).
It looks like identity core by default would hash using V3 method, which did not exist in the older version of identity - which would be the cause of your problem.
https://github.com/aspnet/Identity/blob/a8ba99bc5b11c5c48fc31b9b0532c0d6791efdc8/src/Microsoft.AspNetCore.Identity/PasswordHasherOptions.cs
Note in the above source, V3 is used as the default.
/// <summary>
/// Gets or sets the compatibility mode used when hashing passwords.
/// </summary>
/// <value>
/// The compatibility mode used when hashing passwords.
/// </value>
/// <remarks>
/// The default compatibility mode is 'ASP.NET Identity version 3'.
/// </remarks>
public PasswordHasherCompatibilityMode CompatibilityMode { get; set; } = PasswordHasherCompatibilityMode.IdentityV3;
Unfortunately, that looks like it means your passwords that were hashed in identity core cannot be hashed the same in an older version of identity, as that older method was not implemented. Perhaps you could create your own mimicking what was done in v3?
To follow up Kritner's excellent answer with a TLDR:
TLDR if you are migrating from Microsoft.AspNet.Identity.Core to Microsoft.AspNetCore.Identity (note the subtle difference) you want to replace
// Microsoft.AspNet.Identity.Core
PasswordHasher hasher = new PasswordHasher();
with something that looks like
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
// Microsoft.AspNetCore.Identity
PasswordHasher<YourUserTypeActuallyImmaterial> hasher
= new PasswordHasher<YourUserTypeActuallyImmaterial>(
Options.Create(new PasswordHasherOptions()
{
CompatibilityMode = PasswordHasherCompatibilityMode.IdentityV2,
}));
Thereafter the difference in API is that the newer PasswordHasher<T> requires you to pass in an instance of T when hashing or verifying.
This will hash plaintext in a compatible way with the old method and will successfully verify valid passwords hashed with the previous method.

Custom membership provider in web Applications

I need to implement my own custom provider for Membership in my web application. After implementing it partially successfully, I am looking for answers on below question:
Which all function I need to override in my application
Which all classes i need to inherit from. So far I used classes: MemberShipProvider, RoleProvider.
Can the ASP.NET automatically connect to the correct table of my database. Is there any settings for this? like specifying the default table name ?
Is there any Builtin function for setting the password as Salted Hash? OR I need to implement this on my own?
the WAT Tool will be helpful for me still OR it will be limited in functionality, As i found that it may atleast help in debugging?
I found that some function i've missed to override and also I think I did same with RoleProvider also. If there is any complete list OR so.. that's bound to help me
1) Which all function I need to override in my application
You mainly need to override GetUser and ValidateUser in order for Membership Provider to work with Login Control. The rest are optional.
public class CustomMembershipProvider : MembershipProvider
{
public override MembershipUser GetUser(string username, bool userIsOnline)
{
throw new NotImplementedException();
}
public override bool ValidateUser(string username, string password)
{
throw new NotImplementedException();
}
}
2) Which all classes i need to inherit from. So far I used classes:
MemberShipProvider, RoleProvider.
MembershipProvider is a must. If you want to authorize a user by roles, you need to implement RoleProvider.
3) Can the ASP.NET automatically connect to the correct table of my
database. Is there any settings for this? like specifying the default
table name ?
The reason you are overriding Membership Provider is you want to work with custom tables that you created. You are in charged of returning data from database; Membership provider no longer requires to know the name of your tables. Therefore, the answer is No - there is no setting.
4) Is there any Builtin function for setting the password as Salted Hash?
OR I need to implement this on my own?
Here are the methods that Membership Provider uses to generate hash password -
private static string GenerateSalt()
{
byte[] numArray = new byte[16];
(new RNGCryptoServiceProvider()).GetBytes(numArray);
string base64String = Convert.ToBase64String(numArray);
return base64String;
}
private string EncodePassword(string pass, int passwordFormat, string salt)
{
byte[] numArray;
byte[] numArray1;
string base64String;
bool length = passwordFormat != 0;
if (length)
{
byte[] bytes = Encoding.Unicode.GetBytes(pass);
byte[] numArray2 = Convert.FromBase64String(salt);
byte[] numArray3 = null;
HashAlgorithm hashAlgorithm = HashAlgorithm.Create(Membership.HashAlgorithmType);
if (hashAlgorithm as KeyedHashAlgorithm == null)
{
numArray1 = new byte[(int) numArray2.Length + (int) bytes.Length];
Buffer.BlockCopy(numArray2, 0, numArray1, 0, (int) numArray2.Length);
Buffer.BlockCopy(bytes, 0, numArray1, (int) numArray2.Length, (int) bytes.Length);
numArray3 = hashAlgorithm.ComputeHash(numArray1);
}
else
{
KeyedHashAlgorithm keyedHashAlgorithm = (KeyedHashAlgorithm) hashAlgorithm;
if (keyedHashAlgorithm.Key.Length != numArray2.Length)
{
if (keyedHashAlgorithm.Key.Length >= (int) numArray2.Length)
{
numArray = new byte[(int) keyedHashAlgorithm.Key.Length];
int num = 0;
while (true)
{
length = num < (int) numArray.Length;
if (!length)
{
break;
}
int num1 = Math.Min((int) numArray2.Length, (int) numArray.Length - num);
Buffer.BlockCopy(numArray2, 0, numArray, num, num1);
num = num + num1;
}
keyedHashAlgorithm.Key = numArray;
}
else
{
numArray = new byte[(int) keyedHashAlgorithm.Key.Length];
Buffer.BlockCopy(numArray2, 0, numArray, 0, (int) numArray.Length);
keyedHashAlgorithm.Key = numArray;
}
}
else
{
keyedHashAlgorithm.Key = numArray2;
}
numArray3 = keyedHashAlgorithm.ComputeHash(bytes);
}
base64String = Convert.ToBase64String(numArray3);
}
else
{
base64String = pass;
}
return base64String;
}
5) the WAT Tool will be helpful for me still OR it will be limited in
functionality, As i found that it may atleast help in debugging?
Yes, you can still use website administration tool, but it depends on those methods that you override.
For example, if you do not override role provider, assigning a user to a role won't work.
http://www.asp.net/general/videos/how-do-i-create-a-custom-membership-provider
http://www.davidhayden.com/blog/dave/archive/2007/10/11/CreateCustomMembershipProviderASPNETWebsiteSecurity.aspx
http://www.shiningstar.net/aspnet_articles/customprovider/CustomProvider.aspx
http://www.devx.com/asp/Article/29256/0/page/3
http://www.15seconds.com/issue/050216.htm
http://www.codeproject.com/KB/aspnet/CustomMembershipProviders.aspx
http://www.codeproject.com/KB/aspnet/WSSecurityProvider.aspx

Padding is invalid and cannot be removed with Rijndael decryption

I am seeing the "Padding is invalid and cannot be removed" error when I call the method below to decrypt the string from a windows application. String was encrypted from an asp.net application. Both application references the same assembly. I am able encrypt and decrypt with out any problem from the asp.net application. Here is the main code where I do the encryption and decryption.
private static byte[] EncryptHelper(byte[] arrData, string Password, bool Encrypt)
{
//Create the SymetricAlgorithem object
SymmetricAlgorithm myAlg = new RijndaelManaged();
//define a salt value to derive the key.
byte[] salt = System.Text.Encoding.ASCII.GetBytes("hjkhj877ffasah");
//Instantiate Rfc2898DeriveBytes with the password and salt.
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(Password, salt);
myAlg.Key = key.GetBytes(myAlg.KeySize / 8);
myAlg.IV = key.GetBytes(myAlg.BlockSize / 8);
myAlg.Padding = PaddingMode.PKCS7;
//Create the ICryptoTransform Object
ICryptoTransform encrytptor = Encrypt ? myAlg.CreateEncryptor() : myAlg.CreateDecryptor();
//Create Memorystream to write the encrypted data
using (MemoryStream aStream = new MemoryStream())
{
//Create the CryptoStream Ojbect using the aStream object
using (CryptoStream encryptStream = new CryptoStream(aStream, encrytptor, CryptoStreamMode.Write))
{
//Write the contents to crypto stream
encryptStream.Write(arrData, 0, arrData.Length);
//Flush the cryptostream
encryptStream.FlushFinalBlock();
//Reposition the memorystream to write the contents to an array.
aStream.Position = 0;
}
aStream.Flush();
//Convert to an array and return
return aStream.ToArray();
}
}
This is the method I use to convert the plain text from/to byte array
private static byte[] GetBytes(string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
private static string GetString(byte[] bytes)
{
char[] chars = new char[bytes.Length / sizeof(char)];
System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
return new string(chars);
}
For persist the cipher text to database I use Convert.ToBase64String() and Convert.FromBase64String. Is the problem is with the way I use Rfc2898DeriveBytes class?
Well I think it's important to mention that from a security perspective, you are going to have the same IV for every message with the same password, and a predictable IV is a really big no no.
After that point I kinda don't want to look at it more to see what's going wrong, there are a lot of really bad cut and paste C# encryption on stackoverflow, and they just sit there with no mechanism for update, no one looking at them again except for people finding them to cut and paste again.
Look at Modern Examples of Symmetric Authenticated Encryption of a string. c#.
I try to keep it up to date and reviewed.

Re-inventing my authentication strategy with ASP.NET

Currently, I use custom written authentication code for my site, which is built on .NET. I didn't take the standard Forms Auth route, as all the examples I could find were tightly integrated with WebForms, which I do not use. For all intents and purposes, I have all static HTML, and any logic is done through Javascript and web service calls. Things like logging in, logging off, and creating a new account are done without even leaving the page.
Here's how it works now: In the database, I have a User ID, a Security ID, and a Session ID. All three are UUIDs, and the first two never change. Each time the user logs on, I check the user table for a row that matches that username and hashed password, and I update the Session ID to a new UUID. I then create a cookie that's a serialized representation of all three UUIDs. In any secure web service calls, I deserialize that cookie that make sure there's a row in the users table with those 3 UUIDs. It's a fairly simple system and works well, however I don't really like the fact that a user can only be logged on with one client at a time. It's going to cause issues when I create mobile and tablet apps, and already creates issues if they have multiple computers or web browsers. For this reason, I'm thinking about throwing away this system and going with something new. Since I wrote it years ago, I figure there might be something much more recommended.
I've been reading up on the FormsAuthentication class in the .NET Framework, which handles auth cookies, and runs as an HttpModule to validate each request. I'm wondering if I can take advantage of this in my new design.
It looks like cookies are stateless, and sessions don't have to be tracked within the database. This is done through the fact that cookies are encrypted with a private key on the server, that can also be shared across a cluster of web servers. If I do something like:
FormsAuthentication.SetAuthCookie("Bob", true);
Then in later requests, I can be assured that Bob is indeed a valid user as a cookie would be very difficult if not impossible to forge.
Would I be wise to use the FormsAuthentication class to replace my current authentication model with? Rather than have a Session ID column in the database, I'd rely on encrypted cookies to represent valid sessions.
Are there third party/open source .NET authentication frameworks that might work better for my architecture?
Will this authentication mechanism cause any grief with code running on mobile and tablet clients, such as an iPhone app or Windows 8 Surface app? I would assume this would work, as long as these apps could handle cookies. Thanks!
Since I didn't get any responses, I decided to take a shot at this myself. First, I found an open source project that implements session cookies in an algorithm agnostic way. I used this as a starting point to implement a similar handler.
One issue I had with the built in ASP.NET implementation, which is a similar restriction in the AppHarbor implementation, is sessions are only keyed by a string username. I wanted to be able to store arbitrary data to identify a user, such as their UUID in the database as well as their logon name. As much of my existing code assumes this data is available in the cookie, it would take a lot of refactoring if this data were no longer available. Plus, I like the idea of being able to store basic user information without having to hit the database.
Another issue with the AppHarbor project, as pointed out in the this open issue, is the encryption algorithm isn't verified. This is not exactly true, as AppHarbor is algorithm agnostic, however it was requested that the sample project should show how to use PBKDF2. For that reason, I decided to use this algorithm (implemented in the .NET Framework through the Rfc2898DeriveBytes class) in my code.
Here's what I was able to come up with. It's meant as a starting point for someone looking to implement their own session management, so feel free to use it for whatever purpose you see fit.
using System;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security;
using System.Security.Cryptography;
using System.Security.Principal;
using System.Web;
namespace AuthTest
{
[Serializable]
public class AuthIdentity : IIdentity
{
public Guid Id { get; private set; }
public string Name { get; private set; }
public AuthIdentity() { }
public AuthIdentity(Guid id, string name)
{
Id = id;
Name = name;
}
public string AuthenticationType
{
get { return "CookieAuth"; }
}
public bool IsAuthenticated
{
get { return Id != Guid.Empty; }
}
}
[Serializable]
public class AuthToken : IPrincipal
{
public IIdentity Identity { get; set; }
public bool IsInRole(string role)
{
return false;
}
}
public class AuthModule : IHttpModule
{
static string COOKIE_NAME = "AuthCookie";
//Note: Change these two keys to something else (VALIDATION_KEY is 72 bytes, ENCRYPTION_KEY is 64 bytes)
static string VALIDATION_KEY = #"MkMvk1JL/ghytaERtl6A25iTf/ABC2MgPsFlEbASJ5SX4DiqnDN3CjV7HXQI0GBOGyA8nHjSVaAJXNEqrKmOMg==";
static string ENCRYPTION_KEY = #"QQJYW8ditkzaUFppCJj+DcCTc/H9TpnSRQrLGBQkhy/jnYjqF8iR6do9NvI8PL8MmniFvdc21sTuKkw94jxID4cDYoqr7JDj";
static byte[] key;
static byte[] iv;
static byte[] valKey;
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.AuthenticateRequest += OnAuthenticateRequest;
context.EndRequest += OnEndRequest;
byte[] bytes = Convert.FromBase64String(ENCRYPTION_KEY); //72 bytes (8 for salt, 64 for key)
byte[] salt = bytes.Take(8).ToArray();
byte[] pw = bytes.Skip(8).ToArray();
Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes(pw, salt, 1000);
key = k1.GetBytes(16);
iv = k1.GetBytes(8);
valKey = Convert.FromBase64String(VALIDATION_KEY); //64 byte validation key to prevent tampering
}
public static void SetCookie(AuthIdentity token, bool rememberMe = false)
{
//Base64 encode token
var formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
formatter.Serialize(stream, token);
byte[] buffer = stream.GetBuffer();
byte[] encryptedBytes = EncryptCookie(buffer);
string str = Convert.ToBase64String(encryptedBytes);
var cookie = new HttpCookie(COOKIE_NAME, str);
cookie.HttpOnly = true;
if (rememberMe)
{
cookie.Expires = DateTime.Today.AddDays(100);
}
HttpContext.Current.Response.Cookies.Add(cookie);
}
public static void Logout()
{
HttpContext.Current.Response.Cookies.Remove(COOKIE_NAME);
HttpContext.Current.Response.Cookies.Add(new HttpCookie(COOKIE_NAME, "")
{
Expires = DateTime.Today.AddDays(-1)
});
}
private static byte[] EncryptCookie(byte[] rawBytes)
{
TripleDES des = TripleDES.Create();
des.Key = key;
des.IV = iv;
MemoryStream encryptionStream = new MemoryStream();
CryptoStream encrypt = new CryptoStream(encryptionStream, des.CreateEncryptor(), CryptoStreamMode.Write);
encrypt.Write(rawBytes, 0, rawBytes.Length);
encrypt.FlushFinalBlock();
encrypt.Close();
byte[] encBytes = encryptionStream.ToArray();
//Add validation hash (compute hash on unencrypted data)
HMACSHA256 hmac = new HMACSHA256(valKey);
byte[] hash = hmac.ComputeHash(rawBytes);
//Combine encrypted bytes and validation hash
byte[] ret = encBytes.Concat<byte>(hash).ToArray();
return ret;
}
private static byte[] DecryptCookie(byte[] encBytes)
{
TripleDES des = TripleDES.Create();
des.Key = key;
des.IV = iv;
HMACSHA256 hmac = new HMACSHA256(valKey);
int valSize = hmac.HashSize / 8;
int msgLength = encBytes.Length - valSize;
byte[] message = new byte[msgLength];
byte[] valBytes = new byte[valSize];
Buffer.BlockCopy(encBytes, 0, message, 0, msgLength);
Buffer.BlockCopy(encBytes, msgLength, valBytes, 0, valSize);
MemoryStream decryptionStreamBacking = new MemoryStream();
CryptoStream decrypt = new CryptoStream(decryptionStreamBacking, des.CreateDecryptor(), CryptoStreamMode.Write);
decrypt.Write(message, 0, msgLength);
decrypt.Flush();
byte[] decMessage = decryptionStreamBacking.ToArray();
//Verify key matches
byte[] hash = hmac.ComputeHash(decMessage);
if (valBytes.SequenceEqual(hash))
{
return decMessage;
}
throw new SecurityException("Auth Cookie appears to have been tampered with!");
}
private void OnAuthenticateRequest(object sender, EventArgs e)
{
var context = ((HttpApplication)sender).Context;
var cookie = context.Request.Cookies[COOKIE_NAME];
if (cookie != null && cookie.Value.Length > 0)
{
try
{
var formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
var bytes = Convert.FromBase64String(cookie.Value);
var decBytes = DecryptCookie(bytes);
stream.Write(decBytes, 0, decBytes.Length);
stream.Seek(0, SeekOrigin.Begin);
AuthIdentity auth = formatter.Deserialize(stream) as AuthIdentity;
AuthToken token = new AuthToken() { Identity = auth };
context.User = token;
//Renew the cookie for another 100 days (TODO: Should only renew if cookie was originally set to persist)
context.Response.Cookies[COOKIE_NAME].Value = cookie.Value;
context.Response.Cookies[COOKIE_NAME].Expires = DateTime.Today.AddDays(100);
}
catch { } //Ignore any errors with bad cookies
}
}
private void OnEndRequest(object sender, EventArgs e)
{
var context = ((HttpApplication)sender).Context;
var response = context.Response;
if (response.Cookies.Keys.Cast<string>().Contains(COOKIE_NAME))
{
response.Cache.SetCacheability(HttpCacheability.NoCache, "Set-Cookie");
}
}
}
}
Also, be sure to include the following module in your web.config file:
<httpModules>
<add name="AuthModule" type="AuthTest.AuthModule" />
</httpModules>
In your code, you can lookup the currently logged on user with:
var id = HttpContext.Current.User.Identity as AuthIdentity;
And set the auth cookie like so:
AuthIdentity token = new AuthIdentity(Guid.NewGuid(), "Mike");
AuthModule.SetCookie(token, false);

how to reset & change the hash password in asp.net membership provider in MVC

I came accross the code :
MembershipUser u = Membership.GetUser();
u.ChangePassword(u.ResetPassword(), "Password"); //where will I get the "Password" from
I dont understand how I will
get the client password as the user has forgotten his old password.
I want to add a reset functionality which would generate a random password and
send an email to the particular client which will have the userid and the random generated password. After he/she would be able to change the password.
You can generate a random password like this using the Membership GeneratePassword method
string password = System.Web.Security.Membership.GeneratePassword(14, 0);
If you need to create your own salt and hash a new password, here is an implementation which does much the same as the membership code:
public class Cryptographer : ICryptographer
{
#region ICryptographer Members
public string CreateSalt()
{
byte[] data = new byte[0x10];
new RNGCryptoServiceProvider().GetBytes(data);
return Convert.ToBase64String(data);
}
/// <summary>
/// Hash the password against the salt
/// </summary>
/// <param name="pass">Plain password</param>
/// <param name="salt">Salt string</param>
/// <returns>Encrypted password</returns>
public string HashPassword(string password, string salt)
{
byte[] bytes = Encoding.Unicode.GetBytes(password);
byte[] src = Convert.FromBase64String(salt);
byte[] dst = new byte[src.Length + bytes.Length];
byte[] inArray = null;
Buffer.BlockCopy(src, 0, dst, 0, src.Length);
Buffer.BlockCopy(bytes, 0, dst, src.Length, bytes.Length);
HashAlgorithm algorithm = HashAlgorithm.Create(System.Web.Security.Membership.HashAlgorithmType);
inArray = algorithm.ComputeHash(dst);
return Convert.ToBase64String(inArray);
}
#endregion
}
The second paremeter of the ChangePassword method is a string that reprisents the new password you'd like to use for that user.
You can change this to be any string you want, even an auto generated string that you'll email to the user.
UPDATE
To answer your new question, I believe that all hashing of the password etc is handled by the Membership Provider.
If you simply want to reset the users password to a random new value, you might be better using the ResetPassword method instead of ChangePassword.
This will:
Resets a user's password to a new, automatically generated password.

Resources