EnVisageOnline/Main-RMO/Source/EnVisage/Controllers/AccountController.cs

861 lines
31 KiB
C#

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using EnVisage.Code.BLL;
using EnVisage.Properties;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.Owin.Security;
using EnVisage.Models;
using EnVisage.Code;
using System.Net;
using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;
using EnVisage.Code.Cache;
using EnVisage.Code.UserVoice;
using EnVisage.Code.Session;
using Microsoft.IdentityModel.Claims;
using System.Security.Principal;
using System.Threading;
namespace EnVisage.Controllers
{
[Authorize]
public class AccountController : BaseController
{
public AccountController()
: this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
{
}
public AccountController(UserManager<ApplicationUser> userManager)
{
UserManager = userManager;
}
public UserManager<ApplicationUser> UserManager { get; private set; }
//
// GET: /Account/Login
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
[AllowAnonymous]
public ActionResult SSOFailureNoLocalAccount()
{
return View();
}
[Authorize]
public void SSOLogOff()
{
Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(""), new string[0]);
}
[Authorize]
public async Task<ApplicationUser> SSOLoginConfirmation()
{
IClaimsPrincipal principal = Thread.CurrentPrincipal as IClaimsPrincipal;
if (principal == null)
{
ssoDefault();
return null;
}
var identity = (IClaimsIdentity)principal.Identity;
if (identity.Name != null)
{
string username = identity.Name;
string[] splprm = { "\\" };
string[] names = username.Split(splprm, StringSplitOptions.None);
if (names.Length >= 2)
username = names[1];
var user = await UserManager.FindByNameAsync(username);
if (user != null)
{
if (user.Type == (int)Code.UserType.Active)
{
identity.Claims.Add(new Microsoft.IdentityModel.Claims.Claim(Microsoft.IdentityModel.Claims.ClaimTypes.NameIdentifier, user.Id));
//----Create UserVoice Token
UserVoiceApi userVoice = new UserVoiceApi();
string ssoToken = UserVoiceGenerator.create(userVoice.GetUserJsonObject(user));
if (!SessionManager.Exists(Constants.USERVOICE_SSO_TOKEN))
{
SessionManager.SetValue(Constants.USERVOICE_SSO_TOKEN, ssoToken);
HttpCookie ssoTokenCookie = new HttpCookie(Constants.USERVOICE_COOKIE_CONTEXT);
ssoTokenCookie[Constants.USERVOICE_SSO_TOKEN] = ssoToken;
ssoTokenCookie.Expires = DateTime.Now.AddDays(30d);
Response.Cookies.Add(ssoTokenCookie);
}
}
}
return user;
}
return null;
}
private void ssoDefault()
{
var principal = Thread.CurrentPrincipal;
var i = principal.Identity as System.Security.Claims.ClaimsIdentity;
string username = principal.Identity.Name;
string[] splprm = { "\\" };
string[] names = username.Split(splprm, StringSplitOptions.None);
if (names.Length >= 2)
username = names[1];
var user = UserManager.FindByNameAsync(username).Result;
if (user != null)
{
if (user.Type == (int)Code.UserType.Active)
{
i.AddClaim(new System.Security.Claims.Claim(Microsoft.IdentityModel.Claims.ClaimTypes.NameIdentifier, user.Id));
UserVoiceApi userVoice = new UserVoiceApi();
string ssoToken = UserVoiceGenerator.create(userVoice.GetUserJsonObject(user));
if (!SessionManager.Exists(Constants.USERVOICE_SSO_TOKEN))
{
SessionManager.SetValue(Constants.USERVOICE_SSO_TOKEN, ssoToken);
HttpCookie ssoTokenCookie = new HttpCookie(Constants.USERVOICE_COOKIE_CONTEXT);
ssoTokenCookie[Constants.USERVOICE_SSO_TOKEN] = ssoToken;
ssoTokenCookie.Expires = DateTime.Now.AddDays(30d);
Response.Cookies.Add(ssoTokenCookie);
}
}
}
}
//
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindAsync(model.UserName, model.Password);
if (user != null)
{
if (user.Type == (int)Code.UserType.Active)
{
await SignInAsync(user, model.RememberMe);
//----Create UserVoice Token
UserVoiceApi userVoice = new UserVoiceApi();
string ssoToken = UserVoiceGenerator.create(userVoice.GetUserJsonObject(user));
if (!SessionManager.Exists(Constants.USERVOICE_SSO_TOKEN))
{
SessionManager.SetValue(Constants.USERVOICE_SSO_TOKEN, ssoToken);
HttpCookie ssoTokenCookie = new HttpCookie(Constants.USERVOICE_COOKIE_CONTEXT);
ssoTokenCookie[Constants.USERVOICE_SSO_TOKEN] = ssoToken;
ssoTokenCookie.Expires = DateTime.Now.AddDays(30d);
Response.Cookies.Add(ssoTokenCookie);
}
return RedirectToLocal(returnUrl);
}
else
ModelState.AddModelError("", "Sorry, your account is not active.");
}
else
{
//var LDAPLogin="planit\\serverLogin"; //For directory lookup
//var LDAPPass = "serverPass";
//DirectoryEntry entry = new DirectoryEntry("LDAP://planitserver/OU=People,O=planit", LDAPLogin, LDAPPass);
// //DirectorySearcher search = new DirectorySearcher(
// // entry,
// // "(uid=" + "planit\\" + model.UserName + ")",
// // new string[] { "uid" }
// //);
// //search.SearchScope = System.DirectoryServices.SearchScope.Subtree;
// //SearchResult found = search.FindOne();
// //if (found == null){
// // ModelState.AddModelError("", "Invalid username or password.");
// // return View(model);
// //}
//bool result;
//using(var context = new PrincipalContext(ContextType.Domain, "planit", LDAPLogin, LDAPPass)) {
// //Username and password for authentication.
// result = context.ValidateCredentials("planit\\" + model.UserName, model.Password);
//}
//if (result)
//{
// var newuser = new ApplicationUser();
// newuser.UserName = model.UserName;
// var creationResult = await UserManager.CreateAsync(user, model.Password);
// if (creationResult.Succeeded)
// creationResult = UserManager.AddToRole(newuser.Id, "User");
// await SignInAsync(newuser, model.RememberMe);
// return RedirectToLocal(returnUrl);
//}
//else
ModelState.AddModelError("", "Invalid username or password.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
//
// GET: /Account/Register
[AllowAnonymous]
[Obsolete]
public ActionResult Register()
{
return View();
}
//
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
[Obsolete]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser() { UserName = model.UserName};
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInAsync(user, isPersistent: false);
return RedirectToAction("Index", "Home");
}
else
{
AddErrors(result);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
//
// POST: /Account/Disassociate
[HttpPost]
[ValidateAntiForgeryToken]
[Obsolete]
public async Task<ActionResult> Disassociate(string loginProvider, string providerKey)
{
ManageMessageId? message = null;
IdentityResult result = await UserManager.RemoveLoginAsync(User.Identity.GetID(), new UserLoginInfo(loginProvider, providerKey));
if (result.Succeeded)
{
message = ManageMessageId.RemoveLoginSuccess;
}
else
{
message = ManageMessageId.Error;
}
return RedirectToAction("Manage", new { Message = message });
}
//
// GET: /Account/Manage
[Obsolete]
public ActionResult Manage(ManageMessageId? message)
{
ViewBag.StatusMessage =
message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
: message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."
: message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed."
: message == ManageMessageId.Error ? "An error has occurred."
: "";
ViewBag.HasLocalPassword = HasPassword();
ViewBag.ReturnUrl = Url.Action("Manage");
var userId = User.Identity.GetID();
var user = DbContext.AspNetUsers.Find(userId);
var model = new ManageUserViewModel()
{
Email = user.Email,
Phone = user.Phone,
PreferredResourceAllocation = user.PreferredResourceAllocation,
PreferredTotalsDisplaying = user.PreferredTotalsDisplaying,
FirstName=user.FirstName,
LastName=user.LastName,
UserName=user.UserName
};
model.DomainUser = HttpContext.User.Identity.isSSO();
return View(model);
}
//
// POST: /Account/Manage
[HttpPost]
[ValidateAntiForgeryToken]
[Obsolete]
public async Task<ActionResult> Manage(ManageUserViewModel model)
{
bool hasPassword = HasPassword();
ViewBag.HasLocalPassword = hasPassword;
ViewBag.ReturnUrl = Url.Action("Manage");
if (hasPassword)
{
if (ModelState.IsValid)
{
IdentityResult result = await UserManager.ChangePasswordAsync(User.Identity.GetID(), model.OldPassword, model.NewPassword);
if (result.Succeeded)
{
return RedirectToAction("Manage", new { Message = ManageMessageId.ChangePasswordSuccess });
}
else
{
AddErrors(result);
}
}
}
else
{
// User does not have a password so remove any validation errors caused by a missing OldPassword field
ModelState state = ModelState["OldPassword"];
if (state != null)
{
state.Errors.Clear();
}
if (ModelState.IsValid)
{
IdentityResult result = await UserManager.AddPasswordAsync(User.Identity.GetID(), model.NewPassword);
if (result.Succeeded)
{
return RedirectToAction("Manage", new { Message = ManageMessageId.SetPasswordSuccess });
}
else
{
AddErrors(result);
}
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
//
// POST: /Account/ChangeEmail
[HttpPost]
[Obsolete]
public JsonResult ChangeEmailAndPhone(string newEmail, string newPhone, bool newPreferredResourceAllocation, bool newPreferredTotalsDisplaying,string firstname,string lastname)
{
try
{
var userId = User.Identity.GetID();
var user = UserManager.FindById(userId);
if (user.Email != newEmail)
user.Email = newEmail;
if (user.Phone != newPhone)
user.Phone = newPhone;
if (user.FirstName != firstname)
user.FirstName = firstname;
if (user.LastName != lastname)
user.LastName = lastname;
user.PreferredResourceAllocation = newPreferredResourceAllocation;
user.PreferredTotalsDisplaying = newPreferredTotalsDisplaying;
UserManager.Update(user);
DbContext.SaveChanges();
(new UsersCache()).Invalidate();
}
catch (Exception ex)
{
return Json(new { Status = "Error", Msg = ex.Message, Exception = ex.ToString() });
}
return Json(new { Status = "OK" });
}
//
// POST: /Account/ExternalLogin
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
[Obsolete]
public ActionResult ExternalLogin(string provider, string returnUrl)
{
// Request a redirect to the external login provider
return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }));
}
//
// GET: /Account/ExternalLoginCallback
[AllowAnonymous]
[Obsolete]
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
if (loginInfo == null)
{
return RedirectToAction("Login");
}
// Sign in the user with this external login provider if the user already has a login
var user = await UserManager.FindAsync(loginInfo.Login);
if (user != null)
{
await SignInAsync(user, isPersistent: false);
return RedirectToLocal(returnUrl);
}
else
{
// If the user does not have an account, then prompt the user to create an account
ViewBag.ReturnUrl = returnUrl;
ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { UserName = loginInfo.DefaultUserName });
}
}
//
// POST: /Account/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 ChallengeResult(provider, Url.Action("LinkLoginCallback", "Account"), User.Identity.GetID());
}
//
// GET: /Account/LinkLoginCallback
public async Task<ActionResult> LinkLoginCallback()
{
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(XsrfKey, User.Identity.GetID());
if (loginInfo == null)
{
return RedirectToAction("Manage", new { Message = ManageMessageId.Error });
}
var result = await UserManager.AddLoginAsync(User.Identity.GetID(), loginInfo.Login);
if (result.Succeeded)
{
return RedirectToAction("Manage");
}
return RedirectToAction("Manage", new { Message = ManageMessageId.Error });
}
//
// POST: /Account/ExternalLoginConfirmation
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl)
{
if (User.Identity.IsAuthenticated)
{
return RedirectToAction("Manage");
}
if (ModelState.IsValid)
{
// Get the information about the user from the external login provider
var info = await AuthenticationManager.GetExternalLoginInfoAsync();
if (info == null)
{
return View("ExternalLoginFailure");
}
var user = new ApplicationUser() { UserName = model.UserName};
var result = await UserManager.CreateAsync(user);
if (result.Succeeded)
{
result = await UserManager.AddLoginAsync(user.Id, info.Login);
if (result.Succeeded)
{
await SignInAsync(user, isPersistent: false);
return RedirectToLocal(returnUrl);
}
}
AddErrors(result);
}
ViewBag.ReturnUrl = returnUrl;
return View(model);
}
//
// POST: /Account/LogOff
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LogOff()
{
AuthenticationManager.SignOut();
SessionManager.Remove(Constants.USERVOICE_SSO_TOKEN);
return RedirectToAction("Index", "Home");
}
//
// GET: /Account/ExternalLoginFailure
[AllowAnonymous]
public ActionResult ExternalLoginFailure()
{
return View();
}
[ChildActionOnly]
[Obsolete]
public ActionResult RemoveAccountList()
{
var linkedAccounts = UserManager.GetLogins(User.Identity.GetID());
ViewBag.ShowRemoveButton = HasPassword() || linkedAccounts.Count > 1;
return (ActionResult)PartialView("_RemoveAccountPartial", linkedAccounts);
}
//
// GET: /Account/Activate
[AllowAnonymous]
public ActionResult Activate(string userId)
{
var user = UserManager.FindById(userId);
if (user == null)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
if (user.Type != (int)UserType.Pending)
ModelState.AddModelError("", "This account is already activated.");
var activatedUser = new ActivationUserModel()
{
Email = user.Email,
UserName = user.UserName,
Password = string.Empty,
ConfirmationPassword = string.Empty,
UserId = user.Id
};
return View(activatedUser);
}
//
// POST: /Accont/Activate
[AllowAnonymous]
[HttpPost]
public async Task<ActionResult> Activate(ActivationUserModel model)
{
if (ModelState.IsValid)
{
if (!string.IsNullOrWhiteSpace(model.UserId))
{
ApplicationDbContext cnt = new ApplicationDbContext();
var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(cnt));
var user = userManager.FindById(model.UserId);
if (user == null)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
if (user.Type != (int)UserType.Pending)
ModelState.AddModelError("", "This account is already activated.");
var passwordHash = userManager.PasswordHasher.HashPassword(model.Password);
user.PasswordHash = passwordHash;
user.Type = (int)UserType.Active;
cnt.SaveChanges();
await SignInAsync(user, false);
return RedirectToAction("Index", "Home");
}
else
ModelState.AddModelError("", "This user is not exist.");
}
return View();
}
[AllowAnonymous]
public ActionResult ForgotPassword()
{
return View(new ForgotPasswordModel());
}
[HttpPost]
[ValidateAntiForgeryToken]
[AllowAnonymous]
public ActionResult ForgotPassword(ForgotPasswordModel model)
{
if (ModelState.IsValid)
{
try
{
using (var db = new EnVisageEntities())
{
var user = db.AspNetUsers.FirstOrDefault(t => t.Email == model.Email);
if (user == null)
{
ModelState.AddModelError("", "No matching email address found");
return View(model);
}
SendResetPasswordLink(user.Id, user.UserName, user.Email, db);
}
model.Sent = true;
}
catch (BLLException blEx) // handle any system specific error
{
// display error message if required
if (blEx.DisplayError)
ModelState.AddModelError(string.Empty, blEx.Message);
else // if display not requried then display modal form with general error message
{
LogException(blEx);
SetErrorScript();
}
}
catch (Exception exception) // handle any unexpected error
{
LogException(exception);
SetErrorScript();
}
}
return View(model);
}
[HttpPost]
public ActionResult ResetPwd(string id)
{
try
{
using (var db = new EnVisageEntities())
{
var user = db.AspNetUsers.FirstOrDefault(t => t.Id == id);
if (user == null)
{
throw new ArgumentException("No matching user Id '{0}' found", id);
}
SendResetPasswordLink(user.Id, user.UserName, user.Email, db);
}
return Json(new {status = "OK"});
}
catch (Exception exception) // handle any unexpected error
{
LogException(exception);
return Json(new {status = "ERROR"});
}
}
[AllowAnonymous]
public ActionResult RestorePassword(Guid token)
{
if (Guid.Empty.Equals(token))
return new HttpNotFoundResult();
var model = new RestorePasswordModel();
try
{
using (var db = new EnVisageEntities())
{
var request = db.PasswordResetRequests.FirstOrDefault(t => t.Token == token);
if (request == null)
return new HttpNotFoundResult();
if (request.ValidUntil < DateTime.Now)
throw new RestorePasswordTokenExpiredException();
}
}
catch (BLLException blEx) // handle any system specific error
{
// display error message if required
if (blEx.DisplayError)
ModelState.AddModelError(string.Empty, blEx.Message);
else // if display not requried then display modal form with general error message
{
LogException(blEx);
SetErrorScript();
}
}
catch (Exception exception) // handle any unexpected error
{
LogException(exception);
SetErrorScript();
}
return View(model);
}
[HttpPost]
[ValidateAntiForgeryToken]
[AllowAnonymous]
public ActionResult RestorePassword(RestorePasswordModel model)
{
if (ModelState.IsValid)
{
try
{
using (var db = new EnVisageEntities())
{
var request = db.PasswordResetRequests.FirstOrDefault(t => t.Token == model.Token);
if (request == null)
return new HttpNotFoundResult();
if (request.ValidUntil < DateTime.Now)
throw new RestorePasswordTokenExpiredException();
var user = db.AspNetUsers.FirstOrDefault(t => t.Id == request.UserId);
if (user == null)
return new HttpNotFoundResult();
db.Entry(request).State = EntityState.Deleted;
UserManager.RemovePassword(user.Id);
UserManager.AddPassword(user.Id, model.Password);
user.Type = (int)UserType.Active;
db.SaveChanges();
}
model.Restored = true;
}
catch (BLLException blEx) // handle any system specific error
{
// display error message if required
if (blEx.DisplayError)
ModelState.AddModelError(string.Empty, blEx.Message);
else // if display not requried then display modal form with general error message
{
LogException(blEx);
SetErrorScript();
}
}
catch (Exception exception) // handle any unexpected error
{
LogException(exception);
SetErrorScript();
}
}
return View(model);
}
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
{
get
{
return HttpContext.GetOwinContext().Authentication;
}
}
private async Task SignInAsync(ApplicationUser user, bool isPersistent)
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
// identity.AddClaim(new System.Security.Claims.Claim("PrevuID",user.Id.ToString(),"PrevuID"));
var auth_props = new AuthenticationProperties() { IsPersistent = isPersistent };
if(isPersistent)
auth_props.ExpiresUtc = DateTime.UtcNow.AddHours(12);
AuthenticationManager.SignIn(auth_props, identity);
}
private void AddErrors(IdentityResult result)
{
foreach (var error in result.Errors)
{
ModelState.AddModelError("", error);
}
}
private bool HasPassword()
{
var user = UserManager.FindById(User.Identity.GetID());
if (user != null)
{
return user.PasswordHash != null;
}
return false;
}
public enum ManageMessageId
{
ChangePasswordSuccess,
SetPasswordSuccess,
RemoveLoginSuccess,
Error
}
private ActionResult RedirectToLocal(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
private class ChallengeResult : HttpUnauthorizedResult
{
public ChallengeResult(string provider, string redirectUri) : this(provider, redirectUri, null)
{
}
public ChallengeResult(string provider, string redirectUri, string userId)
{
LoginProvider = provider;
RedirectUri = redirectUri;
UserId = userId;
}
public string LoginProvider { get; set; }
public string RedirectUri { get; set; }
public string UserId { get; set; }
public override void ExecuteResult(ControllerContext context)
{
var properties = new AuthenticationProperties() { RedirectUri = RedirectUri };
if (UserId != null)
{
properties.Dictionary[XsrfKey] = UserId;
}
context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);
}
}
private static void SendResetPasswordLink(string userId, string userName, string email, EnVisageEntities db)
{
var request = new PasswordResetRequest
{
Token = Guid.NewGuid(),
Id = Guid.NewGuid(),
UserId = userId,
ValidUntil = DateTime.Now.AddDays(Settings.Default.ForgotPasswordLinkTTLDays)
};
db.PasswordResetRequests.Add(request);
db.SaveChanges();
MailManager.SendRestorePasswordMessage(email, request.Token, userName);
}
#endregion
}
}