using System; using System.Globalization; using System.Threading; using System.Threading.Tasks; namespace Microsoft.AspNet.Identity { /// /// TokenProvider that generates time based codes using the user's security stamp /// /// /// public abstract class TotpSecurityStampBasedTokenProvider : IUserTokenProvider where TUser : class { public abstract string Name { get; } /// /// This token provider does not notify the user by default /// /// /// /// /// public virtual Task NotifyAsync(string token, UserManager manager, TUser user, CancellationToken cancellationToken = default(CancellationToken)) { return Task.FromResult(0); } /// /// Generate a token for the user using their security stamp /// /// /// /// /// public virtual async Task GenerateAsync(string purpose, UserManager manager, TUser user, CancellationToken cancellationToken = default(CancellationToken)) { if (manager == null) { throw new ArgumentNullException("manager"); } var token = await manager.CreateSecurityTokenAsync(user, cancellationToken); var modifier = await GetUserModifierAsync(purpose, manager, user); return Rfc6238AuthenticationService.GenerateCode(token, modifier).ToString("D6", CultureInfo.InvariantCulture); } /// /// Validate the token for the user /// /// /// /// /// /// public virtual async Task ValidateAsync(string purpose, string token, UserManager manager, TUser user, CancellationToken cancellationToken = default(CancellationToken)) { if (manager == null) { throw new ArgumentNullException("manager"); } int code; if (!int.TryParse(token, out code)) { return false; } var securityToken = await manager.CreateSecurityTokenAsync(user, cancellationToken); var modifier = await GetUserModifierAsync(purpose, manager, user); return securityToken != null && Rfc6238AuthenticationService.ValidateCode(securityToken, code, modifier); } /// /// Used for entropy in the token, uses the user.Id by default /// /// /// /// /// public virtual async Task GetUserModifierAsync(string purpose, UserManager manager, TUser user, CancellationToken cancellationToken = default(CancellationToken)) { if (manager == null) { throw new ArgumentNullException("manager"); } var userId = await manager.GetUserIdAsync(user); return "Totp:" + purpose + ":" + userId; } public abstract Task CanGenerateTwoFactorTokenAsync(UserManager manager, TUser user, CancellationToken cancellationToken = default(CancellationToken)); } }