public async Task <AccountRecoveryResult> RecoverAsync(string accountRecoveryPayload) { var payload = OwnIdSerializer.Deserialize <RecoveryPayload>(accountRecoveryPayload); if (string.IsNullOrEmpty(payload?.OobCode) || string.IsNullOrEmpty(payload.ApiKey)) { throw new ArgumentException("Recovery code api key cannot be null", nameof(accountRecoveryPayload)); } var url = $"https://identitytoolkit.googleapis.com/v1/accounts:resetPassword?key={payload.ApiKey}"; var httpResult = await _httpClient.PostAsJsonAsync(url, new { oobCode = payload.OobCode, newPassword = _randomPasswordProvider.Generate() }); var result = await httpResult.Content.ReadFromJsonAsync <RecoverPasswordResponse>( OwnIdSerializer.GetDefaultProperties()); if (!string.IsNullOrEmpty(result?.Error?.Message)) { if (result.Error.Message == "EXPIRED_OOB_CODE") { throw new OwnIdException(ErrorType.RecoveryTokenExpired); } throw new Exception($"Firebase REST -> {result.Error.Code}: {result.Error.Message}"); } var user = await _firebaseContext.Auth.GetUserByEmailAsync(result !.Email); return(new AccountRecoveryResult { DID = user.Uid }); }
public IFormContext CreateUserDefinedContext(UserProfileData profileData, ILocalizationService localizationService) { return(new UserProfileFormContext <TProfile>(profileData.DID, profileData.PublicKey, OwnIdSerializer.Deserialize <TProfile>(profileData.Profile?.GetRawText(), _serializerOptions), localizationService)); }
public async Task InvokeAsync(HttpContext context) { using var reader = new StreamReader(context.Request.Body); var bodyString = await reader.ReadToEndAsync(); if (string.IsNullOrEmpty(bodyString)) { return; } var logMessage = OwnIdSerializer.Deserialize <LogMessage>(bodyString); using (LogContext.Push(new PropertyEnricher("source", logMessage.Source ?? "client-side"))) using (LogContext.Push(new PropertyEnricher("version", logMessage.Version))) { if (!Enum.TryParse(logMessage.LogLevel, true, out LogLevel logLevel)) { logLevel = LogLevel.Debug; } using (_logger.BeginScope($"context: {context}", logMessage.Context)) { _logger.LogWithData(logLevel, logMessage.Message, logMessage.Data); } } }
public async Task <CacheItem> ExecuteAsync(string fido2Payload, CacheItem relatedItem) { var request = OwnIdSerializer.Deserialize <Fido2LoginRequest>(fido2Payload); var storedFido2Info = await _userHandlerAdapter.FindFido2InfoAsync(request.CredentialId); if (storedFido2Info == null) { throw new OwnIdException(ErrorType.UserNotFound); } var options = new AssertionOptions { Challenge = Encoding.ASCII.GetBytes(relatedItem.Context), RpId = _configuration.Fido2.RelyingPartyId }; var fidoResponse = new AuthenticatorAssertionRawResponse { Extensions = new AuthenticationExtensionsClientOutputs(), Id = Base64Url.Decode(request.CredentialId), RawId = Base64Url.Decode(request.CredentialId), Response = new AuthenticatorAssertionRawResponse.AssertionResponse { AuthenticatorData = Base64Url.Decode(request.AuthenticatorData), ClientDataJson = Base64Url.Decode(request.ClientDataJson), Signature = Base64Url.Decode(request.Signature), UserHandle = Base64Url.Decode(storedFido2Info.UserId) }, Type = PublicKeyCredentialType.PublicKey }; var result = await _fido2.MakeAssertionAsync( fidoResponse, options, Base64Url.Decode(storedFido2Info.PublicKey), storedFido2Info.SignatureCounter, args => { var storedCredentialId = Base64Url.Decode(storedFido2Info.CredentialId); var storedCredDescriptor = new PublicKeyCredentialDescriptor(storedCredentialId); var credIdValidationResult = storedCredDescriptor.Id.SequenceEqual(args.CredentialId); return(Task.FromResult(credIdValidationResult)); }); return(await _cacheItemRepository.UpdateAsync(relatedItem.Context, item => { item.PublicKey = storedFido2Info.PublicKey; item.Fido2SignatureCounter = result.Counter; item.Fido2CredentialId = request.CredentialId; item.FinishFlow(storedFido2Info.UserId, storedFido2Info.PublicKey); })); }
public async Task <CacheItem> ExecuteAsync(string fido2Payload, CacheItem relatedItem) { var request = OwnIdSerializer.Deserialize <Fido2RegisterRequest>(fido2Payload); if (string.IsNullOrWhiteSpace(request.AttestationObject)) { throw new CommandValidationException("Incorrect Fido2 register request: AttestationObject is missing"); } if (string.IsNullOrWhiteSpace(request.ClientDataJson)) { throw new CommandValidationException("Incorrect Fido2 register request: ClientDataJson is missing"); } var fido2Response = new AuthenticatorAttestationRawResponse { Id = _encodingService.Base64UrlDecode(NewUserId), RawId = _encodingService.Base64UrlDecode(NewUserId), Type = PublicKeyCredentialType.PublicKey, Response = new AuthenticatorAttestationRawResponse.ResponseData { AttestationObject = _encodingService.Base64UrlDecode(request.AttestationObject), ClientDataJson = _encodingService.Base64UrlDecode(request.ClientDataJson) } }; var options = new CredentialCreateOptions { Challenge = _encodingService.ASCIIDecode(relatedItem.Context), Rp = new PublicKeyCredentialRpEntity( _configuration.Fido2.RelyingPartyId, _configuration.Fido2.RelyingPartyName, null), User = new Fido2User { DisplayName = _configuration.Fido2.UserDisplayName, Name = _configuration.Fido2.UserName, Id = _encodingService.Base64UrlDecode(NewUserId) } }; var result = await _fido2.MakeNewCredentialAsync(fido2Response, options, args => Task.FromResult(true)); if (result == null) { throw new InternalLogicException("Cannot verify fido2 register request"); } var publicKey = _encodingService.Base64UrlEncode(result.Result.PublicKey); return(await ProcessFido2RegisterResponseAsync(relatedItem, publicKey, result.Result.Counter, _encodingService.Base64UrlEncode(result.Result.CredentialId))); }
public async Task <CacheItem> GetAsync(string key) { var compKey = GetCustomerKey(key); var item = await _redisDb.StringGetAsync(compKey); if (item.IsNullOrEmpty) { return(null); } _logger.Log(LogLevel.Debug, () => $"get(key -> '{compKey}') -> Response: '{item.ToString()}'"); return(OwnIdSerializer.Deserialize <CacheItem>(item.ToString())); }
public CacheItem Get(string key) { var compKey = GetCustomerKey(key); var item = _redisDb.StringGet($"{_keyPrefix}{key}"); if (item.IsNullOrEmpty) { return(null); } _logger.Log(LogLevel.Debug, () => $"get(key -> '{compKey}') -> Response: '{item.ToString()}'"); return(OwnIdSerializer.Deserialize <CacheItem>(item.ToString())); }
public async Task <AccountRecoveryResult> RecoverAsync(string accountRecoveryPayload) { var payload = OwnIdSerializer.Deserialize <GigyaAccountRecoveryPayload>(accountRecoveryPayload); var newPassword = _randomPasswordProvider.Generate(); var resetPasswordResponse = await _apiClient.ResetPasswordAsync(payload.ResetToken, newPassword); if (resetPasswordResponse.ErrorCode != 0) { throw new OwnIdException(ErrorType.RecoveryTokenExpired, resetPasswordResponse.ErrorDetails); } return(new AccountRecoveryResult { DID = resetPasswordResponse.UID }); }
public async Task <LinkState> GetCurrentUserLinkStateAsync(string payload) { var jwt = OwnIdSerializer.Deserialize <JwtContainer>(payload)?.Jwt; if (string.IsNullOrEmpty(jwt)) { throw new Exception("No JWT was found in HttpRequest"); } var decodedToken = await _firebaseContext.Auth.VerifyIdTokenAsync(jwt); var did = decodedToken.Uid; var connections = await _firebaseContext.Db.Collection(Constants.CollectionName) .WhereEqualTo(Constants.UserIdFieldName, did).GetSnapshotAsync(); return(new LinkState(did, (uint)connections.Count)); }
public async Task <LinkState> GetCurrentUserLinkStateAsync(string payload) { var jwt = OwnIdSerializer.Deserialize <JwtContainer>(payload)?.Jwt; if (string.IsNullOrEmpty(jwt)) { throw new Exception("No JWT was found in HttpRequest"); } var tokenHandler = new JwtSecurityTokenHandler(); if (!tokenHandler.CanReadToken(jwt)) { throw new Exception("Invalid jwt"); } var rsaSecurityKey = await _restApiClient.GetPublicKey(); try { tokenHandler.ValidateToken(jwt, new TokenValidationParameters { IssuerSigningKey = rsaSecurityKey, RequireSignedTokens = true, RequireExpirationTime = true, ValidateIssuerSigningKey = true, ValidateLifetime = true, ValidateAudience = false, ValidateIssuer = false // TODO: add issuer to token for validation }, out _); } catch (SecurityTokenValidationException ex) { throw new Exception($"Token failed validation: {ex.Message}"); } catch (ArgumentException ex) { throw new Exception($"Token was invalid: {ex.Message}"); } var token = tokenHandler.ReadJwtToken(jwt); if (!token.Payload.ContainsKey(ApiKeyPayloadKey) || (string)token.Payload[ApiKeyPayloadKey] != _configuration.ApiKey) { throw new Exception("Jwt was created for different apiKey"); } var did = token.Subject; var accountInfo = await _restApiClient.SearchAsync <AccountInfoResponse <TProfile> >(GigyaFields.UID, did); if (!accountInfo.IsSuccess) { if (accountInfo.ErrorCode != 0) { throw new Exception(accountInfo.GetFailureMessage()); } throw new Exception($"Can't find user with did = {did}"); } return(new LinkState(did, (uint)(accountInfo.First.Data?.OwnId?.Connections?.Count ?? 0))); }
public async Task <FrontendBehavior> ExecuteAsync(CacheItem cacheItem, string routingPayload) { if (!_coreConfiguration.Fido2.IsEnabled) { return(null); } // If this is second attempt to call same start endpoint if (cacheItem.FlowType == FlowType.Fido2Login || cacheItem.FlowType == FlowType.Fido2Register || cacheItem.FlowType == FlowType.Fido2Link || cacheItem.FlowType == FlowType.Fido2LinkWithPin || cacheItem.FlowType == FlowType.Fido2Recover || cacheItem.FlowType == FlowType.Fido2RecoverWithPin) { return(null); } // Not supported for Fido2 flows if (cacheItem.FlowType != FlowType.PartialAuthorize && cacheItem.FlowType != FlowType.Link && cacheItem.FlowType != FlowType.Recover && cacheItem.FlowType != FlowType.LinkWithPin && cacheItem.FlowType != FlowType.RecoverWithPin) { return(null); } if (string.IsNullOrEmpty(routingPayload)) { return(null); } var routing = OwnIdSerializer.Deserialize <ExtAuthenticationRouting>(routingPayload); if (routing.Authenticator != ExtAuthenticatorType.Fido2) { return(null); } if (!string.IsNullOrEmpty(routing.Error)) { _logger.LogError($"Found error in FIDO2 ExtAuthenticationRouting object: {routing.Error}"); return(null); } var initialFlowType = cacheItem.FlowType; var initialChallengeType = cacheItem.ChallengeType; switch (routing.Type) { case "l": { if (cacheItem.FlowType == FlowType.PartialAuthorize) { cacheItem.FlowType = FlowType.Fido2Login; } break; } case "r": cacheItem.FlowType = cacheItem.FlowType switch { FlowType.PartialAuthorize => FlowType.Fido2Register, FlowType.Link => FlowType.Fido2Link, FlowType.LinkWithPin => FlowType.Fido2LinkWithPin, FlowType.Recover => FlowType.Fido2Recover, FlowType.RecoverWithPin => FlowType.Fido2RecoverWithPin, _ => cacheItem.FlowType }; if (cacheItem.FlowType == FlowType.Fido2Register) { cacheItem.ChallengeType = ChallengeType.Register; } break; default: throw new InternalLogicException($"Incorrect fido2 request: '{routing.Type}'"); } if (initialFlowType == cacheItem.FlowType) { return(null); } await _cacheItemRepository.UpdateAsync(cacheItem.Context, item => { item.FlowType = cacheItem.FlowType; item.ChallengeType = cacheItem.ChallengeType; }); if (_eventsMetricsService != null && initialChallengeType != cacheItem.ChallengeType) { _eventsMetricsService?.LogSwitchAsync(initialChallengeType.ToEventType()); _eventsMetricsService?.LogStartAsync(cacheItem.ChallengeType.ToEventType()); } // TODO: rework to exclude explicit url creation return(new FrontendBehavior(StepType.Fido2Authorize, cacheItem.ChallengeType, new CallAction(_urlProvider.GetChallengeUrl(cacheItem.Context, ChallengeType.Register, "/fido2")))); }