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);
        }
Beispiel #2
0
        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);
        }
Beispiel #4
0
        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));
        }