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 }); }
protected override async Task ExecuteAsync(HttpContext httpContext) { var request = await OwnIdSerializer.DeserializeAsync <ExchangeMagicLinkRequest>(httpContext.Request.Body); await JsonAsync(httpContext, await _exchangeMagicLinkCommand.ExecuteAsync(request), StatusCodes.Status200OK); }
protected override async Task ExecuteAsync(HttpContext context) { List <GetStatusRequest> request; try { request = await OwnIdSerializer.DeserializeAsync <List <GetStatusRequest> >(context.Request.Body); } catch { BadRequest(context.Response); return; } var result = await _getStatusCommand.ExecuteAsync(request); context.Response.StatusCode = StatusCodes.Status200OK; context.Response.ContentType = "application/json"; // TODO: remove after web ui sdk changes enums as strings await context.Response.WriteAsync(JsonSerializer.Serialize <object>(result, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, IgnoreNullValues = true })); // TODO: uncomment after web ui sdk changes enums as strings // await Json(context, result, StatusCodes.Status200OK, false); }
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); } } }
protected override async Task ExecuteAsync(HttpContext httpContext) { var request = await OwnIdSerializer.DeserializeAsync <ApproveActionRequest>(httpContext.Request.Body); await _approveActionCommand.ExecuteAsync(request); OkNoContent(httpContext.Response); }
protected override async Task ExecuteAsync(HttpContext httpContext) { var request = await OwnIdSerializer.DeserializeAsync <GenerateContextRequest>(httpContext.Request.Body); var result = await _createFlowCommand.ExecuteAsync(request); await JsonAsync(httpContext, result, StatusCodes.Status200OK, false); }
public async Task Invoke(HttpContext context) { var config = await OwnIdSerializer.DeserializeAsync <ConfigToInject>(context.Request.Body); _configuration.TFAEnabled = config.TFAEnabled; _configuration.Fido2FallbackBehavior = config.Fido2FallbackBehavior; context.Response.StatusCode = StatusCodes.Status204NoContent; }
public static IList <KeyValuePair <string, string> > AddParameter <T>( this IList <KeyValuePair <string, string> > nameValueCollection, string key, T value) { nameValueCollection.Add( new KeyValuePair <string, string>(key, OwnIdSerializer.Serialize(value))); return(nameValueCollection); }
protected override async Task ExecuteAsync(HttpContext httpContext) { var request = await OwnIdSerializer.DeserializeAsync <AcceptStartRequest>(httpContext.Request.Body); var input = new TransitionInput <AcceptStartRequest>(RequestIdentity, GetRequestCulture(httpContext), request, ClientDate); var result = await _flowRunner.RunAsync(input, StepType.AcceptStart); await JsonAsync(httpContext, result, StatusCodes.Status200OK); }
protected async Task <JwtContainer> GetRequestJwtContainerAsync(HttpContext httpContext) { var jwtContainer = await OwnIdSerializer.DeserializeAsync <JwtContainer>(httpContext.Request.Body); if (string.IsNullOrEmpty(jwtContainer?.Jwt)) { throw new CommandValidationException("No JWT was found in request"); } return(jwtContainer); }
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); })); }
protected override async Task ExecuteAsync(HttpContext httpContext) { var request = await OwnIdSerializer.DeserializeAsync <UserIdentification>(httpContext.Request.Body); var commandInput = new TransitionInput <UserIdentification>(RequestIdentity, GetRequestCulture(httpContext), request, ClientDate); var result = await _flowRunner.RunAsync(commandInput, StepType.CheckUserExistence); await JsonAsync(httpContext, result, StatusCodes.Status200OK); }
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())); }
protected async Task JsonAsync <T>(HttpContext context, T responseBody, int statusCode, bool addLocaleHeader = true) where T : class { context.Response.StatusCode = statusCode; context.Response.ContentType = "application/json"; if (addLocaleHeader) { var culture = GetRequestCulture(context); context.Response.Headers.Add("Content-Language", culture.ToString()); } await context.Response.WriteAsync(OwnIdSerializer.Serialize(responseBody)); }
public async Task SetAsync(string key, CacheItem data, TimeSpan expiration) { var serializedData = OwnIdSerializer.Serialize(data); var compKey = GetCustomerKey(key); var isSuccess = await _redisDb.StringSetAsync(compKey, serializedData, expiration); _logger.Log(LogLevel.Debug, () => $"set(key -> '{compKey}' value -> '{serializedData}')"); if (!isSuccess) { throw new Exception($"Can not set element to redis with context {data.Context}"); } }
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)); }
protected override async Task ExecuteAsync(HttpContext httpContext) { // TODO: add parsing exception handling to BaseMiddleware AddConnectionRequest request; try { request = await OwnIdSerializer.DeserializeAsync <AddConnectionRequest>(httpContext.Request.Body); } catch { BadRequest(httpContext.Response); return; } var result = await _addConnectionCommand.ExecuteAsync(request); await JsonAsync(httpContext, result, StatusCodes.Status200OK); }
public async Task InvokeAsync(HttpContext context) { if (string.Equals(context.Request.Path, "/ownid/log", StringComparison.InvariantCultureIgnoreCase)) { await _next(context); return; } using (_logger.BeginScope(new { requestId = context.TraceIdentifier })) await using (var respStream = new MemoryStream()) { var originalRespStream = context.Response.Body; try { context.Response.Body = respStream; var body = string.Empty; if (context.Request.Body.CanRead) { context.Request.EnableBuffering(); var stream = new StreamReader(context.Request.Body); body = await stream.ReadToEndAsync(); } var data = new { method = context.Request.Method, scheme = context.Request.Scheme, url = $"{context.Request.Scheme}://{context.Request.Host}{context.Request.Path.ToString()}{context.Request.QueryString.ToString()}", body, cookies = OwnIdSerializer.Serialize(context.Request.Cookies.ToDictionary(x => x.Key, x => x.Value)), headers = OwnIdSerializer.Serialize(context.Request.Headers.ToDictionary(x => x.Key, x => x.Value)) }; _logger.LogWithData(LogLevel.Debug, "Request log", data); } catch (Exception e) { _logger.LogDebug(e, "failed to log request"); } finally { try { context.Request.Body.Position = 0; } catch (Exception) { } } await _next(context); try { var body = string.Empty; respStream.Position = 0; using var sr = new StreamReader(respStream); body = await sr.ReadToEndAsync(); respStream.Position = 0; await respStream.CopyToAsync(originalRespStream); context.Response.Body = originalRespStream; var data = new { body, statusCode = context.Response.StatusCode, headers = OwnIdSerializer.Serialize(context.Response.Headers.ToDictionary(x => x.Key, x => x.Value)) }; _logger.LogWithData(LogLevel.Debug, "Response log", data); } catch (Exception e) { _logger.LogDebug(e, "failed to log request"); } } }
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")))); }
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 UserHandlerAdapter(IUserHandler <TProfile> adaptee) { _adaptee = adaptee; _serializerOptions = OwnIdSerializer.GetDefaultProperties(); _serializerOptions.PropertyNamingPolicy = null; }