public async Task <IActionResult> EnableAuthenticator(EnableAuthenticatorViewModel model) { if (!ModelState.IsValid) { return(View(model)); } var id = User?.FindFirstValue("sub"); string accessToken = await GetAccessToken(); EnableAuthenticator contentModel = new EnableAuthenticator { Id = id, AuthenticatorUri = model.AuthenticatorUri, Code = model.Code, SharedKey = model.SharedKey, }; string asJson = JsonSerializer.Serialize <EnableAuthenticator>(contentModel); StringContent content = new StringContent(asJson, Encoding.UTF8, "application/json"); HttpClient client = _httpClientFactory.CreateClient("IdApiAccount"); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, $"{_configuration["AppURLS:IdApiBaseUrl"]}/api/v1/Account/EnableAuthenticatorAsync") { Content = content }; using HttpResponseMessage response = await client.SendAsync(request); if (!response.IsSuccessStatusCode) { string badResponse = await response.Content.ReadAsStringAsync(); ResponsePayload badResponseObj = JsonSerializer.Deserialize <ResponsePayload>(badResponse); if (badResponseObj.StatusCode == 400) { ModelState.AddModelError("Code", "Verification code is invalid. Please scan the QR Code or enter the above Verification Code Key. Then use the One-Time password code generated by the Authenticator App to verify and complete 2FA set up."); return(View(model)); } _logger.LogError("~/Account/EnableAuthenticator(EnableAuthenticatorViewModel) - Error from IdApi - {0}", badResponseObj); TempData["ErrorMessage"] = "An error occurred while setting up your account for 2 factor authentication."; return(RedirectToAction(nameof(Index))); } string responseObj = await response.Content.ReadAsStringAsync(); EnableAuthenticatorViewModel responseModel = JsonSerializer.Deserialize <EnableAuthenticatorViewModel>(responseObj); response.EnsureSuccessStatusCode(); _logger.LogInformation("User with id:{0} has enabled 2FA with an authenticator app.", id); return(View("ShowCodes", responseModel)); }
public async Task <IActionResult> LoadSharedKeyAndQrCodeUriAsync([FromBody] string userId) { ApplicationUser user; try { user = await _userManager.FindByIdAsync(userId); if (user == null) { _logger.LogError("~/Account/LoadSharedKeyAndQrCodeUriAsync(userId) - Could not find User Id:{0}. Unable to generate shared key and QR codes.", userId); return(NotFound(new ApiResponse(404, $"~/Account/LoadSharedKeyAndQrCodeUriAsync(userId) - Could not find User Id:{userId}. Unable to generate shared key and QR codes."))); } } catch (Exception ex) { _logger.LogError("UserManger encountered an error connecting to the database. Error:{0}", ex); return(StatusCode(503, new ApiResponse(503, "Error connecting to the database."))); } string unformattedKey; try { await _userManager.ResetAuthenticatorKeyAsync(user); //reset Authenticator Key - there maybe a stale Authenticator Key from previous enable/disable 2fa unformattedKey = await _userManager.GetAuthenticatorKeyAsync(user); //For some reason, calling this method without calling ResetAuthenticatorKeyAsync first, returns null. Find time to understand why. if (String.IsNullOrWhiteSpace(unformattedKey)) { _logger.LogError("~/Account/LoadSharedKeyAndQrCodeUriAsync(userId) - _userManager encountered an error Getting Authenticator Key Async."); return(StatusCode(500, new ApiResponse(500, "An internal error occurred enabling Multi-Factor Authentication."))); } } catch (Exception ex) { _logger.LogError("~/Account/LoadSharedKeyAndQrCodeUriAsync(userId) - UserManger encountered an error connecting to the database. Error:{0}", ex); return(StatusCode(503, new ApiResponse(503, "Error connecting to the database."))); } EnableAuthenticator responseObj = new EnableAuthenticator { SharedKey = FormatKey(unformattedKey), AuthenticatorUri = GenerateQrCodeUri(user.Email, unformattedKey), }; string response = JsonSerializer.Serialize <EnableAuthenticator>(responseObj); return(Ok(response)); }
internal async Task <Index> Send2FACodeAsync(string twoFactorKey) { var code = EnableAuthenticator.ComputeCode(twoFactorKey); var response = await Client.SendAsync(_twoFactorForm, new Dictionary <string, string> { ["Input_TwoFactorCode"] = code }); var goToIndex = ResponseAssert.IsRedirect(response); Assert.Equal(Index.Path, goToIndex.ToString()); var indexResponse = await Client.GetAsync(goToIndex); var index = await ResponseAssert.IsHtmlDocumentAsync(indexResponse); return(new Index(Client, index, Context.WithAuthenticatedUser())); }
public async Task <IActionResult> EnableAuthenticatorAsync([FromBody] EnableAuthenticator model) { ApplicationUser user; try { user = await _userManager.FindByIdAsync(model.Id); if (user == null) { _logger.LogError("~/Account/EnableAuthenticatorAsync(EnableAuthenticator) - Could not find User Id:{0}. Unable to generate shared key and QR codes.", model.Id); return(NotFound(new ApiResponse(404, $"~/Account/EnableAuthenticatorAsync(EnableAuthenticator) - Could not find User Id:{model.Id}. Unable to generate shared key and QR codes."))); } } catch (Exception ex) { _logger.LogError("UserManger encountered an error connecting to the database. Error:{0}", ex); return(StatusCode(503, new ApiResponse(503, "Error connecting to the database."))); } try { //Clean any whitespace in model.Code string verificationCode = model.Code.Replace(" ", string.Empty).Replace("-", string.Empty); bool is2faTokenValid = await _userManager.VerifyTwoFactorTokenAsync(user, _userManager.Options.Tokens.AuthenticatorTokenProvider, verificationCode); if (!is2faTokenValid) { return(StatusCode(400, new ApiResponse(400, "Verification code is invalid. Please scan the QR Code or enter the above Verification Code Key. Then use the One-Time password code generated by the Authenticator App to verify and complete 2FA set up."))); } } catch (Exception ex) { _logger.LogError("UserManger encountered an error connecting to the database. Error:{0}", ex); return(StatusCode(503, new ApiResponse(503, "Error connecting to the database."))); } try { IdentityResult TwoFactorResult = await _userManager.SetTwoFactorEnabledAsync(user, true); if (!TwoFactorResult.Succeeded) { string errors = BuildErrorString(TwoFactorResult); _logger.LogError("~/Account/EnableAuthenticator(EnableAuthenticatorViewModel) - userManager could not SetTwoFactorEnabledAsync for id:{0}'s account. Error:{1}", model.Id, errors); return(StatusCode(500, new ApiResponse(500, "An error occurred setting 2FA for your account."))); } } catch (Exception ex) { _logger.LogError("UserManger encountered an error connecting to the database. Error:{0}", ex); return(StatusCode(503, new ApiResponse(503, "Error connecting to the database."))); } IEnumerable <string> recoveryCodes; try { recoveryCodes = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 10); if (!recoveryCodes.Any()) { _logger.LogError("~/Account/EnableAuthenticator(EnableAuthenticatorViewModel) - userManager could not GenerateNewTwoFactorRecoveryCodesAsync for id:{0}'s account.", model.Id); return(StatusCode(500, new ApiResponse(500, "An error occurred setting 2FA for your account."))); } } catch (Exception ex) { _logger.LogError("UserManger encountered an error connecting to the database. Error:{0}", ex); return(StatusCode(503, new ApiResponse(503, "Error connecting to the database."))); } EnableAuthenticator responseObj = new EnableAuthenticator { Id = user.Id, AuthenticatorUri = model.AuthenticatorUri, Code = model.Code, SharedKey = model.SharedKey, RecoveryCodes = recoveryCodes.ToArray(), }; string response = JsonSerializer.Serialize <EnableAuthenticator>(responseObj); return(Ok(response)); }