Untitled
unknown
plain_text
a year ago
11 kB
9
Indexable
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
//public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
public ActionResult Login(LoginViewModel model, string returnUrl)
{
//We need to be sure basic session values are there for site operation (such as company logo, Adobe key, KBItems, etc.)
if (Session["appPath"] == null)
{
setSiteBasics();//session variables required for site operation even before user logs in
}
//We post to this ActionResult multiple times. The first time, it's for intial authentication and this will be null.
//Subsequent posts are related to MFA and the user will be in cache. We can use the data in cache to save on the database hit.
var cachedUser = MotorBase_Biz.Account.GetCurrentUserFromCache(HttpContext.User.Identity.Name);
if (cachedUser == null && model.portalUser != null) {
//The user logged in from spsuite.com and we haven't redirected yet, so no HttpContext.User.Identity.Name. We can look in cache this way.
cachedUser = MotorBase_Biz.Account.GetCurrentUserFromCache(model.portalUser.strUserName);
}
//If the user hasn't entered a username and a password, throw a validation error.
if (!ModelState.IsValid && cachedUser == null)
{
return View(model);
}
//This will contain everything about the current user, needed to process MFA or send them on their merry way after MFA is satisfied
spReturntblEmployee portalUser = new spReturntblEmployee();
//If the user is not logged in yet, we need to try their username and password.
if (cachedUser == null)
{
//returns a non null object if they are authenticated properly
portalUser = MotorBase_Biz.Account.AuthenticateUser(model.Username, model.Password);
if (!String.IsNullOrEmpty(portalUser.strEmployeeID))
{
//successfully authenticated, set our session variable for Employee ID
Session["EmpID"] = portalUser.strEmployeeID;
//Clean up our user table, used for licensing products in the suite and IP security.
List<SqlParameter> nvcParams = new List<SqlParameter>();
nvcParams.Add(new SqlParameter("strEmployeeID", portalUser.strEmployeeID));
var gUtils = new MotorBase_Biz.generalUtils();
// Old records can go, as can ours from a previous login. This table only ever contains active users.
bool result = gUtils.ExecuteNonQuery("Delete from tblzWebUser Where dtmLastActivity < DATEADD(HOUR, -1, GETDATE()) Or strEmpID = @strEmployeeID", nvcParams, CommandType.Text);
//Set our authentication cookie so the site considers the user authenticated.
FormsAuthentication.SetAuthCookie(portalUser.strUserName, false);
gUtils.logger("** authenticated username: " + portalUser.strUserName);
//assign the web roles to the user. These roles determine access to parts of the menu/site.
var UserRoles = MotorBase_Biz.generalUtils.GetRolesForUser(portalUser.strUserName);
portalUser.userRoles = UserRoles;
portalUser.strWebStartPage = "/About/MyProfile";
//We use the session id to detect concurrent logins from different sessions.
portalUser.strSessionId = Session.SessionID;
//add this user to cache. We can retrieve it from there, if we need any of these properties for site operations
MotorBase_Biz.Account.AddUserToCache(portalUser);
}
}
else if (cachedUser != null)
{
portalUser = cachedUser;//grab the user from cache. They are already authenticated. We use this variable for MFA below
}
if (!String.IsNullOrEmpty(portalUser.strEmployeeID))
{
//If we already triggered MFA, we are waiting on a code and don't need to trigger again. (MFAStates.WaitOnCode)
//Has this user opted in? If so, is it time to trigger? If they previously indicated to be remembered for 60 days we want to account for that.
int CheckTriggerMFA = MotorBase_Biz.Account.CheckTriggerMFA(portalUser.strEmployeeID, portalUser.strUserName);
if (CheckTriggerMFA == 0 || (String.IsNullOrEmpty(portalUser.strMFAMethod1) && String.IsNullOrEmpty(portalUser.strMFAMethod2)))
{
//If user opted out, or has no method stored we can forgo MFA
model.mfaState = MFAStates.NoMFA;
}
else if (CheckTriggerMFA == 1 && model.mfaState != MFAStates.WaitOnCode)
{
//If the portal user has only one MFA method, no need to stop and ask. Just send the code.
if ((!String.IsNullOrEmpty(portalUser.strMFAMethod1) && String.IsNullOrEmpty(portalUser.strMFAMethod2)) || (String.IsNullOrEmpty(portalUser.strMFAMethod1) && !String.IsNullOrEmpty(portalUser.strMFAMethod2)))
{
var strCurrentMFAMethod = (String.IsNullOrEmpty(portalUser.strMFAMethod1) ? portalUser.strMFAMethod2 : portalUser.strMFAMethod1);
if (!String.IsNullOrEmpty(strCurrentMFAMethod))
{
model.strCurrentMFA = strCurrentMFAMethod;
//We need to generate our code and send it to the method specified
string MFACode = GetMFACode();
model.portalUser = portalUser;
if (MFACode != "")
{
model.MFACode = MFACode;
portalUser.strCurrentMFA = model.strCurrentMFA;
portalUser.strSessionId = Session.SessionID;
MotorBase_Biz.Account.AddSecurityAuth(model.portalUser, MFACode);
bool codeSendResult = SendMFACode(MFACode, model.strCurrentMFA);
if (!codeSendResult)
{
ViewBag.MFAResult = "We are sorry, there has been an error attempting to send your code. Please try another method, or again later.";
model.mfaState = MFAStates.TriggerMFA;
}
else
model.mfaState = MFAStates.WaitOnCode;
//The UI lets the user know the code has been sent and presents a place to enter this code.
return View("Login",model);
}
}
}
//If the user has opted in and we aren't yet awaiting a code, we need to trigger the code send
model.mfaState = MFAStates.TriggerMFA;
} //Waiting on a code but having a value in strCurrentMFA but no value in the MFA Code yet means the user has chosen a method to send the code
else if (model.mfaState == MFAStates.WaitOnCode && !String.IsNullOrEmpty(model.strCurrentMFA) && String.IsNullOrEmpty(model.MFACode))
{
//We need to generate our code and send it to the method specified
string MFACode = GetMFACode();
model.portalUser = portalUser;
if (MFACode != "")
{
model.MFACode = MFACode;
portalUser.strCurrentMFA = model.strCurrentMFA;
portalUser.strSessionId = Session.SessionID;
MotorBase_Biz.Account.AddSecurityAuth(model.portalUser, MFACode);
bool codeSendResult = SendMFACode(MFACode, model.strCurrentMFA);
if (!codeSendResult)
{
ViewBag.MFAResult = "We are sorry, there has been an error attempting to send your code. Please try again later.";
model.mfaState = MFAStates.TriggerMFA;
}
else
model.mfaState = MFAStates.WaitOnCode;
//The UI lets the user know the code has been sent and presents a place to enter this code.
//The UI lets the user know the code has been sent and presents a place to enter this code.
return View("Login", model);
}
}
//If we are waiting on a code, the code exists, as does the current MFA method, the user had entered a code and we need to validate it
else if (model.mfaState == MFAStates.WaitOnCode && !String.IsNullOrEmpty(model.strCurrentMFA) && !String.IsNullOrEmpty(model.MFACode))
{
//Checks tblSecurityAuth to validate the code. Can't be older than 15 minutes and has to match exactly. If more than one was triggered, only the last one works
int authID = MotorBase_Biz.Account.CheckMFACode(model.strCurrentMFA, model.MFACode, model.Username);
if (authID == 0)
{
ViewBag.MFAResult = "Incorrect or expired code. Please send and use another code.";
model.mfaState = MFAStates.TriggerMFA;
model.portalUser = portalUser;
return View(model);
}
else
{
//Update tblSecurityAuth with our login date and time.
MotorBase_Biz.Account.UpdateMFACode(authID, portalUser.denyRoleID);
model.mfaState = MFAStates.MFASatisfied;
//If the user indicated we to remember for 60 days, we need to set that value.
if (model.ysnRememberMFA)
{
portalUser.ysnRememberMFA = true;
MotorBase_Biz.Account.UpdateMFARemember(portalUser);
}
}
}
//If this user has MFA turned on, now that they have authenticated let's require the code.
if (model.mfaState != MFAStates.MFASatisfied && model.mfaState != MFAStates.NoMFA && portalUser.ysnMFAOptIn)
{
model.mfaState = MFAStates.TriggerMFA;
model.portalUser = portalUser;
return View("Login", model);
}
else
{
//Authentication and MFA is satisfied!
//These are items we will handle as part of our cached object when we can carry out clean up
string redirectNow = SetSessionValuesForUser(portalUser);
if (String.IsNullOrEmpty(redirectNow))
redirectNow = "/Report/Dashboard";
if (Session["ReturnUrl"] == null)
Session["ReturnUrl"] = "";
if (String.IsNullOrEmpty(Session["ReturnUrl"].ToString()))
{
if (portalUser.strPassword == "123")
{
//The user still has the default password. Need to request that they change it.
Session["ChangePasswordNow"] = "1";
}
portalUser.strWebStartPage = redirectNow;
return Redirect(portalUser.strWebStartPage);
}
else
{
return Redirect(Session["ReturnUrl"].ToString());//They could be using a bookmark or a QR code
}
}
}
else
{
ModelState.AddModelError("", "Invalid username or password. Please try again");
return View(model);
}
}Editor is loading...
Leave a Comment