MakeAssertionAsync(AnonymousAuthenticatorAssertionRawResponse clientResponse, string deviceName) { try { // 1. Get the assertion options we sent the client if (string.IsNullOrWhiteSpace(clientResponse.RequestId)) { _logger.LogError("Attempted to make assertion without request id"); return(Result.Failure <(User, string, string), (bool, string)>((false, "No user id or request id provided"))); } var cacheKey = $"AssertionOptions:{clientResponse.RequestId}"; if (!_cache.TryGetValue(cacheKey, out AssertionOptions options)) { _logger.LogError($"Failed to find assertion options for key '{cacheKey}'"); return(Result.Failure <(User, string, string), (bool, string)>((true, "No assertion found"))); } _cache.Remove(cacheKey); // 2. Get registered credential from database var authorization = await _db.DeviceAuthorizations .Include(x => x.User) //todo In .net 5, ef-core 5 will support using SequenceEqual, for now we'll use normal equality and just remember that it will be properly translated into sql for real databases, see https://github.com/dotnet/efcore/issues/10582 //.FirstOrDefaultAsync(x => x.CredentialId.SequenceEqual(clientResponse.Id)); .FirstOrDefaultAsync(x => x.CredentialId == clientResponse.Id); if (authorization is null) { _logger.LogError("Failed to find credentials"); return(Result.Failure <(User, string, string), (bool, string)>((true, "No credentials found"))); } // 3. Make the assertion var avr = await _fido2.MakeAssertionAsync(clientResponse, options, authorization.PublicKey, authorization.SignatureCounter, x => Task.FromResult(true)); // 4. Store the updated counter authorization.SignatureCounter = avr.Counter; var login = _userService.GenerateAndSaveLogin(authorization.User, deviceName, authorization.Id); return(Result.Success <(User user, string accessToken, string refreshToken), (bool unauthorized, string message)>(login)); } catch (Exception e) { _logger.LogError(e, "Failed to make assertion for user"); return(Result.Failure <(User, string, string), (bool, string)>((false, "Error making assertion"))); } }
public async Task <IActionResult> CompleteDeviceAssertion([FromBody] AnonymousAuthenticatorAssertionRawResponse response) { var(_, isFailure, (user, accessToken, refreshToken), (unauthorized, errorMessage)) = await _webAuthnService.MakeAssertionAsync(response, Request.GetDeviceName()); if (!isFailure) { return(Ok(new AuthenticatedUser(user, accessToken, refreshToken))); } if (unauthorized) { return(Unauthorized()); } return(BadRequest(errorMessage)); }