2017-03-02 21:04:03 -08:00
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
2016-10-14 00:06:35 -07:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
using System.Threading.Tasks ;
using Microsoft.AspNetCore.Authorization ;
using Microsoft.AspNetCore.Identity ;
using Microsoft.AspNetCore.Mvc ;
using Microsoft.Extensions.Logging ;
using WebApplication.Models ;
using WebApplication.Models.ManageViewModels ;
using WebApplication.Services ;
namespace WebApplication.Controllers
{
[Authorize]
public class ManageController : Controller
{
private readonly UserManager < ApplicationUser > _userManager ;
private readonly SignInManager < ApplicationUser > _signInManager ;
private readonly IEmailSender _emailSender ;
private readonly ISmsSender _smsSender ;
private readonly ILogger _logger ;
public ManageController (
UserManager < ApplicationUser > userManager ,
SignInManager < ApplicationUser > signInManager ,
IEmailSender emailSender ,
ISmsSender smsSender ,
ILoggerFactory loggerFactory )
{
_userManager = userManager ;
_signInManager = signInManager ;
_emailSender = emailSender ;
_smsSender = smsSender ;
_logger = loggerFactory . CreateLogger < ManageController > ( ) ;
}
//
// GET: /Manage/Index
[HttpGet]
public async Task < IActionResult > Index ( ManageMessageId ? message = null )
{
ViewData [ "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 user = await GetCurrentUserAsync ( ) ;
var model = new IndexViewModel
{
HasPassword = await _userManager . HasPasswordAsync ( user ) ,
PhoneNumber = await _userManager . GetPhoneNumberAsync ( user ) ,
TwoFactor = await _userManager . GetTwoFactorEnabledAsync ( user ) ,
Logins = await _userManager . GetLoginsAsync ( user ) ,
BrowserRemembered = await _signInManager . IsTwoFactorClientRememberedAsync ( user )
} ;
return View ( model ) ;
}
//
// POST: /Manage/RemoveLogin
[HttpPost]
[ValidateAntiForgeryToken]
public async Task < IActionResult > RemoveLogin ( RemoveLoginViewModel account )
{
ManageMessageId ? message = ManageMessageId . Error ;
var user = await GetCurrentUserAsync ( ) ;
if ( user ! = null )
{
var result = await _userManager . RemoveLoginAsync ( user , account . LoginProvider , account . ProviderKey ) ;
if ( result . Succeeded )
{
await _signInManager . SignInAsync ( user , isPersistent : false ) ;
message = ManageMessageId . RemoveLoginSuccess ;
}
}
return RedirectToAction ( nameof ( ManageLogins ) , new { Message = message } ) ;
}
//
// GET: /Manage/AddPhoneNumber
public IActionResult AddPhoneNumber ( )
{
return View ( ) ;
}
//
// POST: /Manage/AddPhoneNumber
[HttpPost]
[ValidateAntiForgeryToken]
public async Task < IActionResult > AddPhoneNumber ( AddPhoneNumberViewModel model )
{
if ( ! ModelState . IsValid )
{
return View ( model ) ;
}
// Generate the token and send it
var user = await GetCurrentUserAsync ( ) ;
var code = await _userManager . GenerateChangePhoneNumberTokenAsync ( user , model . PhoneNumber ) ;
await _smsSender . SendSmsAsync ( model . PhoneNumber , "Your security code is: " + code ) ;
return RedirectToAction ( nameof ( VerifyPhoneNumber ) , new { PhoneNumber = model . PhoneNumber } ) ;
}
//
// POST: /Manage/EnableTwoFactorAuthentication
[HttpPost]
[ValidateAntiForgeryToken]
public async Task < IActionResult > EnableTwoFactorAuthentication ( )
{
var user = await GetCurrentUserAsync ( ) ;
if ( user ! = null )
{
await _userManager . SetTwoFactorEnabledAsync ( user , true ) ;
await _signInManager . SignInAsync ( user , isPersistent : false ) ;
_logger . LogInformation ( 1 , "User enabled two-factor authentication." ) ;
}
return RedirectToAction ( nameof ( Index ) , "Manage" ) ;
}
//
// POST: /Manage/DisableTwoFactorAuthentication
[HttpPost]
[ValidateAntiForgeryToken]
public async Task < IActionResult > DisableTwoFactorAuthentication ( )
{
var user = await GetCurrentUserAsync ( ) ;
if ( user ! = null )
{
await _userManager . SetTwoFactorEnabledAsync ( user , false ) ;
await _signInManager . SignInAsync ( user , isPersistent : false ) ;
_logger . LogInformation ( 2 , "User disabled two-factor authentication." ) ;
}
return RedirectToAction ( nameof ( Index ) , "Manage" ) ;
}
//
// GET: /Manage/VerifyPhoneNumber
[HttpGet]
public async Task < IActionResult > VerifyPhoneNumber ( string phoneNumber )
{
var code = await _userManager . GenerateChangePhoneNumberTokenAsync ( await GetCurrentUserAsync ( ) , phoneNumber ) ;
// Send an SMS to verify the phone number
return phoneNumber = = null ? View ( "Error" ) : View ( new VerifyPhoneNumberViewModel { PhoneNumber = phoneNumber } ) ;
}
//
// POST: /Manage/VerifyPhoneNumber
[HttpPost]
[ValidateAntiForgeryToken]
public async Task < IActionResult > VerifyPhoneNumber ( VerifyPhoneNumberViewModel model )
{
if ( ! ModelState . IsValid )
{
return View ( model ) ;
}
var user = await GetCurrentUserAsync ( ) ;
if ( user ! = null )
{
var result = await _userManager . ChangePhoneNumberAsync ( user , model . PhoneNumber , model . Code ) ;
if ( result . Succeeded )
{
await _signInManager . SignInAsync ( user , isPersistent : false ) ;
return RedirectToAction ( nameof ( Index ) , new { Message = ManageMessageId . AddPhoneSuccess } ) ;
}
}
// If we got this far, something failed, redisplay the form
ModelState . AddModelError ( string . Empty , "Failed to verify phone number" ) ;
return View ( model ) ;
}
//
// POST: /Manage/RemovePhoneNumber
[HttpPost]
[ValidateAntiForgeryToken]
public async Task < IActionResult > RemovePhoneNumber ( )
{
var user = await GetCurrentUserAsync ( ) ;
if ( user ! = null )
{
var result = await _userManager . SetPhoneNumberAsync ( user , null ) ;
if ( result . Succeeded )
{
await _signInManager . SignInAsync ( user , isPersistent : false ) ;
return RedirectToAction ( nameof ( Index ) , new { Message = ManageMessageId . RemovePhoneSuccess } ) ;
}
}
return RedirectToAction ( nameof ( Index ) , new { Message = ManageMessageId . Error } ) ;
}
//
// GET: /Manage/ChangePassword
[HttpGet]
public IActionResult ChangePassword ( )
{
return View ( ) ;
}
//
// POST: /Manage/ChangePassword
[HttpPost]
[ValidateAntiForgeryToken]
public async Task < IActionResult > ChangePassword ( ChangePasswordViewModel model )
{
if ( ! ModelState . IsValid )
{
return View ( model ) ;
}
var user = await GetCurrentUserAsync ( ) ;
if ( user ! = null )
{
var result = await _userManager . ChangePasswordAsync ( user , model . OldPassword , model . NewPassword ) ;
if ( result . Succeeded )
{
await _signInManager . SignInAsync ( user , isPersistent : false ) ;
_logger . LogInformation ( 3 , "User changed their password successfully." ) ;
return RedirectToAction ( nameof ( Index ) , new { Message = ManageMessageId . ChangePasswordSuccess } ) ;
}
AddErrors ( result ) ;
return View ( model ) ;
}
return RedirectToAction ( nameof ( Index ) , new { Message = ManageMessageId . Error } ) ;
}
//
// GET: /Manage/SetPassword
[HttpGet]
public IActionResult SetPassword ( )
{
return View ( ) ;
}
//
// POST: /Manage/SetPassword
[HttpPost]
[ValidateAntiForgeryToken]
public async Task < IActionResult > SetPassword ( SetPasswordViewModel model )
{
if ( ! ModelState . IsValid )
{
return View ( model ) ;
}
var user = await GetCurrentUserAsync ( ) ;
if ( user ! = null )
{
var result = await _userManager . AddPasswordAsync ( user , model . NewPassword ) ;
if ( result . Succeeded )
{
await _signInManager . SignInAsync ( user , isPersistent : false ) ;
return RedirectToAction ( nameof ( Index ) , new { Message = ManageMessageId . SetPasswordSuccess } ) ;
}
AddErrors ( result ) ;
return View ( model ) ;
}
return RedirectToAction ( nameof ( Index ) , new { Message = ManageMessageId . Error } ) ;
}
//GET: /Manage/ManageLogins
[HttpGet]
public async Task < IActionResult > ManageLogins ( ManageMessageId ? message = null )
{
ViewData [ "StatusMessage" ] =
message = = ManageMessageId . RemoveLoginSuccess ? "The external login was removed."
: message = = ManageMessageId . AddLoginSuccess ? "The external login was added."
: message = = ManageMessageId . Error ? "An error has occurred."
: "" ;
var user = await GetCurrentUserAsync ( ) ;
if ( user = = null )
{
return View ( "Error" ) ;
}
var userLogins = await _userManager . GetLoginsAsync ( user ) ;
var otherLogins = _signInManager . GetExternalAuthenticationSchemes ( ) . Where ( auth = > userLogins . All ( ul = > auth . AuthenticationScheme ! = ul . LoginProvider ) ) . ToList ( ) ;
ViewData [ "ShowRemoveButton" ] = user . PasswordHash ! = null | | userLogins . Count > 1 ;
return View ( new ManageLoginsViewModel
{
CurrentLogins = userLogins ,
OtherLogins = otherLogins
} ) ;
}
//
// POST: /Manage/LinkLogin
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult LinkLogin ( string provider )
{
// Request a redirect to the external login provider to link a login for the current user
var redirectUrl = Url . Action ( "LinkLoginCallback" , "Manage" ) ;
var properties = _signInManager . ConfigureExternalAuthenticationProperties ( provider , redirectUrl , _userManager . GetUserId ( User ) ) ;
return Challenge ( properties , provider ) ;
}
//
// GET: /Manage/LinkLoginCallback
[HttpGet]
public async Task < ActionResult > LinkLoginCallback ( )
{
var user = await GetCurrentUserAsync ( ) ;
if ( user = = null )
{
return View ( "Error" ) ;
}
var info = await _signInManager . GetExternalLoginInfoAsync ( await _userManager . GetUserIdAsync ( user ) ) ;
if ( info = = null )
{
return RedirectToAction ( nameof ( ManageLogins ) , new { Message = ManageMessageId . Error } ) ;
}
var result = await _userManager . AddLoginAsync ( user , info ) ;
var message = result . Succeeded ? ManageMessageId . AddLoginSuccess : ManageMessageId . Error ;
return RedirectToAction ( nameof ( ManageLogins ) , new { Message = message } ) ;
}
#region Helpers
private void AddErrors ( IdentityResult result )
{
foreach ( var error in result . Errors )
{
ModelState . AddModelError ( string . Empty , error . Description ) ;
}
}
public enum ManageMessageId
{
AddPhoneSuccess ,
AddLoginSuccess ,
ChangePasswordSuccess ,
SetTwoFactorSuccess ,
SetPasswordSuccess ,
RemoveLoginSuccess ,
RemovePhoneSuccess ,
Error
}
private Task < ApplicationUser > GetCurrentUserAsync ( )
{
return _userManager . GetUserAsync ( HttpContext . User ) ;
}
#endregion
}
}