/// <summary> /// The user Add flow works differently than other adds. After adding the record here, the calling code will also /// generate a token to send to user so they can complete registration. /// </summary> /// <param name="model"></param> /// <param name="userId"></param> /// <returns></returns> //add this layer so we can instantiate the new entity here. public override async Task <int?> Add(UserModel model, UserToken userToken) { //generate random password and then encrypt in here. var password = PasswordUtils.GenerateRandomPassword(_configUtil.PasswordConfigSettings.RandomPasswordLength); User entity = new User { ID = null , Created = DateTime.UtcNow //not actually used during registration but keep it here because db expects non null. //if future, the user sets their own pw on register complete , Password = PasswordUtils.EncryptNewPassword(_configUtil.PasswordConfigSettings.EncryptionSettings, password) }; this.MapToEntity(ref entity, model, userToken); //do this after mapping to enforce isactive is true on add entity.IsActive = true; //this will add and call saveChanges await _repo.AddAsync(entity); model.ID = entity.ID; // Return id for newly added user return(entity.ID); }
/// <summary> /// Complete user registration /// </summary> /// <param name="id"></param> /// <param name="orgId"></param> /// <returns></returns> public async void CompleteRegistration(int id, string userName, string newPassword) { //get user - match on user id, user name and is active var result = _repo.FindByCondition(u => u.ID.Equals(id) && u.UserName.ToLower().Equals(userName) && u.IsActive) .Include(p => p.UserPermissions) .FirstOrDefault(); if (result == null) { return; } //if (result == null) return null; //only allow completing registration if NOT already completed if (result.RegistrationComplete.HasValue) { // Null value is used on initial creation, therefore null may not be passed into this method. var ex = new InvalidOperationException("User has already completed registration."); _logger.Error(ex); // Log this within all targets as an error. throw ex; // Throw an explicit exception, those using this should be aware this cannot be allowed. } //encrypt and save password w/ profile result.Password = PasswordUtils.EncryptNewPassword(_configUtil.PasswordConfigSettings.EncryptionSettings, newPassword); result.LastLogin = DateTime.UtcNow; result.RegistrationComplete = DateTime.UtcNow; await _repo.UpdateAsync(result); await _repo.SaveChanges(); //return this.MapToModel(result); }
/// <summary> /// Get rule and related data /// </summary> /// <param name="id"></param> /// <param name="orgId"></param> /// <returns></returns> public async Task <UserModel> Validate(string userName, string password) { if (string.IsNullOrEmpty(password)) { // Null value is used on initial creation, therefore null may not be passed into this method. var ex = new ArgumentNullException(password, "Password required."); _logger.Error(ex); // Log this within all targets as an error. throw ex; // Throw an explicit exception, those using this should be aware this cannot be allowed. } //1. Validate against our encryption. Because we use the existing user's settings, we get the // existing pw, parse it into parts and encrypt the new pw with the same settings to see if it matches var result = _repo.FindByCondition(u => u.UserName.ToLower() == userName.ToLower() && u.IsActive && u.RegistrationComplete.HasValue) .Include(p => p.UserPermissions) .FirstOrDefault(); if (result == null) { return(null); } //test against our encryption, means we match bool updateEncryptionLevel = false; if (PasswordUtils.ValidatePassword(_configUtil.PasswordConfigSettings.EncryptionSettings, result.Password, password, out updateEncryptionLevel)) { //if the encryption level has been upgraded since original encryption, upgrade their pw now. if (updateEncryptionLevel) { result.Password = PasswordUtils.EncryptNewPassword(_configUtil.PasswordConfigSettings.EncryptionSettings, password); } result.LastLogin = DateTime.UtcNow; await _repo.UpdateAsync(result); await _repo.SaveChanges(); return(this.MapToModel(result)); } // No user match found, username or password incorrect. return(null); }
/// <summary> /// The user Add flow works differently than the other add. This allows caller to add and complete /// registration in one step rather than two. /// </summary> /// <param name="model"></param> /// <param name="userId"></param> /// <returns></returns> //add this layer so we can instantiate the new entity here. public async Task <int?> AddOneStep(UserModel model, UserToken userToken, string password) { User entity = new User { ID = null , Created = DateTime.UtcNow , Password = PasswordUtils.EncryptNewPassword(_configUtil.PasswordConfigSettings.EncryptionSettings, password) , RegistrationComplete = DateTime.UtcNow }; this.MapToEntity(ref entity, model, userToken); //do this after mapping to enforce isactive is true on add entity.IsActive = true; //this will add and call saveChanges await _repo.AddAsync(entity); model.ID = entity.ID; // Return id for newly added user return(entity.ID); }
/// <summary> /// Complete user registration /// </summary> /// <param name="id"></param> /// <param name="orgId"></param> /// <returns></returns> public async Task <UserModel> ResetPassword(int id, string userName, string newPassword) { //get user - match on user id, user name and is active var result = _repo.FindByCondition(u => u.ID.Equals(id) && u.UserName.ToLower().Equals(userName.ToLower()) && u.IsActive) .Include(p => p.UserPermissions) .FirstOrDefault(); if (result == null) { return(null); } //encrypt and save password w/ profile result.Password = PasswordUtils.EncryptNewPassword(_configUtil.PasswordConfigSettings.EncryptionSettings, newPassword); result.LastLogin = DateTime.UtcNow; await _repo.UpdateAsync(result); await _repo.SaveChanges(); return(this.MapToModel(result)); }
/// <summary> /// Update the user's pasword /// </summary> /// <remarks> /// This assumes the controller does all the proper validation and passes a non-encrypted value /// </remarks> /// <param name="user"></param> /// <param name="newPassword"></param> /// <returns></returns> public async Task <int> ChangePassword(int id, string oldPassword, string newPassword) { var existingUser = _repo.GetByID(id); if (existingUser == null || !existingUser.IsActive) { throw new ArgumentNullException($"User not found with id {id}"); } //validate existing password if (this.Validate(existingUser.UserName, oldPassword) == null) { throw new ArgumentNullException($"Change Password - Old Password does not match for user {id}"); } //Encrypt new password existingUser.Password = PasswordUtils.EncryptNewPassword(_configUtil.PasswordConfigSettings.EncryptionSettings, newPassword); //save changes await _repo.UpdateAsync(existingUser); return(await _repo.SaveChanges()); }