Demo User repository (sample!)
ASP has had several user systems for Forms Authentication since .net 2, from the overcomplicated Membership Provider to the underpowered Identity. This repository is just a simple sample with no backing store. It demonstrates very simple security including hashing passwords, and counting login attempts, without being too complicated. Have a look at Membership Reboot for a better membership system.
User class
public class User
{
public User()
{
RolesList = new List<string>();
}
public string Name { get; set; }
public IList<string> RolesList { get; set; }
public string PasswordHash { get; set; }
public string PasswordSalt { get; set; }
public int PasswordFailuresSinceLastSuccess { get; set; }
public DateTime? LastPasswordFailureDate { get; set; }
}
UserRepository
public class UserRepository
{
public User FindUser(string userName, string password)
{
var user = LoadUser(userName);
#if DEBUG
//for testing, null passwords are the actual password
if (user.PasswordHash == null)
{
ResetPassword(user, password);
}
#endif
//allow one try per hour
if (user.PasswordFailuresSinceLastSuccess >= 5 &&
((DateTime.UtcNow - user.LastPasswordFailureDate) < TimeSpan.FromHours(1)))
{
Trace.TraceWarning("Locked out: " + userName);
return null;
}
var hashedPass = EncodePassword(password, user.PasswordSalt);
if (user.PasswordHash != hashedPass)
{
Trace.TraceWarning("Password failure " + userName);
user.LastPasswordFailureDate = DateTime.UtcNow;
user.PasswordFailuresSinceLastSuccess++;
//save it!
return null;
}
if (user.PasswordFailuresSinceLastSuccess > 0)
{
user.PasswordFailuresSinceLastSuccess = 0;
//save it!
}
return user;
}
private User LoadUser(string userName)
{
//should hit database
var user = new User { Name = userName };
user.RolesList.Add("Admin");
user.PasswordSalt = GenerateSalt();
return user;
}
public void ResetPassword(User user, string password)
{
if (string.IsNullOrEmpty(user.PasswordSalt))
user.PasswordSalt = GenerateSalt();
user.PasswordFailuresSinceLastSuccess = 0;
user.LastPasswordFailureDate = null;
user.PasswordHash = EncodePassword(password, user.PasswordSalt);
}
private static string EncodePassword(string pass, string salt)
{
var bytes = Encoding.Unicode.GetBytes(pass);
var src = Convert.FromBase64String(salt);
var dst = new byte[src.Length + bytes.Length];
Buffer.BlockCopy(src, 0, dst, 0, src.Length);
Buffer.BlockCopy(bytes, 0, dst, src.Length, bytes.Length);
var algorithm = System.Security.Cryptography.
HashAlgorithm.Create("SHA256");//"SHA" or "SHA256"
var inArray = algorithm.ComputeHash(dst);
return Convert.ToBase64String(inArray);
}
private static string GenerateSalt()
{
var buf = new byte[16];
(new System.Security.Cryptography.
RNGCryptoServiceProvider()).GetBytes(buf);
return Convert.ToBase64String(buf);
}
}