using Microsoft.AspNet.Identity; using Microsoft.AspNet.Identity.Owin; using Microsoft.Owin.Security; using PostSharp.Samples.MiniProfiler.Models; using System.Linq; using System.Threading.Tasks; using System.Web; using System.Web.Mvc; namespace PostSharp.Samples.MiniProfiler.Controllers { [Authorize] public class ManageController : Controller { private ApplicationSignInManager _signInManager; private ApplicationUserManager _userManager; public ManageController() { } public ManageController(ApplicationUserManager userManager, ApplicationSignInManager signInManager) { UserManager = userManager; SignInManager = signInManager; } public ApplicationSignInManager SignInManager { get { return _signInManager ?? HttpContext.GetOwinContext().Get<ApplicationSignInManager>(); } private set { _signInManager = value; } } public ApplicationUserManager UserManager { get { return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>(); } private set { _userManager = value; } } // // GET: /Manage/Index public async Task<ActionResult> Index(ManageMessageId? message) { ViewBag.StatusMessage = message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed." : message == ManageMessageId.SetPasswordSuccess ? "Your password has been set." : message == ManageMessageId.SetTwoFactorSuccess ? "Your two-factor authentication provider has been set." : message == ManageMessageId.Error ? "An error has occurred." : message == ManageMessageId.AddPhoneSuccess ? "Your phone number was added." : message == ManageMessageId.RemovePhoneSuccess ? "Your phone number was removed." : ""; var userId = User.Identity.GetUserId(); var model = new IndexViewModel { HasPassword = HasPassword(), PhoneNumber = await UserManager.GetPhoneNumberAsync(userId), TwoFactor = await UserManager.GetTwoFactorEnabledAsync(userId), Logins = await UserManager.GetLoginsAsync(userId), BrowserRemembered = await AuthenticationManager.TwoFactorBrowserRememberedAsync(userId) }; return View(model); } // // POST: /Manage/RemoveLogin [HttpPost] [ValidateAntiForgeryToken] public async Task<ActionResult> RemoveLogin(string loginProvider, string providerKey) { ManageMessageId? message; var result = await UserManager.RemoveLoginAsync(User.Identity.GetUserId(), new UserLoginInfo(loginProvider, providerKey)); if (result.Succeeded) { var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); if (user != null) { await SignInManager.SignInAsync(user, false, false); } message = ManageMessageId.RemoveLoginSuccess; } else { message = ManageMessageId.Error; } return RedirectToAction("ManageLogins", new { Message = message }); } // // GET: /Manage/AddPhoneNumber public ActionResult AddPhoneNumber() { return View(); } // // POST: /Manage/AddPhoneNumber [HttpPost] [ValidateAntiForgeryToken] public async Task<ActionResult> AddPhoneNumber(AddPhoneNumberViewModel model) { if (!ModelState.IsValid) { return View(model); } // Generate the token and send it var code = await UserManager.GenerateChangePhoneNumberTokenAsync(User.Identity.GetUserId(), model.Number); if (UserManager.SmsService != null) { var message = new IdentityMessage { Destination = model.Number, Body = "Your security code is: " + code }; await UserManager.SmsService.SendAsync(message); } return RedirectToAction("VerifyPhoneNumber", new { PhoneNumber = model.Number }); } // // POST: /Manage/EnableTwoFactorAuthentication [HttpPost] [ValidateAntiForgeryToken] public async Task<ActionResult> EnableTwoFactorAuthentication() { await UserManager.SetTwoFactorEnabledAsync(User.Identity.GetUserId(), true); var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); if (user != null) { await SignInManager.SignInAsync(user, false, false); } return RedirectToAction("Index", "Manage"); } // // POST: /Manage/DisableTwoFactorAuthentication [HttpPost] [ValidateAntiForgeryToken] public async Task<ActionResult> DisableTwoFactorAuthentication() { await UserManager.SetTwoFactorEnabledAsync(User.Identity.GetUserId(), false); var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); if (user != null) { await SignInManager.SignInAsync(user, false, false); } return RedirectToAction("Index", "Manage"); } // // GET: /Manage/VerifyPhoneNumber public async Task<ActionResult> VerifyPhoneNumber(string phoneNumber) { var code = await UserManager.GenerateChangePhoneNumberTokenAsync(User.Identity.GetUserId(), phoneNumber); // Send an SMS through the SMS provider to verify the phone number return phoneNumber == null ? View("Error") : View(new VerifyPhoneNumberViewModel { PhoneNumber = phoneNumber }); } // // POST: /Manage/VerifyPhoneNumber [HttpPost] [ValidateAntiForgeryToken] public async Task<ActionResult> VerifyPhoneNumber(VerifyPhoneNumberViewModel model) { if (!ModelState.IsValid) { return View(model); } var result = await UserManager.ChangePhoneNumberAsync(User.Identity.GetUserId(), model.PhoneNumber, model.Code); if (result.Succeeded) { var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); if (user != null) { await SignInManager.SignInAsync(user, false, false); } return RedirectToAction("Index", new { Message = ManageMessageId.AddPhoneSuccess }); } // If we got this far, something failed, redisplay form ModelState.AddModelError("", "Failed to verify phone"); return View(model); } // // POST: /Manage/RemovePhoneNumber [HttpPost] [ValidateAntiForgeryToken] public async Task<ActionResult> RemovePhoneNumber() { var result = await UserManager.SetPhoneNumberAsync(User.Identity.GetUserId(), null); if (!result.Succeeded) { return RedirectToAction("Index", new { Message = ManageMessageId.Error }); } var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); if (user != null) { await SignInManager.SignInAsync(user, false, false); } return RedirectToAction("Index", new { Message = ManageMessageId.RemovePhoneSuccess }); } // // GET: /Manage/ChangePassword public ActionResult ChangePassword() { return View(); } // // POST: /Manage/ChangePassword [HttpPost] [ValidateAntiForgeryToken] public async Task<ActionResult> ChangePassword(ChangePasswordViewModel model) { if (!ModelState.IsValid) { return View(model); } var result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword, model.NewPassword); if (result.Succeeded) { var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); if (user != null) { await SignInManager.SignInAsync(user, false, false); } return RedirectToAction("Index", new { Message = ManageMessageId.ChangePasswordSuccess }); } AddErrors(result); return View(model); } // // GET: /Manage/SetPassword public ActionResult SetPassword() { return View(); } // // POST: /Manage/SetPassword [HttpPost] [ValidateAntiForgeryToken] public async Task<ActionResult> SetPassword(SetPasswordViewModel model) { if (ModelState.IsValid) { var result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword); if (result.Succeeded) { var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); if (user != null) { await SignInManager.SignInAsync(user, false, false); } return RedirectToAction("Index", new { Message = ManageMessageId.SetPasswordSuccess }); } AddErrors(result); } // If we got this far, something failed, redisplay form return View(model); } // // GET: /Manage/ManageLogins public async Task<ActionResult> ManageLogins(ManageMessageId? message) { ViewBag.StatusMessage = message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed." : message == ManageMessageId.Error ? "An error has occurred." : ""; var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); if (user == null) { return View("Error"); } var userLogins = await UserManager.GetLoginsAsync(User.Identity.GetUserId()); var otherLogins = AuthenticationManager.GetExternalAuthenticationTypes() .Where(auth => userLogins.All(ul => auth.AuthenticationType != ul.LoginProvider)).ToList(); ViewBag.ShowRemoveButton = user.PasswordHash != null || userLogins.Count > 1; return View(new ManageLoginsViewModel { CurrentLogins = userLogins, OtherLogins = otherLogins }); } // // POST: /Manage/LinkLogin [HttpPost] [ValidateAntiForgeryToken] public ActionResult LinkLogin(string provider) { // Request a redirect to the external login provider to link a login for the current user return new AccountController.ChallengeResult(provider, Url.Action("LinkLoginCallback", "Manage"), User.Identity.GetUserId()); } // // GET: /Manage/LinkLoginCallback public async Task<ActionResult> LinkLoginCallback() { var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(XsrfKey, User.Identity.GetUserId()); if (loginInfo == null) { return RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error }); } var result = await UserManager.AddLoginAsync(User.Identity.GetUserId(), loginInfo.Login); return result.Succeeded ? RedirectToAction("ManageLogins") : RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error }); } protected override void Dispose(bool disposing) { if (disposing && _userManager != null) { _userManager.Dispose(); _userManager = null; } base.Dispose(disposing); } #region Helpers // Used for XSRF protection when adding external logins private const string XsrfKey = "XsrfId"; private IAuthenticationManager AuthenticationManager => HttpContext.GetOwinContext().Authentication; private void AddErrors(IdentityResult result) { foreach (var error in result.Errors) { ModelState.AddModelError("", error); } } private bool HasPassword() { var user = UserManager.FindById(User.Identity.GetUserId()); if (user != null) { return user.PasswordHash != null; } return false; } private bool HasPhoneNumber() { var user = UserManager.FindById(User.Identity.GetUserId()); if (user != null) { return user.PhoneNumber != null; } return false; } public enum ManageMessageId { AddPhoneSuccess, ChangePasswordSuccess, SetTwoFactorSuccess, SetPasswordSuccess, RemoveLoginSuccess, RemovePhoneSuccess, Error } #endregion } }