public async Task <TwoFactorResponseModel> PutTwoFactorRegenerate([FromBody] RegenerateTwoFactorRequestModel model) { var user = await _userService.GetUserByPrincipalAsync(User); if (!await _userManager.CheckPasswordAsync(user, model.MasterPasswordHash)) { await Task.Delay(2000); throw new BadRequestException("MasterPasswordHash", "Invalid password."); } if (!await _userManager.VerifyTwoFactorTokenAsync(user, TwoFactorProviderType.Authenticator.ToString(), model.Token)) { await Task.Delay(2000); throw new BadRequestException("Token", "Invalid token."); } if (user.TwoFactorEnabled) { user.TwoFactorRecoveryCode = Guid.NewGuid().ToString("N"); await _userService.SaveUserAsync(user); } var response = new TwoFactorResponseModel(user); return(response); }
public async Task <TwoFactorResponseModel> PutTwoFactor([FromBody] UpdateTwoFactorRequestModel model) { var user = _currentContext.User; if (!await _userManager.CheckPasswordAsync(user, model.MasterPasswordHash)) { await Task.Delay(2000); throw new BadRequestException("MasterPasswordHash", "Invalid password."); } if (model.Enabled.Value && !await _userManager.VerifyTwoFactorTokenAsync(user, "Authenticator", model.Token)) { await Task.Delay(2000); throw new BadRequestException("Token", "Invalid token."); } user.TwoFactorProvider = TwoFactorProvider.Authenticator; user.TwoFactorEnabled = model.Enabled.Value; await _userService.SaveUserAsync(user); var response = new TwoFactorResponseModel(user); return(response); }
public async Task <TwoFactorResponseModel> GetTwoFactor(string masterPasswordHash, TwoFactorProviderType provider) { var user = await _userService.GetUserByPrincipalAsync(User); if (!await _userManager.CheckPasswordAsync(user, masterPasswordHash)) { await Task.Delay(2000); throw new BadRequestException("MasterPasswordHash", "Invalid password."); } await _userService.GetTwoFactorAsync(user, provider); var response = new TwoFactorResponseModel(user); return(response); }
public async Task <TwoFactorResponseModel> ValidateTwoFactorCodeAsync(string code) { // Initially setting this to Fail var response = new TwoFactorResponseModel { Code = string.Empty, Email = string.Empty, IsValid = false, RememberDevice = false, ResponseMessage = new ResponseStatusInfoModel { Message = "Code-InValid", StatusCode = HttpStatusCode.Unauthorized } }; try { string twoFactorToken = _httpContextAccessor.HttpContext.Request.Headers["twoFactorToken"]; var loggedInUserId = GetLoggedInUserId(); var user = await _userManager.FindByIdAsync(loggedInUserId); if (user != null && twoFactorToken != null && !string.IsNullOrEmpty(code)) { var userResult = await _db.TwoFactorCodes.Where(x => x.UserId == user.Id && x.CodeExpired == false && x.ExpiryDate > DateTime.UtcNow && !x.CodeIsUsed && x.Attempts <= 3).FirstOrDefaultAsync(); if (userResult != null) { // Check Code attempts if (userResult.TwoFactorCode != code) { userResult.Attempts -= 1; _db.Update(userResult); await _db.SaveChangesAsync(); response.Attempts = userResult.Attempts; _cookieSvc.SetCookie("user_id", EncryptData <string>(loggedInUserId, _dataProtectionKeys.ApplicationUserKey), Convert.ToInt32(userResult.ExpiryDate.Subtract(DateTime.UtcNow).TotalMinutes)); if (userResult.Attempts == 0) { await using var dbContextTransaction = await _db.Database.BeginTransactionAsync(); user.LockoutEnabled = true; _db.Entry(user).State = EntityState.Modified; await _db.SaveChangesAsync(); await dbContextTransaction.CommitAsync(); } return(response); } var decryptedTwoFactorToken = DecryptData(twoFactorToken, userResult.EncryptionKey2Fa); if (decryptedTwoFactorToken == userResult.Token) { // Before sending true we need to set the code as Expired // reset the two-factor again userResult.CodeExpired = true; userResult.CodeIsUsed = true; response.Code = userResult.TwoFactorCode; response.Email = user.Email; response.IsValid = true; response.RememberDevice = false; response.ResponseMessage = new ResponseStatusInfoModel { Message = "Code-Valid", StatusCode = HttpStatusCode.OK }; return(response); } } } } catch (Exception ex) { Log.Error("An error occurred at ValidateTwoFactorAsync {Error} {StackTrace} {InnerException} {Source}", ex.Message, ex.StackTrace, ex.InnerException, ex.Source); } return(response); }
public async Task <TwoFactorResponseModel> SendTwoFactorAsync(TwoFactorRequestModel model) { var twoFactorResponse = new TwoFactorResponseModel(); var result = new TwoFactorCodeModel(); try { var protectorProvider = _provider.GetService <IDataProtectionProvider>(); var userIdFromHeader = _httpContextAccessor.HttpContext.Request.Headers["user_id"]; var twoFactorToken = model.TwoFactorToken; // If two factor token is null we dont want to further execute this method if (!string.IsNullOrEmpty(twoFactorToken) && !string.IsNullOrEmpty(userIdFromHeader)) { var userId = DecryptData(userIdFromHeader, _dataProtectionKeys.ApplicationUserKey).ToString(); // First find user with that Id id two-factor Table // If user was found, check if the token is valid or expired var userResult = await _db.TwoFactorCodes.Where(x => x.UserId == userId && x.CodeExpired == false && x.CodeIsUsed == false && x.ExpiryDate > DateTime.UtcNow).FirstOrDefaultAsync(); if (userResult != null) { // Decrypted Two-Factor-Token from request var protector = protectorProvider.CreateProtector(userResult.EncryptionKey2Fa); var decryptedTwoFactorToken = protector.Unprotect(twoFactorToken); // Get the Application User var appUser = await _userManager.FindByIdAsync(userId); // If both the values match request vs DB if (userResult.Token != null && decryptedTwoFactorToken != null && userResult.Token == decryptedTwoFactorToken) { // check in current request if they want to remember userResult.RememberDevice = model.RememberDevice; await using var dbContextTransaction = await _db.Database.BeginTransactionAsync(); _db.Entry(userResult).State = EntityState.Modified; await _db.SaveChangesAsync(); await dbContextTransaction.CommitAsync(); twoFactorResponse.IsValid = true; twoFactorResponse.Email = appUser.Email; twoFactorResponse.Code = userResult.TwoFactorCode; twoFactorResponse.RememberDevice = userResult.RememberDevice; twoFactorResponse.ResponseMessage = new ResponseStatusInfoModel { Message = "Authentication Success", StatusCode = HttpStatusCode.OK }; protector = protectorProvider.CreateProtector(_dataProtectionKeys.ApplicationUserKey); var protectedUserId = protector.Protect(userId); _cookieSvc.SetCookie("user_id", protectedUserId, Convert.ToInt32(userResult.ExpiryDate.Subtract(DateTime.UtcNow).TotalMinutes)); return(twoFactorResponse); } } } twoFactorResponse.IsValid = false; twoFactorResponse.Email = string.Empty; twoFactorResponse.Code = string.Empty; twoFactorResponse.RememberDevice = false; twoFactorResponse.ResponseMessage = new ResponseStatusInfoModel { Message = "Authentication Failed", StatusCode = HttpStatusCode.Unauthorized }; } catch (Exception ex) { Log.Error("An error occurred at ValidateTwoFactorAsync {Error} {StackTrace} {InnerException} {Source}", ex.Message, ex.StackTrace, ex.InnerException, ex.Source); } return(twoFactorResponse); }