Exemplo n.º 1
0
        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)));
        }
Exemplo n.º 2
0
        // 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);
        }
Exemplo n.º 3
0
        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 = "" }));
        }
Exemplo n.º 4
0
        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));
        }
Exemplo n.º 5
0
        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"));
        }
Exemplo n.º 6
0
        // 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);
        }
Exemplo n.º 7
0
        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)));
        }
Exemplo n.º 8
0
        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));
        }
Exemplo n.º 9
0
        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));
        }
Exemplo n.º 11
0
        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));
        }
Exemplo n.º 12
0
 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)));
        }
Exemplo n.º 14
0
        // 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);
        }
Exemplo n.º 15
0
        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));
        }
Exemplo n.º 16
0
        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));
        }
Exemplo n.º 17
0
        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)));
        }