/// <inheritdoc/> public ITotpPurposeBuilder UsingDeliveryChannel(TotpDeliveryChannel deliveryChannel, string subject = null) { _totpMessageBuilder.DeliveryChannel = deliveryChannel; _totpMessageBuilder.Subject = subject; var totpPurposeBuilder = new TotpPurposeBuilder(_totpMessageBuilder); return(totpPurposeBuilder); }
/// <inheritdoc /> public async Task <TotpResult> Send(ClaimsPrincipal principal, string message, TotpDeliveryChannel channel = TotpDeliveryChannel.Sms, string purpose = null, string securityToken = null, string phoneNumberOrEmail = null) { var totpResult = ValidateParameters(principal, securityToken, phoneNumberOrEmail); if (!totpResult.Success) { return(totpResult); } User user = null; var hasPrincipal = principal != null; if (hasPrincipal) { user = await UserManager.GetUserAsync(principal); if (user?.PhoneNumberConfirmed == false || string.IsNullOrEmpty(user?.PhoneNumber)) { return(TotpResult.ErrorResult(Localizer["Cannot send SMS. User's phone number is not verified."])); } } purpose ??= TotpConstants.TokenGenerationPurpose.StrongCustomerAuthentication; var token = string.Empty; var hasSecurityToken = !string.IsNullOrEmpty(securityToken); if (hasSecurityToken) { var modifier = GetModifier(purpose, phoneNumberOrEmail); var encodedToken = Encoding.Unicode.GetBytes(securityToken); token = Rfc6238AuthenticationService.GenerateCode(encodedToken, modifier).ToString("D6", CultureInfo.InvariantCulture); } if (hasPrincipal) { token = await UserManager.GenerateUserTokenAsync(user, TokenOptions.DefaultPhoneProvider, purpose); } var userName = user?.UserName ?? "Anonymous"; var cacheKey = $"totp{(hasPrincipal ? $":{user.Id}" : string.Empty)}:{channel}:{token}:{purpose}"; if (await CacheKeyExists(cacheKey)) { Logger.LogInformation($"User: '******' - Last token has not expired yet. Throttling."); return(TotpResult.ErrorResult(Localizer["Last token has not expired yet. Please wait a few seconds and try again."])); } Logger.LogInformation($"User: '******' - Token generated successfully."); switch (channel) { case TotpDeliveryChannel.Sms: await SmsService.SendAsync(user?.PhoneNumber ?? phoneNumberOrEmail, Localizer["OTP"], Localizer[message, token]); break; case TotpDeliveryChannel.Email: case TotpDeliveryChannel.Viber: case TotpDeliveryChannel.Telephone: case TotpDeliveryChannel.EToken: throw new NotSupportedException($"EToken delivery channel {channel} is not implemented."); default: break; } await AddCacheKey(cacheKey); return(TotpResult.SuccessResult); }
/// <inheritdoc /> public async Task <TotpResult> Send(ClaimsPrincipal principal, string message, TotpDeliveryChannel channel = TotpDeliveryChannel.Sms, string purpose = null, string securityToken = null, string phoneNumberOrEmail = null) { var userId = principal.GetSubjectId(); if (!string.IsNullOrEmpty(userId)) { var hasDeveloperTotp = await _dbContext.UserClaims.Where(x => x.UserId == userId && x.ClaimType == BasicClaimTypes.DeveloperTotp).AnyAsync(); if (hasDeveloperTotp) { return(TotpResult.SuccessResult); } } return(await _totpService.Send(principal, message, channel, purpose, securityToken, phoneNumberOrEmail)); }
/// <summary> /// Sends a new code via the selected channel for the given user id. /// </summary> /// <param name="service">The service to use.</param> /// <param name="userId">The user id.</param> /// <param name="message">The message to be sent in the SMS. It's important for the message to contain the {0} placeholder in the position where the OTP should be placed.</param> /// <param name="channel">Delivery channel.</param> /// <param name="reason">Optionaly pass the reason to generate the TOTP.</param> /// <exception cref="TotpServiceException">used to pass errors between service and the caller.</exception> public static Task <TotpResult> Send(this ITotpService service, string userId, string message, TotpDeliveryChannel channel = TotpDeliveryChannel.Sms, string reason = null) => service.Send(new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(BasicClaimTypes.Subject, userId) })), message, channel, reason);
public Task <TotpResult> Send(ClaimsPrincipal principal, string message, TotpDeliveryChannel channel = TotpDeliveryChannel.Sms, string purpose = null, string securityToken = null, string phoneNumberOrEmail = null, string data = null, string classification = null, string subject = null) => Task.FromResult(TotpResult.SuccessResult);
/// <inheritdoc /> public async Task <TotpResult> Send(ClaimsPrincipal principal, string message, TotpDeliveryChannel channel = TotpDeliveryChannel.Sms, string purpose = null, string securityToken = null, string phoneNumberOrEmail = null, string data = null, string classification = null, string subject = null) { var totpResult = ValidateParameters(principal, securityToken, phoneNumberOrEmail); if (!totpResult.Success) { return(totpResult); } User user = null; var hasPrincipal = principal != null; if (hasPrincipal) { user = await _userManager.GetUserAsync(principal); if (user?.PhoneNumberConfirmed == false || string.IsNullOrEmpty(user?.PhoneNumber)) { return(TotpResult.ErrorResult(_localizer["Cannot send SMS. User's phone number is not verified."])); } } purpose ??= TotpConstants.TokenGenerationPurpose.StrongCustomerAuthentication; var token = string.Empty; var hasSecurityToken = !string.IsNullOrEmpty(securityToken); if (hasSecurityToken) { var modifier = GetModifier(purpose, phoneNumberOrEmail); var encodedToken = Encoding.Unicode.GetBytes(securityToken); token = _rfc6238AuthenticationService.GenerateCode(encodedToken, modifier).ToString("D6", CultureInfo.InvariantCulture); } if (hasPrincipal) { token = await _userManager.GenerateUserTokenAsync(user, TokenOptions.DefaultPhoneProvider, purpose); } var userName = user?.UserName ?? "Anonymous"; var cacheKey = $"totp{(hasPrincipal ? $":{user.Id}" : string.Empty)}:{channel}:{token}:{purpose}"; if (await CacheKeyExists(cacheKey)) { _logger.LogInformation("User: '******' - Last token has not expired yet. Throttling", userName); return(TotpResult.ErrorResult(_localizer["Last token has not expired yet. Please wait a few seconds and try again."])); } _logger.LogInformation("User: '******' - Token generated successfully", userName); switch (channel) { case TotpDeliveryChannel.Sms: case TotpDeliveryChannel.Viber: var smsService = _smsServiceFactory.Create(channel.ToString()); await smsService.SendAsync(user?.PhoneNumber ?? phoneNumberOrEmail, _localizer[subject ?? "OTP"], _localizer[message, token]); break; case TotpDeliveryChannel.Email: case TotpDeliveryChannel.Telephone: case TotpDeliveryChannel.EToken: throw new NotSupportedException($"Delivery channel '{channel}' is not supported."); case TotpDeliveryChannel.PushNotification: if (_pushNotificationService == null) { throw new ArgumentNullException(nameof(_pushNotificationService), $"Cannot send push notification since there is no implementation of {nameof(IPushNotificationService)}."); } await _pushNotificationService.SendAsync(builder => builder.To(user?.Id) .WithToken(token) .WithTitle(string.Format(message, token)) .WithData(data) .WithClassification(classification)); break; default: break; } await AddCacheKey(cacheKey); return(TotpResult.SuccessResult); }