public void ClientEvent_OnSubmitEnableGoogleAuthCode(Client player, string code) { if (!player.IsLoggedIn(true)) { return; } var acc = player.GetAccount(); if (acc.TempTwoFactorGASharedKey == null) { return; } if (!ValidateString(ValidationStrings.GoogleAuthenticatorCode, code)) { player.TriggerEvent(Events.ServerToClient.Authentication.DisplayError, "Must be 6 characters and only digits"); return; } if (GoogleAuthenticator.GeneratePin(acc.TempTwoFactorGASharedKey) != code) { player.TriggerEvent(Events.ServerToClient.Authentication.DisplayError, "Wrong code try again"); return; } acc.TwoFactorGASharedKey = acc.TempTwoFactorGASharedKey; TaskManager.Run(player, async() => await acc.UpdateAsync()); player.TriggerEvent(Events.ServerToClient.Authentication.ShowQRCodeEnabled); }
public ActionResult SecondFactor(SecondFactorModel model, string returnUrl) { var user = TempData[CurrentUserTempDataKey] as MvcTFAProfile; TempData.Keep(); if (user != null) { var secretKey = Base32Encoder.FromBase32String(user.SecretKey); var currentInterval = GoogleAuthenticator.CurrentInterval; var secondFactorMatched = false; // The currentInterval +- 1 has been added to allow for devices which are slightly out of sync // to connect still, this does decrease the security of the application slightly but I feel that // the modification is an acceptable usability/security compromise. if (GoogleAuthenticator.GeneratePin(secretKey, currentInterval) == model.SecondFactor) { secondFactorMatched = true; } else if (GoogleAuthenticator.GeneratePin(secretKey, currentInterval + 1) == model.SecondFactor) { secondFactorMatched = true; } else if (GoogleAuthenticator.GeneratePin(secretKey, currentInterval - 1) == model.SecondFactor) { secondFactorMatched = true; } if (secondFactorMatched) { var rememberMe = TempData[RememberMeTempDataKey] != null && (bool)TempData[RememberMeTempDataKey]; FormsAuthentication.SetAuthCookie(user.UserName, rememberMe); return(RedirectToLocal(returnUrl)); } ModelState.AddModelError("SecondFactor", "The one time password you speccified is incorrect"); } else { ModelState.AddModelError("", "A problem occurred while retrieving your session"); } return(View(model)); }
public void ClientEvent_OnSubmitGoogleAuthCode(Client client, string token) { var accountData = client.GetAccount(); if (!client.IsLoggedIn(true)) { client.TriggerEvent(Events.ServerToClient.Authentication.DisplayError, AccountStrings.ErrorPlayerNotLoggedIn); return; } if (!ValidateString(ValidationStrings.GoogleAuthenticatorCode, token)) { client.TriggerEvent(Events.ServerToClient.Authentication.DisplayError, "Must be 6 characters and only digits"); return; } if (!accountData.HasVerifiedEmail()) { throw new Exception("Tried to verify Two-Step by GA when user has no email set"); // Dummy check } if (!accountData.Is2FAbyGAEnabled()) { client.TriggerEvent(Events.ServerToClient.Authentication.DisplayError, "Two Step auth by GA is not enabled for this account."); return; } if (GoogleAuthenticator.GeneratePin(accountData.TwoFactorGASharedKey) != token) { client.TriggerEvent(Events.ServerToClient.Authentication.DisplayError, "Wrong 2FA code, try again"); return; } accountData.HasPassedTwoStepByGA = true; if (accountData.Is2FAbyEmailEnabled() && !accountData.HasPassedTwoStepByEmail) { client.TriggerEvent(Events.ServerToClient.Authentication.Show2FAbyEmailAddress); return; } SetLoginState(client, false); }
public async Task <ActionResult> Authenticator(AuthenticatorViewModel model, string returnUrl) { if (!ModelState.IsValid) { return(View(model)); } var loginViewModel = TempData.Peek("LoginAuthenticatorViewModel") as LoginAuthenticatorViewModel; if (loginViewModel == null) { return(RedirectToAction("Login")); } //var secretKey = Base32Encoder.FromBase32String(SecretKey); var secretKey = Base32Encoder.FromBase32String(loginViewModel.AuthenticatorSecrete); var currentInterval = GoogleAuthenticator.CurrentInterval; if (GoogleAuthenticator.GeneratePin(secretKey, currentInterval) == model.Factor) { // This doesn't count login failures towards account lockout // To enable password failures to trigger account lockout, change to shouldLockout: true var result = await SignInManager.PasswordSignInAsync(loginViewModel.Email, loginViewModel.Password, loginViewModel.RememberMe, false); switch (result) { case SignInStatus.Success: { TempData.Remove("LoginViewModel"); return(RedirectToLocal(returnUrl)); } case SignInStatus.LockedOut: { TempData.Remove("LoginViewModel"); return(View("Lockout")); } case SignInStatus.RequiresVerification: { TempData.Remove("LoginViewModel"); return(RedirectToAction("SendCode", new { ReturnUrl = returnUrl, loginViewModel.RememberMe })); } case SignInStatus.Failure: default: { ModelState.AddModelError("", "Invalid authenticator attempt."); return(View(model)); } } } ModelState.AddModelError("", "Invalid authenticator attempt."); return(View(model)); }