public virtual ActionResult ChangePassword(ChangePasswordViewModel model) { if (ModelState.IsValid) { var result = new ExecutionResults(); var user = new User { UserID = SecurityContextManager.CurrentIdentity.Ticket.UserSession.UserID, Name = model.UserName, PasswordHash = model.ConfirmPassword }; if (UserManager.UpdateUser(user, model.OldPassword, Request.UserHostAddress, result)) { //success if (this.IsJsonRequest()) return Json(new { success = true }); return RedirectToAction(MVC.Account.ChangePasswordSuccess()); } //failed business layer rules if (this.IsJsonRequest()) return Json(new { success = false, message = result.ToHtmlString() }); for (int e = 0; e < result.Messages.Count; e++) { ModelState.AddModelError(e.ToString(CultureInfo.InvariantCulture), result.Messages[e].Message); } return View(model); } if (this.IsJsonRequest()) return Json(new { success = false, errors = ModelState.ToJson() }); return View(model); //modelstate already populated }
protected override void SaveUser(User user) { throw new NotImplementedException(); }
/// <summary> /// Saves a user, insert or update. /// </summary> /// <param name="user"></param> protected abstract void SaveUser(User user);
/// <summary> /// Base logic to register a full user, or a guest user. Creates the appropriate records and the proper validation. /// </summary> /// <param name="user">A user with a raw password which is turned into a password hash as part of registration.</param> /// <param name="result">A ExecutionResults instance to add applicable /// warning and error messages to.</param> /// <returns>A boolean indicating success (true) or failure (false).</returns> protected virtual bool RegisterBase(User user, ExecutionResults result) { var password = user.PasswordHash; if (!ValidateName(user.Name, result) || !ValidatePassword(password, result)) return false; var existing = GetUserByName(user.Name); if (existing != null) { //seed user table with deleted users with names you don't want users to have result.AppendError("The name you specified cannot be used."); return false; } if (user.UserID.Equals(Guid.Empty)) user.UserID = Guid.NewGuid(); var hasher = HashManager.SelectProvider(); var salt = new UserSalt { PasswordSalt = hasher.GetSalt(), UserID = user.UserID, HashGroup = new Random(DateTime.Now.Second).Next(HashGroupMinimum, HashGroupMaximum), HashName = hasher.Name }; user.PasswordHash = hasher.Hash(salt.PasswordSalt, password, salt.HashGroup + BaseHashIterations); using (var scope = new System.Transactions.TransactionScope()) { //starts as a lightweight transaction SaveUser(user); //enlists in a full distributed transaction if users and salts have different connection strings SaveUserSalt(salt); scope.Complete(); } return true; }
/// <summary> /// updates a user's name and/or password. /// </summary> /// <param name="item">The user details to be saved. If Password is empty is it not changed. If specified it should be the new raw password (not a hash).</param> /// <param name="currentPassword">The current raw password for the user used to authenticate that the change can be made, or the current resetcode last sent to this user.</param> /// <param name="ipAddress">The internet address where the user is connecting from.</param> /// <param name="result">A ExecutionResults instance to add applicable /// warning and error messages to.</param> /// <returns>A boolean indicating success (true) or failure (false).</returns> public virtual bool UpdateUser(User item, String currentPassword, String ipAddress, ExecutionResults result) { if (item.UserID.Equals(Guid.Empty)) throw new ArgumentException("The user identity must be specified."); var user = GetUserByID(item.UserID); var salt = GetUserSalt(item.UserID); if (user == null || salt == null) { result.AppendError("The specified user identity does not exist."); return false; } if (salt.ResetCode == currentPassword) { if (salt.ResetCodeExpiration < DateTime.UtcNow) { result.AppendError( user.IsGuest ? "Your account verification code has expired. Request a password reset to complete your registration." : "Your password reset code has expired. Request a new one to be sent to you, and then use it immediately."); return false; } salt.ResetCode = null; salt.ResetCodeExpiration = DateTime.UtcNow; } else { var rememberMe = !SecurityContextManager.IsAnonymous && SecurityContextManager.CurrentUser.Identity.Ticket.UserSession.ExpirationDate > DateTime.UtcNow.AddMinutes(PublicSessionDuration); if (!AuthenticateUser(name: item.Name, password: currentPassword, ipAddress: ipAddress, duration: rememberMe ? UserSessionDurationType.Extended : UserSessionDurationType.PublicComputer, allowUpdateHash: false, checkHistory: false, result: result).IsAuthenticated) { result.AppendError("Cannot change password due to authentication error with current password."); return false; } } if (user.Name != item.Name) { //user is changing their sign in name. Make sure the new name is available. var nameExisting = GetUserByName(item.Name); if (nameExisting != null) { result.AppendError("The name you specified cannot be used."); return false; } user.Name = item.Name; } if (!String.IsNullOrEmpty(item.PasswordHash)) { var password = item.PasswordHash; //update hashes on regular basis, keeps the iterations in latest range for current users, and with a 'current' hash provider. HashProvider hasher = HashManager.SelectProvider(); salt.PasswordSalt = hasher.GetSalt(); salt.HashGroup = new Random(DateTime.Now.Second).Next(HashGroupMinimum, HashGroupMaximum); salt.HashName = hasher.Name; user.PasswordHash = hasher.Hash(salt.PasswordSalt, password, salt.HashGroup + BaseHashIterations); user.PasswordUpdatedDate = DateTime.UtcNow; } using (var scope = new System.Transactions.TransactionScope()) { //starts as a lightweight transaction SaveUser(user); //enlists in a full distributed transaction if users and salts have different connection strings SaveUserSalt(salt); scope.Complete(); } return true; }
/// <summary> /// Registers a new user. The PasswordHash property should be the actual password. /// </summary> /// <param name="user">A user with a raw password which is turned into a password hash as part of registration.</param> /// <param name="duration">The amount of time that the initial session will be valid.</param> /// <param name="ipAddress">The internet address where the user is connecting from.</param> /// <param name="result">A ExecutionResults instance to add applicable /// warning and error messages to.</param> /// <returns>A boolean indicating success (true) or failure (false).</returns> public virtual UserIdentity RegisterUser(User user, UserSessionDurationType duration, String ipAddress, ExecutionResults result) { var password = user.PasswordHash; //grab before it gets hashed. if (!RegisterBase(user, result)) return new UserIdentity(); return AuthenticateUser(name: user.Name, password: password, duration: duration, ipAddress: ipAddress, checkHistory: false, allowUpdateHash: false, result: result); }
/// <summary> /// Registers a new guest user. The user is being created by another user /// that is inviting this user to join. /// </summary> /// <param name="user">A user with a raw password which is turned into a password hash as part of registration.</param> /// <param name="result">A ExecutionResults instance to add applicable /// warning and error messages to.</param> /// <returns>The guest password good for 14 days, or another configurable number of days. /// After that initial period the user can request a password reset when joining.</returns> public virtual String RegisterGuestUser(User user, ExecutionResults result) { user.IsGuest = true; return !RegisterBase(user, result) ? null : GenerateUserResetCode(user.Name, TimeSpan.FromDays(GuestUserExpirationDays)); }
/// <summary> /// Saves a user, insert or update depending if RecordId is non-zero. /// </summary> /// <param name="user"></param> protected override void SaveUser(User user) { using (var cn = new SqlConnection(ConnectionStringUser)) { cn.Open(); using (var cmd = new SqlCommand()) { cmd.Connection = cn; cmd.CommandType = System.Data.CommandType.Text; if (user.RecordID == 0) { cmd.CommandText = @"insert into Security.User (UserID, Name, IsGuest, PasswordHash, PasswordHashUpdatedDate) Values (@UserID, @Name, @IsGuest, @PasswordHash, getutcdate())"; cmd.Parameters.AddWithValue("UserID", user.UserID); cmd.Parameters.AddWithValue("Name", user.Name); cmd.Parameters.AddWithValue("IsGuest", user.IsGuest); cmd.Parameters.AddWithValue("PasswordHash", user.PasswordHash); } else { cmd.CommandText = @"update Security.User set Name = @Name, IsGuest = @IsGuest, PasswordHash = @PasswordHash, PasswordHashUpdatedDate = @PasswordHashUpdatedDate, PasswordUpdatedDate = @PasswordUpdatedDate IsDeleted = @IsDeleted, UpdatedDate = @UpdatedDate, UpdatedByUserID = @UpdatedByUserID where UserID = @UserID"; cmd.Parameters.AddWithValue("Name", user.Name); cmd.Parameters.AddWithValue("IsGuest", user.IsGuest); cmd.Parameters.AddWithValue("PasswordHash", user.PasswordHash); cmd.Parameters.AddWithValue("PasswordHashUpdatedDate", user.PasswordHashUpdatedDate); cmd.Parameters.AddWithValue("PasswordUpdatedDate", user.PasswordUpdatedDate); cmd.Parameters.AddWithValue("IsDeleted", user.IsDeleted); cmd.Parameters.AddWithValue("UpdatedDate", user.UpdatedDate); cmd.Parameters.AddWithValue("UpdatedByUserID", user.UpdatedByUserID); cmd.Parameters.AddWithValue("UserID", user.UserID); } cmd.ExecuteNonQuery(); } } }
/// <summary> /// updates a user's name and/or password. /// </summary> /// <param name="item">The user details to be saved. If Password is empty is it not changed. If specified it should be the new raw password (not a hash).</param> /// <param name="currentPassword">The current raw password for the user used to authenticate that the change can be made.</param> /// <param name="ipAddress">The internet address where the user is connecting from.</param> /// <param name="result">A ExecutionResults instance to add applicable /// warning and error messages to.</param> /// <returns>A boolean indicating success (true) or failure (false).</returns> public static bool UpdateUser(User item, String currentPassword, String ipAddress, ExecutionResults result) { return Provider.UpdateUser(item, currentPassword, ipAddress, result); }
/// <summary> /// Registers a new user. The PasswordHash property should be the actual password. /// </summary> /// <param name="user">A user with a raw password which is turned into a password hash as part of registration.</param> /// <param name="duration">The amount of time that the initial session will be valid.</param> /// <param name="ipAddress">The internet address where the user is connecting from.</param> /// <param name="result">A ExecutionResults instance to add applicable /// warning and error messages to.</param> /// <returns>A boolean indicating success (true) or failure (false).</returns> public static UserIdentity RegisterUser(User user, UserSessionDurationType duration, String ipAddress, ExecutionResults result) { return Provider.RegisterUser(user, duration, ipAddress, result); }