public ActionResult Log(int id) { var isAdmin = UserIdentity.IsUserInRole(this, "Admin"); var currentUserId = UserIdentity.GetUserId(this); var users = _context.User .Include("UserLogs") .Where(u => u.Id == id && (u.Id == currentUserId || isAdmin)); if (users.ToList().Count == 0) { return(new HttpNotFoundResult()); } var user = users.Single(); var requester = UserIdentity.GetRequester(this); // SECURE: Check user should have access to this account if (!UserIdentity.IsUserInRole(this, "Admin") && UserIdentity.GetUserId(this) != user.Id) { Logger.Information("Failed User Log Get, access not permitted by requester {@requester}", requester); return(new HttpNotFoundResult()); } ViewBag.UserName = user.UserName; return(View(new UserLogViewModel(user))); }
// GET: Error public ActionResult Forbidden() { ActionResult result; object model = Request.Url?.PathAndQuery; if (!Request.IsAjaxRequest()) { result = View("Forbidden", model); } else { result = PartialView("_Forbidden", model); } Response.StatusCode = 403; Response.TrySkipIisCustomErrors = true; Requester requester = UserIdentity.GetRequester(this); var currentExecutionFilePath = Request.CurrentExecutionFilePath; if (Server.GetLastError() is HttpAntiForgeryException) { Logger.Information("Forbidden request, attempted CSRF {currentExecutionFilePath} accessed by user {@requester}", currentExecutionFilePath, requester); } else { Logger.Information("Forbidden request {currentExecutionFilePath} accessed by user {@requester}", currentExecutionFilePath, requester); } return(result); }
public JsonResult Disable(int id, FormCollection collection) { if (id == 0) { return(Json(new { success = false, message = "unable to locate user id" })); } var requester = UserIdentity.GetRequester(this); var user = _context.User.FirstOrDefault(u => u.Id == id); if (user == null) { Logger.Information("Failed User Disable Post for id {id}, user did not exist by requester {@requester}", id, requester); return(Json(new { success = false, message = "unable to locate user" })); } if (user.Id == UserIdentity.GetUserId(this)) { return(Json(new { success = false, message = "You cannot disable your own account" })); } user.Enabled = false; _context.SaveChanges(); Logger.Information("User Disable Post for id {id} suceeded, by requester {@requester}", id, requester); return(Json(new { success = true, message = "" })); }
public ActionResult RecoverPassword() { var passwordResetToken = Request.QueryString["PasswordResetToken"] ?? ""; var requester = UserIdentity.GetRequester(this); var user = _context.User.Include("SecurityQuestionLookupItem").SingleOrDefault(u => u.PasswordResetToken == passwordResetToken && u.PasswordResetExpiryDateUtc > DateTime.UtcNow); if (user == null) { HandleErrorInfo error = new HandleErrorInfo(new ArgumentException(@"INFO: The password recovery token is not valid or has expired"), "Account", "RecoverPassword"); Logger.Information("Failed Account RecoverPassword Get, recovery token {passwordResetToken} is not valid or expired by requester {@requester}", passwordResetToken, requester); return(View("Error", error)); } if (user.Enabled == false) { var userName = user.UserName; HandleErrorInfo error = new HandleErrorInfo(new InvalidOperationException(@"INFO: Your account is not currently approved or active"), "Account", "Recover"); Logger.Information("Failed Account RecoverPassword Get, account {userName} not approved or active by requester {@requester}", userName, requester); return(View("Error", error)); } RecoverPasswordViewModel recoverPasswordModel = new RecoverPasswordViewModel() { Id = user.Id, HasRecaptcha = _configuration.HasRecaptcha, SecurityAnswer = "", SecurityQuestion = user.SecurityQuestionLookupItem.Description, PasswordResetToken = passwordResetToken, UserName = user.UserName }; return(View("RecoverPassword", recoverPasswordModel)); }
public async Task <ActionResult> EmailVerifyAsync() { var emailVerificationToken = Request.QueryString["EmailVerficationToken"] ?? ""; var user = _context.User.SingleOrDefault(u => u.EmailConfirmationToken == emailVerificationToken); var requester = UserIdentity.GetRequester(this); if (user == null) { var error = new HandleErrorInfo( new ArgumentException("INFO: The email verification token is not valid or has expired"), "Account", "EmailVerifyAsync"); Logger.Information( "Failed Acccount EmailVerify Get for token {emailVerificationToken} by requester {@requester}", emailVerificationToken, requester); return(View("Error", error)); } user.EmailVerified = true; user.EmailConfirmationToken = null; user.UserLogs.Add(new UserLog { Description = "User Verified Email Address" }); await _context.SaveChangesAsync(); return(View("EmailVerificationSuccess")); }
// GET: Error public ActionResult NotFound() { ActionResult result; object model = Request.Url?.PathAndQuery; if (!Request.IsAjaxRequest()) { result = View("NotFound", model); } else { result = PartialView("_NotFound", model); } Response.StatusCode = 404; Response.TrySkipIisCustomErrors = true; var appSensorDetectionPoint = Core.Constants.AppSensorDetectionPointKind.Re1; // TODO: Determine if path exists, if so RE2, otherwise RE1 var currentExecutionFilePath = Request.CurrentExecutionFilePath; if (!currentExecutionFilePath.Contains("favicon")) { Requester requester = UserIdentity.GetRequester(this, appSensorDetectionPoint); Logger.Information("Unknown route {currentExecutionFilePath} accessed by user {@requester}", currentExecutionFilePath, requester); } return(result); }
public async Task <ActionResult> ChangeEmailAddressAsync(ChangeEmailAddressViewModel model) { var userId = UserIdentity.GetUserId(this); var user = _context.User.FirstOrDefault(u => u.Id == userId && u.Enabled && u.EmailVerified && u.Approved); AppSensor.ValidateFormData(this, new List <string> { "NewEmailAddress", "Password" }); if (user == null) { return(HttpNotFound()); } if (ModelState.IsValid) { if (_context.User.Any(a => a.Id != user.Id && model.NewEmailAddress == a.UserName)) { ModelState.AddModelError("NewEmailAddress", "This email address is already in use"); Logger.Information("Failed Account ChangeEmailAddress Post, Username already exists"); } else { var logonResult = await _userManager.TryLogOnAsync(UserIdentity.GetUserName(this), model.Password); if (logonResult.Success) { user.NewEmailAddressToken = Guid.NewGuid().ToString().Replace("-", ""); user.NewEmailAddressRequestExpiryDateUtc = DateTime.UtcNow.AddMinutes(15); user.NewEmailAddress = model.NewEmailAddress; // Send change username with link to recover password form string emailBody = EmailTemplates.ChangeEmailAddressPendingBodyText(user.FirstName, user.LastName, _configuration.ApplicationName, _configuration.WebsiteBaseUrl, user.NewEmailAddressToken); string emailSubject = $"{_configuration.ApplicationName} - Complete the change email address process"; _services.SendEmail(_configuration.DefaultFromEmailAddress, new List <string>() { user.UserName }, null, null, emailSubject, emailBody, true); user.UserLogs.Add(new UserLog { Description = $"Change email address request started to change from {user.UserName} to {user.NewEmailAddress}" }); await _context.SaveChangesAsync(); return(View("ChangeEmailAddressPending")); } else { Logger.Information("Failed Account ChangeEmailAddress Post, Password incorrect by requester {@requester}", UserIdentity.GetRequester(this, AppSensorDetectionPointKind.Ae1)); ModelState.AddModelError("Password", "The password is not correct"); } } } else { AppSensor.InspectModelStateErrors(this); } return(View("ChangeEmailAddress", new ChangeEmailAddressViewModel(user.UserName, user.NewEmailAddress, user.NewEmailAddressRequestExpiryDateUtc))); }
public async Task <ActionResult> ChangePasswordAsync(ChangePasswordViewModel model) { ViewBag.ReturnUrl = Url.Action("ChangePassword"); var requester = UserIdentity.GetRequester(this); var recaptchaSuccess = true; if (_configuration.HasRecaptcha) { recaptchaSuccess = _recaptcha.ValidateRecaptcha(this); } AppSensor.ValidateFormData(this, new List <string> { "ConfirmPassword", "OldPassword", "NewPassword" }); if (recaptchaSuccess) { var userId = UserIdentity.GetUserId(this); var user = _context.User.FirstOrDefault(u => u.Id == userId); if (user != null) { var result = await _userManager.ChangePasswordAsync(UserIdentity.GetUserId(this), model.OldPassword, model.NewPassword); if (result.Succeeded) { // Email recipient with password change acknowledgement var emailBody = EmailTemplates.ChangePasswordCompletedBodyText(user.FirstName, user.LastName, _configuration.ApplicationName); var emailSubject = $"{_configuration.ApplicationName} - Password change confirmation"; _services.SendEmail(_configuration.DefaultFromEmailAddress, new List <string> { user.UserName }, null, null, emailSubject, emailBody, true); _context.SaveChanges(); _formsAuth.SignOut(); _userManager.SignOut(); _httpCache.RemoveFromCache($"MustChangePassword-{userId}"); Session.Abandon(); Logger.Debug("Account Logoff due to password change"); return(View("ChangePasswordSuccess")); } Logger.Information("Failed Account ChangePassword Post by requester {@requester}", requester); AddErrors(result); } else { return(HttpNotFound()); } } else { Logger.Information("Failed Account Change Password Post Recaptcha failed by requester {@requester}", requester); } return(View("ChangePassword", model)); }
public async Task <ActionResult> RecoverAsync(RecoverViewModel model) { var requester = UserIdentity.GetRequester(this); var userName = model.UserName; AppSensor.ValidateFormData(this, new List <string> { "UserName" }); if (ModelState.IsValid) { var user = _context.User.SingleOrDefault(u => u.UserName == model.UserName && u.Enabled && u.EmailVerified && u.Approved); if (_configuration.HasRecaptcha) { if (!_recaptcha.ValidateRecaptcha(this)) { Logger.Information("Failed Account Recover Post Recaptcha failed by requester {@requester}", requester); return(View("Recover", model)); } } if (user != null) { user.PasswordResetToken = Guid.NewGuid().ToString().Replace("-", ""); user.PasswordResetExpiryDateUtc = DateTime.UtcNow.AddMinutes(15); // Send recovery email with link to recover password form var emailBody = EmailTemplates.ChangePasswordPendingBodyText(user.FirstName, user.LastName, _configuration.ApplicationName, _configuration.WebsiteBaseUrl, user.PasswordResetToken); var emailSubject = $"{_configuration.ApplicationName} - Complete the password recovery process"; _services.SendEmail(_configuration.DefaultFromEmailAddress, new List <string> { user.UserName }, null, null, emailSubject, emailBody, true); user.UserLogs.Add(new UserLog { Description = "Password reset link generated and sent" }); await _context.SaveChangesAsync(); } else { Logger.Information("Failed Account Recover Post UserName {userName} by requester {@requester}", userName, requester); return(View("RecoverSuccess")); } } else { AppSensor.InspectModelStateErrors(this); } return(View("RecoverSuccess")); }
public ActionResult Disable(int id) { User user = _context.User.FirstOrDefault(u => u.Id == id); if (user == null) { var requester = UserIdentity.GetRequester(this); Logger.Information("Failed User Disable, user {id} did not exist by requester {@requester}", id, requester); return(new HttpNotFoundResult()); } return(PartialView("_Disable", user)); }
public async Task <ActionResult> LogOnAsync(LogOnViewModel model, string returnUrl) { var requester = UserIdentity.GetRequester(this); var userName = model.UserName; AppSensor.ValidateFormData(this, new List <string> { "UserName", "Password" }); if (ModelState.IsValid) { var logonResult = await _userManager.TryLogOnAsync(model.UserName, model.Password); if (logonResult.Success) { var userId = await _userManager.LogOnAsync(logonResult.UserName, model.RememberMe); Logger.Information("Successful Account Logon Post for username {userName}", userName, model.UserName); if (logonResult.MustChangePassword) { _httpCache.SetCache($"MustChangePassword-{userId}", ""); } return(RedirectToLocal(returnUrl)); } // SECURE: Increasing wait time (with random component) for each successive logon failure (instead of locking out) _services.Wait(500 + logonResult.FailedLogonAttemptCount * 200 + new Random().Next(4) * 200); ModelState.AddModelError("", "Invalid credentials or the account is locked"); requester.AppSensorDetectionPoint = AppSensorDetectionPointKind.Ae1; Logger.Information( "Failed Account Logon Post for username {userName} attempt by requester {@requester}", userName, requester); if (logonResult.IsCommonUserName) { requester.AppSensorDetectionPoint = AppSensorDetectionPointKind.Ae12; Logger.Information( "Failed Account Logon Post Common username {userName} attempt by requester {@requester}", userName, requester); } } else { AppSensor.InspectModelStateErrors(this); } // If we got this far, something failed, redisplay form return(View("LogOn", model)); }
private ActionResult RedirectToLocal(string returnUrl) { if (Url.IsLocalUrl(returnUrl)) { return(Redirect(returnUrl)); } else { if (!string.IsNullOrEmpty(returnUrl)) { var requester = UserIdentity.GetRequester(this); Logger.Information("Logon redirect attempted to redirect to external site {returnUrl}, by requester {@requester}", returnUrl, requester); } return(RedirectToAction("Landing", "Account")); } }
public ActionResult Edit(int id) { ViewBag.StatusMessage = ""; var isAdmin = UserIdentity.IsUserInRole(this, "Admin"); var currentUserId = UserIdentity.GetUserId(this); var users = _context.User .Include("UserRoles") .Where(u => u.Id == id); var user = users.Single(); var requester = UserIdentity.GetRequester(this); // SECURE: Check user should have access to this account if (!isAdmin && currentUserId != user.Id) { Logger.Information("Failed User Edit Get, user modification was not permitted for access rights by requester {@requester}", requester); return(new HttpNotFoundResult()); } return(View(new UserViewModel(currentUserId, isAdmin, user))); }
// GET: Error public ActionResult Index() { ActionResult result; object model = Request.Url?.PathAndQuery; if (!Request.IsAjaxRequest()) { result = View("Index", model); } else { result = PartialView("_Index", model); } Response.StatusCode = 500; Response.TrySkipIisCustomErrors = true; Requester requestor = UserIdentity.GetRequester(this); Logger.Error(Server.GetLastError(), "Error occurred by user {@requestor}", requestor); return(result); }
public async Task <ActionResult> RegisterAsync(FormCollection collection) { var user = new User(); var password = collection["Password"]; var confirmPassword = collection["ConfirmPassword"]; AppSensor.ValidateFormData(this, new List <string> { "Password", "ConfirmPassword", "User.FirstName", "User.LastName", "User.UserName", "User.SecurityQuestionLookupItemId", "User.SecurityAnswer" }); var requester = UserIdentity.GetRequester(this); if (ModelState.IsValid) { var propertiesToUpdate = new[] { "FirstName", "LastName", "UserName", "SecurityQuestionLookupItemId", "SecurityAnswer" }; if (TryUpdateModel(user, "User", propertiesToUpdate, collection)) { var recaptchaSuccess = true; if (_configuration.HasRecaptcha) { recaptchaSuccess = _recaptcha.ValidateRecaptcha(this); } var userName = user.UserName; if (recaptchaSuccess) { var result = await _userManager.CreateAsync(user.UserName, user.FirstName, user.LastName, password, confirmPassword, user.SecurityQuestionLookupItemId, user.SecurityAnswer); if (result.Succeeded || result.Errors.Any(e => e == "Username already registered")) { user = _context.User.First(u => u.UserName == user.UserName); // Email the user to complete the email verification process or inform them of a duplicate registration and would they like to change their password string emailBody; string emailSubject; if (result.Succeeded) { emailSubject = $"{_configuration.ApplicationName} - Complete your registration"; emailBody = EmailTemplates.RegistrationPendingBodyText(user.FirstName, user.LastName, _configuration.ApplicationName, _configuration.WebsiteBaseUrl, user.EmailConfirmationToken); Logger.Information("Successful Account Register Post for username {userName} by requester {@requester}", userName, requester); } else { emailSubject = $"{_configuration.ApplicationName} - Duplicate Registration"; emailBody = EmailTemplates.RegistrationDuplicatedBodyText(user.FirstName, user.LastName, _configuration.ApplicationName, _configuration.WebsiteBaseUrl); Logger.Information("Duplicate Account Register Post for username {userName} by requester {@requester}", userName, requester); } _services.SendEmail(_configuration.DefaultFromEmailAddress, new List <string> { user.UserName }, null, null, emailSubject, emailBody, true); return(View("RegisterSuccess")); } else { var errorMessage = result.Errors.FirstOrDefault(); Logger.Information("Failed Account Register Post of username {userName} with message {errorMessage}, user creation failed by requester {@requester}", userName, errorMessage, requester); AddErrors(result); } } else { Logger.Information("Failed Account Register Post Recaptcha failed by requester {@requester}", requester); } } } else { AppSensor.InspectModelStateErrors(this); } var securityQuestions = _context.LookupItem.Where(l => l.LookupTypeId == Consts.LookupTypeId.SecurityQuestion && l.IsHidden == false).OrderBy(o => o.Ordinal).ToList(); var registerViewModel = new RegisterViewModel(confirmPassword, _configuration.HasRecaptcha, password, user, securityQuestions); return(View("Register", registerViewModel)); }
public async Task <ActionResult> ChangeSecurityInformationAsync(ChangeSecurityInformationViewModel model) { string errorMessage = ""; var requester = UserIdentity.GetRequester(this); AppSensor.ValidateFormData(this, new List <string> { "SecurityQuestionLookupItemId", "SecurityAnswer", "SecurityAnswerConfirm", "Password" }); if (ModelState.IsValid) { var recaptchaSuccess = true; if (_configuration.HasRecaptcha) { recaptchaSuccess = _recaptcha.ValidateRecaptcha(this); } var logonResult = await _userManager.TryLogOnAsync(UserIdentity.GetUserName(this), model.Password); if (recaptchaSuccess) { if (logonResult.Success) { if (model.SecurityAnswer == model.SecurityAnswerConfirm) { var user = _context.User.First(u => u.UserName == logonResult.UserName); _encryption.Encrypt(_configuration.EncryptionPassword, _configuration.EncryptionIterationCount, model.SecurityAnswer, out var encryptedSecurityAnswerSalt, out var encryptedSecurityAnswer); user.SecurityAnswer = encryptedSecurityAnswer; user.SecurityAnswerSalt = encryptedSecurityAnswerSalt; user.SecurityQuestionLookupItemId = model.SecurityQuestionLookupItemId; user.UserLogs.Add(new UserLog { Description = "User Changed Security Information" }); await _context.SaveChangesAsync(); // Email the user to complete the email verification process or inform them of a duplicate registration and would they like to change their password string emailSubject = $"{_configuration.ApplicationName} - Security Information Changed"; string emailBody = EmailTemplates.ChangeSecurityInformationCompletedBodyText(user.FirstName, user.LastName, _configuration.ApplicationName); _services.SendEmail(_configuration.DefaultFromEmailAddress, new List <string>() { logonResult.UserName }, null, null, emailSubject, emailBody, true); return(View("ChangeSecurityInformationSuccess")); } else { Logger.Information("Failed Account ChangeSecurityInformation Post, security answers do not match by requester {@requester}", requester); errorMessage = "The security question answers do not match"; } } else { Logger.Information("Failed Account ChangeSecurityInformation Post, security information incorrect or account locked out by requester {@requester}", requester); errorMessage = "Security information incorrect or account locked out"; } } else { AppSensor.InspectModelStateErrors(this); } } var securityQuestions = _context.LookupItem.Where(l => l.LookupTypeId == Consts.LookupTypeId.SecurityQuestion && l.IsHidden == false).OrderBy(o => o.Ordinal).ToList(); var changeSecurityInformationViewModel = new ChangeSecurityInformationViewModel(errorMessage, _configuration.HasRecaptcha, securityQuestions); return(View("ChangeSecurityInformation", changeSecurityInformationViewModel)); }
public async Task <ActionResult> RecoverPasswordAsync(RecoverPasswordViewModel recoverPasswordModel) { var user = _context.User.SingleOrDefault(u => u.Id == recoverPasswordModel.Id); var id = recoverPasswordModel.Id; var requester = UserIdentity.GetRequester(this); AppSensor.ValidateFormData(this, new List <string> { "UserName", "SecurityAnswer", "Password", "ConfirmPassword", "Id", "PasswordResetToken" }); if (user == null) { HandleErrorInfo error = new HandleErrorInfo(new Exception("INFO: The user is either not valid, not approved or not active"), "Account", "RecoverPassword"); Logger.Information("Failed Account RecoverPassword Post, recover attempted for a user id {id} which does not exist by requester {@requester}", id, requester); return(View("Error", error)); } if (!(user.Enabled)) { HandleErrorInfo error = new HandleErrorInfo(new Exception("INFO: The user is either not valid, not approved or not active"), "Account", "Recover"); Logger.Information("Failed Account RecoverPassword Post, account user id {id} is not approved or active by requester {@requester}", id, requester); return(View("Error", error)); } _encryption.Decrypt(_configuration.EncryptionPassword, user.SecurityAnswerSalt, _configuration.EncryptionIterationCount, user.SecurityAnswer, out var decryptedSecurityAnswer); if (recoverPasswordModel.SecurityAnswer != decryptedSecurityAnswer) { ModelState.AddModelError("SecurityAnswer", "The security answer is incorrect"); Logger.Information("Failed Account RecoverPassword Post, security answer is incorrect by requester {@requester}", requester); return(View("RecoverPassword", recoverPasswordModel)); } if (recoverPasswordModel.Password != recoverPasswordModel.ConfirmPassword) { ModelState.AddModelError("ConfirmPassword", "The passwords do not match"); Logger.Information("Failed Account RecoverPassword Post, passwords do not match by requester {@requester}", requester); return(View("RecoverPassword", recoverPasswordModel)); } var recaptchaSuccess = true; if (_configuration.HasRecaptcha) { recaptchaSuccess = _recaptcha.ValidateRecaptcha(this); } if (recaptchaSuccess) { if (ModelState.IsValid) { var result = await _userManager.ChangePasswordFromTokenAsync(user.Id, recoverPasswordModel.PasswordResetToken, recoverPasswordModel.Password); if (result.Succeeded) { await _context.SaveChangesAsync(); _httpCache.RemoveFromCache(string.Concat("MustChangePassword-", user.Id)); await _userManager.LogOnAsync(user.UserName, false); Logger.Information("Successful RecoverPassword Post by requester {@requester}", requester); return(View("RecoverPasswordSuccess")); } AddErrors(result); Logger.Information("Failed Account RecoverPassword Post, change password async failed by requester {@requester}", requester); return(View("RecoverPassword", recoverPasswordModel)); } ModelState.AddModelError("", "Password change was not successful"); AppSensor.InspectModelStateErrors(this); } else { Logger.Information("Failed Account Recover Password Post Recaptcha failed by requester {@requester}", requester); } return(View("RecoverPassword", recoverPasswordModel)); }
public ActionResult Edit(int id, FormCollection collection) { var isAdmin = UserIdentity.IsUserInRole(this, "Admin"); var currentUserId = UserIdentity.GetUserId(this); var isOwnProfile = currentUserId == id; var users = _context.User.Where(u => u.Id == id); if (users.ToList().Count == 0) { return(new HttpNotFoundResult()); } var user = users.Single(); ViewBag.StatusMessage = ""; var requester = UserIdentity.GetRequester(this); // SECURE: Check user should have access to this account if (!isAdmin && !isOwnProfile) { Logger.Information("Failed User Edit Post, user modification was not permitted for access rights by requester {@requester}", requester); return(new HttpNotFoundResult()); } ViewBag.StatusMessage = ""; var previousUserName = user.UserName; var propertiesToUpdate = new List <string> { "FirstName", "LastName", "TelNoHome", "TelNoMobile", "TelNoWork", "Title", "Town", "Postcode", "SkypeName" }; var expectedFields = new List <string> { "IsAccessingUserAnAdmin", "IsOwnProfile", "IsCurrentUserAnAdmin", "User.Id" }; if (isAdmin) { if (currentUserId != user.Id) { // Otherwise these fields will be disabled on the front page propertiesToUpdate.AddRange(new List <string> { "Approved", "EmailVerified", "Enabled" }); } propertiesToUpdate.AddRange(new List <string> { "UserName" }); } propertiesToUpdate.ForEach(a => expectedFields.Add(a)); AppSensor.ValidateFormData(this, expectedFields); if (TryUpdateModel(user, "User", propertiesToUpdate.ToArray(), collection)) { if (_context.User.Any(a => a.Id != user.Id && user.UserName == a.UserName)) { ModelState.AddModelError("User.UserName", "This username is already in use"); } else { if (user.UserName != previousUserName) { user.UserLogs.Add(new UserLog { Description = $"Username/Email was changed from {previousUserName} by {UserIdentity.GetUserName(this)}" }); string emailSubject = $"{_configuration.ApplicationName} - Change email address process completed"; string emailBody = EmailTemplates.ChangeEmailAddressCompletedBodyText(user.FirstName, user.LastName, _configuration.ApplicationName, previousUserName, user.UserName); _services.SendEmail(_configuration.DefaultFromEmailAddress, new List <string> { user.UserName }, null, null, emailSubject, emailBody, true); } _context.SaveChanges(); if (!isOwnProfile && isAdmin) { return(RedirectToAction("Index", "User")); } ViewBag.StatusMessage = "Your account information has been saved"; } } else { AppSensor.InspectModelStateErrors(this); } return(View("Edit", new UserViewModel(UserIdentity.GetUserId(this), isAdmin, user))); }