Files
MileageTraker/Web/Membership/CodeFirstMembershipProvider.cs
T

534 lines
14 KiB
C#

using System;
using System.Data.SqlTypes;
using System.Linq;
using System.Security.Cryptography;
using System.Web;
using System.Web.Security;
using MileageTraker.Web.Context;
using MileageTraker.Web.Models;
namespace MileageTraker.Web.Membership
{
public class CodeFirstMembershipProvider : MembershipProvider
{
#region Properties
private const int TokenSizeInBytes = 16;
public override string ApplicationName
{
get { return GetType().Assembly.GetName().Name; }
set
{
if (value == null) throw new ArgumentNullException("value");
ApplicationName = GetType().Assembly.GetName().Name;
}
}
public override int MaxInvalidPasswordAttempts
{
get { return 5; }
}
public override int MinRequiredNonAlphanumericCharacters
{
get { return 0; }
}
public override int MinRequiredPasswordLength
{
get { return 6; }
}
public override int PasswordAttemptWindow
{
get { return 0; }
}
public override MembershipPasswordFormat PasswordFormat
{
get { return MembershipPasswordFormat.Hashed; }
}
public override string PasswordStrengthRegularExpression
{
get { return String.Empty; }
}
public override bool RequiresUniqueEmail
{
get { return true; }
}
#endregion
#region Functions
public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion,
string passwordAnswer, bool isApproved, object providerUserKey,
out MembershipCreateStatus status)
{
if (string.IsNullOrEmpty(username))
{
status = MembershipCreateStatus.InvalidUserName;
return null;
}
if (string.IsNullOrEmpty(password))
{
status = MembershipCreateStatus.InvalidPassword;
return null;
}
if (string.IsNullOrEmpty(email))
{
status = MembershipCreateStatus.InvalidEmail;
return null;
}
var hashedPassword = Crypto.HashPassword(password);
if (hashedPassword.Length > 128)
{
status = MembershipCreateStatus.InvalidPassword;
return null;
}
using (var context = new MileageTrakerContext())
{
if (context.Users.Any(usr => usr.Username == username))
{
status = MembershipCreateStatus.DuplicateUserName;
return null;
}
if (context.Users.Any(usr => usr.Email == email))
{
status = MembershipCreateStatus.DuplicateEmail;
return null;
}
var newUser = new User
{
UserId = Guid.NewGuid(),
Username = username,
Password = hashedPassword,
IsApproved = isApproved,
Email = email,
CreateDate = DateTime.UtcNow,
LastPasswordChangedDate = DateTime.UtcNow,
PasswordFailuresSinceLastSuccess = 0,
LastLoginDate = DateTime.UtcNow,
LastActivityDate = DateTime.UtcNow,
LastLockoutDate = SqlDateTime.MinValue.Value,
IsLockedOut = false,
LastPasswordFailureDate = SqlDateTime.MinValue.Value
};
context.Users.Add(newUser);
context.SaveChanges();
status = MembershipCreateStatus.Success;
return newUser.CloneToMembershipUser(System.Web.Security.Membership.Provider.Name);
}
}
public string CreateUserAndAccount(string userName, string password, bool requireConfirmation)
{
return CreateAccount(userName, password, requireConfirmation);
}
public override bool ValidateUser(string username, string password)
{
if (string.IsNullOrEmpty(username))
{
return false;
}
if (string.IsNullOrEmpty(password))
{
return false;
}
using (var context = new MileageTrakerContext())
{
User user = context.Users.FirstOrDefault(usr => usr.Username == username);
if (user == null)
{
return false;
}
if (!user.IsApproved)
{
return false;
}
if (user.IsLockedOut)
{
return false;
}
var hashedPassword = user.Password;
var verificationSucceeded = (hashedPassword != null && Crypto.VerifyHashedPassword(hashedPassword, password));
if (verificationSucceeded)
{
user.PasswordFailuresSinceLastSuccess = 0;
user.LastLoginDate = DateTime.UtcNow;
user.LastActivityDate = DateTime.UtcNow;
}
else
{
var failures = user.PasswordFailuresSinceLastSuccess;
if (failures < MaxInvalidPasswordAttempts)
{
user.PasswordFailuresSinceLastSuccess += 1;
user.LastPasswordFailureDate = DateTime.UtcNow;
}
else if (failures >= MaxInvalidPasswordAttempts)
{
user.LastPasswordFailureDate = DateTime.UtcNow;
user.LastLockoutDate = DateTime.UtcNow;
user.IsLockedOut = true;
}
}
context.SaveChanges();
return verificationSucceeded;
}
}
public override MembershipUser GetUser(string username, bool userIsOnline)
{
if (string.IsNullOrEmpty(username))
{
return null;
}
using (var context = new MileageTrakerContext())
{
var user = context.Users.FirstOrDefault(usr => usr.Username == username);
if (user == null)
{
return null;
}
if (userIsOnline)
{
user.LastActivityDate = DateTime.UtcNow;
context.SaveChanges();
}
return user.CloneToMembershipUser(System.Web.Security.Membership.Provider.Name);
}
}
public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
{
if (providerUserKey is Guid)
{
}
else
{
return null;
}
using (var context = new MileageTrakerContext())
{
var user = context.Users.Find(providerUserKey);
if (user == null)
{
return null;
}
if (userIsOnline)
{
user.LastActivityDate = DateTime.UtcNow;
context.SaveChanges();
}
return user.CloneToMembershipUser(System.Web.Security.Membership.Provider.Name);
}
}
public override bool ChangePassword(string username, string oldPassword, string newPassword)
{
if (string.IsNullOrEmpty(username))
{
return false;
}
if (string.IsNullOrEmpty(oldPassword))
{
return false;
}
if (string.IsNullOrEmpty(newPassword))
{
return false;
}
using (var context = new MileageTrakerContext())
{
User user = context.Users.FirstOrDefault(usr => usr.Username == username);
if (user == null)
{
return false;
}
var hashedPassword = user.Password;
var verificationSucceeded = (hashedPassword != null && Crypto.VerifyHashedPassword(hashedPassword, oldPassword));
if (verificationSucceeded)
{
user.PasswordFailuresSinceLastSuccess = 0;
}
else
{
var failures = user.PasswordFailuresSinceLastSuccess;
if (failures < MaxInvalidPasswordAttempts)
{
user.PasswordFailuresSinceLastSuccess += 1;
user.LastPasswordFailureDate = DateTime.UtcNow;
}
else if (failures >= MaxInvalidPasswordAttempts)
{
user.LastPasswordFailureDate = DateTime.UtcNow;
user.LastLockoutDate = DateTime.UtcNow;
user.IsLockedOut = true;
}
context.SaveChanges();
return false;
}
var newHashedPassword = Crypto.HashPassword(newPassword);
if (newHashedPassword.Length > 128)
{
return false;
}
user.Password = newHashedPassword;
user.LastPasswordChangedDate = DateTime.UtcNow;
context.SaveChanges();
return true;
}
}
public override bool UnlockUser(string userName)
{
using (var context = new MileageTrakerContext())
{
var user = context.Users.FirstOrDefault(usr => usr.Username == userName);
if (user != null)
{
user.IsLockedOut = false;
user.PasswordFailuresSinceLastSuccess = 0;
context.SaveChanges();
return true;
}
return false;
}
}
public override int GetNumberOfUsersOnline()
{
var dateActive =
DateTime.UtcNow.Subtract(
TimeSpan.FromMinutes(
Convert.ToDouble(
System.Web.Security.Membership.UserIsOnlineTimeWindow)));
using (var context = new MileageTrakerContext())
{
return context.Users.Count(usr => usr.LastActivityDate > dateActive);
}
}
public override bool DeleteUser(string username, bool deleteAllRelatedData)
{
if (string.IsNullOrEmpty(username))
{
return false;
}
using (var context = new MileageTrakerContext())
{
var user = context.Users.FirstOrDefault(usr => usr.Username == username);
if (user != null)
{
context.Users.Remove(user);
context.SaveChanges();
return true;
}
return false;
}
}
public override string GetUserNameByEmail(string email)
{
using (var context = new MileageTrakerContext())
{
var user = context.Users.FirstOrDefault(usr => usr.Email == email);
if (user != null)
{
return user.Username;
}
return string.Empty;
}
}
public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize,
out int totalRecords)
{
var membershipUsers = new MembershipUserCollection();
using (var context = new MileageTrakerContext())
{
totalRecords = context.Users.Count(Usr => Usr.Email == emailToMatch);
var users =
context.Users.Where(usr => usr.Email == emailToMatch)
.OrderBy(usrn => usrn.Username)
.Skip(pageIndex*pageSize)
.Take(pageSize);
foreach (var user in users)
{
membershipUsers.Add(
user.CloneToMembershipUser(System.Web.Security.Membership.Provider.Name));
}
}
return membershipUsers;
}
public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize,
out int totalRecords)
{
var membershipUsers = new MembershipUserCollection();
using (var context = new MileageTrakerContext())
{
totalRecords = context.Users.Count(Usr => Usr.Username == usernameToMatch);
var users =
context.Users.Where(usr => usr.Username == usernameToMatch)
.OrderBy(usrn => usrn.Username)
.Skip(pageIndex*pageSize)
.Take(pageSize);
foreach (var user in users)
{
membershipUsers.Add(user.CloneToMembershipUser(System.Web.Security.Membership.Provider.Name));
}
}
return membershipUsers;
}
public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
{
var membershipUsers = new MembershipUserCollection();
using (var context = new MileageTrakerContext())
{
totalRecords = context.Users.Count();
var users =
context.Users
.OrderBy(usrn => usrn.Username)
.Skip(pageIndex*pageSize)
.Take(pageSize);
foreach (var user in users)
{
membershipUsers.Add(user.CloneToMembershipUser(System.Web.Security.Membership.Provider.Name));
}
}
return membershipUsers;
}
public string CreateAccount(string userName, string password, bool requireConfirmationToken)
{
if (string.IsNullOrEmpty(userName))
{
throw new MembershipCreateUserException(MembershipCreateStatus.InvalidUserName);
}
if (string.IsNullOrEmpty(password))
{
throw new MembershipCreateUserException(MembershipCreateStatus.InvalidPassword);
}
var hashedPassword = Crypto.HashPassword(password);
if (hashedPassword.Length > 128)
{
throw new MembershipCreateUserException(MembershipCreateStatus.InvalidPassword);
}
using (var context = new MileageTrakerContext())
{
if (context.Users.Any(usr => usr.Username == userName))
{
throw new MembershipCreateUserException(MembershipCreateStatus.DuplicateUserName);
}
var token = string.Empty;
if (requireConfirmationToken)
{
token = GenerateToken();
}
var newUser = new User
{
UserId = Guid.NewGuid(),
Username = userName,
Password = hashedPassword,
IsApproved = !requireConfirmationToken,
Email = string.Empty,
CreateDate = DateTime.UtcNow,
LastPasswordChangedDate = DateTime.UtcNow,
PasswordFailuresSinceLastSuccess = 0,
LastLoginDate = DateTime.UtcNow,
LastActivityDate = DateTime.UtcNow,
LastLockoutDate = SqlDateTime.MinValue.Value,
IsLockedOut = false,
LastPasswordFailureDate = SqlDateTime.MinValue.Value,
ConfirmationToken = token
};
context.Users.Add(newUser);
context.SaveChanges();
return token;
}
}
private static string GenerateToken()
{
using (var prng = new RNGCryptoServiceProvider())
{
return GenerateToken(prng);
}
}
private static string GenerateToken(RandomNumberGenerator generator)
{
var tokenBytes = new byte[TokenSizeInBytes];
generator.GetBytes(tokenBytes);
return HttpServerUtility.UrlTokenEncode(tokenBytes);
}
#endregion
#region Not Supported
//CodeFirstMembershipProvider does not support password retrieval scenarios.
public override bool EnablePasswordRetrieval
{
get { return false; }
}
//CodeFirstMembershipProvider does not support password reset scenarios.
public override bool EnablePasswordReset
{
get { return false; }
}
//CodeFirstMembershipProvider does not support question and answer scenarios.
public override bool RequiresQuestionAndAnswer
{
get { return false; }
}
public override string GetPassword(string username, string answer)
{
throw new NotSupportedException("Consider using methods from WebSecurity module.");
}
public override string ResetPassword(string username, string answer)
{
throw new NotSupportedException("Consider using methods from WebSecurity module.");
}
public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion,
string newPasswordAnswer)
{
throw new NotSupportedException("Consider using methods from WebSecurity module.");
}
//CodeFirstMembershipProvider does not support UpdateUser because this method is useless.
public override void UpdateUser(MembershipUser user)
{
throw new NotSupportedException();
}
#endregion
}
}