using System; using System.Linq; using System.Web.Security; using MileageTraker.Web.Models; using MileageTraker.Web.Utility; namespace MileageTraker.Web.DAL { public class CodeFirstMembershipProvider : MembershipProvider { #region Properties 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 DataService()) { if (context.FindUserByUsername(username) != null) { status = MembershipCreateStatus.DuplicateUserName; return null; } if (context.FindUserByUsername(email) != null) { status = MembershipCreateStatus.DuplicateEmail; return null; } var newUser = new User { UserId = Guid.NewGuid(), Username = username, Password = hashedPassword, IsApproved = isApproved, Email = email, Created = DateTime.Now, FullName = "Temp Name" }; context.AddUser(newUser); status = MembershipCreateStatus.Success; return newUser.ToMembershipUser(Membership.Provider.Name); } } public override bool ValidateUser(string username, string password) { if (string.IsNullOrEmpty(username)) { return false; } if (string.IsNullOrEmpty(password)) { return false; } using (var context = new DataService()) { var user = context.FindUserByUsername(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.Now; user.LastActivityDate = DateTime.Now; } else { var failures = user.PasswordFailuresSinceLastSuccess; if (failures < MaxInvalidPasswordAttempts) { user.PasswordFailuresSinceLastSuccess += 1; user.LastPasswordFailureDate = DateTime.Now; } else if (failures >= MaxInvalidPasswordAttempts) { user.LastPasswordFailureDate = DateTime.Now; user.LastLockoutDate = DateTime.Now; user.IsLockedOut = true; } } context.UpdateUser(user); return verificationSucceeded; } } public override MembershipUser GetUser(string username, bool userIsOnline) { if (string.IsNullOrEmpty(username)) { return null; } using (var context = new DataService()) { var user = context.FindUserByUsername(username); if (user == null) { return null; } if (userIsOnline) { user.LastActivityDate = DateTime.Now; context.UpdateUser(user); } return user.ToMembershipUser(System.Web.Security.Membership.Provider.Name); } } public override MembershipUser GetUser(object providerUserKey, bool userIsOnline) { if (!(providerUserKey is Guid)) { return null; } using (var context = new DataService()) { var user = context.GetUser((Guid)providerUserKey); if (user == null) { return null; } if (userIsOnline) { user.LastActivityDate = DateTime.Now; context.UpdateUser(user); } return user.ToMembershipUser(System.Web.Security.Membership.Provider.Name); } } public override bool ChangePassword(string username, string currentPassword, string newPassword) { if (string.IsNullOrEmpty(username)) { return false; } if (string.IsNullOrEmpty(currentPassword)) { return false; } if (string.IsNullOrEmpty(newPassword)) { return false; } using (var context = new DataService()) { var user = context.FindUserByUsername(username); if (user == null) { return false; } var hashedPassword = user.Password; var verificationSucceeded = (hashedPassword != null && Crypto.VerifyHashedPassword(hashedPassword, currentPassword)); if (verificationSucceeded) { user.PasswordFailuresSinceLastSuccess = 0; } else { var failures = user.PasswordFailuresSinceLastSuccess; if (failures < MaxInvalidPasswordAttempts) { user.PasswordFailuresSinceLastSuccess += 1; user.LastPasswordFailureDate = DateTime.Now; } else if (failures >= MaxInvalidPasswordAttempts) { user.LastPasswordFailureDate = DateTime.Now; user.LastLockoutDate = DateTime.Now; user.IsLockedOut = true; } context.UpdateUser(user); return false; } var newHashedPassword = Crypto.HashPassword(newPassword); if (newHashedPassword.Length > 128) { return false; } user.Password = newHashedPassword; user.LastPasswordChangedDate = DateTime.Now; context.UpdateUser(user); return true; } } public override bool UnlockUser(string userName) { using (var context = new DataService()) { var user = context.FindUserByUsername(userName); if (user != null) { user.IsLockedOut = false; user.PasswordFailuresSinceLastSuccess = 0; context.UpdateUser(user); return true; } return false; } } public override int GetNumberOfUsersOnline() { var dateActive = CustomExtensions.UserOnlineThreshold(); using (var context = new DataService()) { return context.GetUsers().Count(usr => usr.LastActivityDate > dateActive); } } public override bool DeleteUser(string username, bool deleteAllRelatedData) { throw new NotSupportedException(); } public override string GetUserNameByEmail(string email) { using (var context = new DataService()) { var user = context.FindUserByEmail(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 DataService()) { totalRecords = context.GetUsers().Count(user => user.Email == emailToMatch); var users = context.GetUsers().Where(usr => usr.Email == emailToMatch) .OrderBy(usrn => usrn.Username) .Skip(pageIndex*pageSize) .Take(pageSize); foreach (var user in users) { membershipUsers.Add( user.ToMembershipUser(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 DataService()) { totalRecords = context.GetUsers().Count(usr => usr.Username == usernameToMatch); var users = context.GetUsers().Where(usr => usr.Username == usernameToMatch) .OrderBy(usrn => usrn.Username) .Skip(pageIndex*pageSize) .Take(pageSize); foreach (var user in users) { membershipUsers.Add(user.ToMembershipUser(Membership.Provider.Name)); } } return membershipUsers; } public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords) { var membershipUsers = new MembershipUserCollection(); using (var context = new DataService()) { totalRecords = context.GetUsers().Count(); var users = context.GetUsers() .OrderBy(usrn => usrn.Username) .Skip(pageIndex*pageSize) .Take(pageSize); foreach (var user in users) { membershipUsers.Add(user.ToMembershipUser(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 = Algorithms.GenerateToken(); // } // var newUser = new User // { // UserId = Guid.NewGuid(), // Username = userName, // Password = hashedPassword, // IsApproved = !requireConfirmationToken, // Email = string.Empty, // Created = DateTime.Now, // LastPasswordChangedDate = DateTime.Now, // PasswordFailuresSinceLastSuccess = 0, // LastLoginDate = SqlDateTime.MinValue.Value, // LastActivityDate = SqlDateTime.MinValue.Value, // LastLockoutDate = SqlDateTime.MinValue.Value, // IsLockedOut = false, // LastPasswordFailureDate = SqlDateTime.MinValue.Value // }; // context.Users.Add(newUser); // context.SaveChanges(); // return token; // } //} #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 } }