Exemplo n.º 1
0
        public override async Task <bool> ValidateAsync(string purpose, string token, UserManager <AppUser> manager, AppUser user)
        {
            int code;

            if (!int.TryParse(token, out code))
            {
                return(false);
            }

            List <UserTotpDevice> devices = await _authDbContext.UserTotpDevices
                                            .Where(u => u.User == user)
                                            .ToListAsync();

            var unixTimestamp = Convert.ToInt64(Math.Round((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds));
            var timestep      = Convert.ToInt64(unixTimestamp / 30);

            foreach (UserTotpDevice device in devices)
            {
                var hash = new HMACSHA1(Base32.FromBase32(device.SharedSecret));

                for (int i = -2; i <= 2; i++)
                {
                    var expectedCode = Rfc6238AuthenticationService.ComputeTotp(hash, (ulong)(timestep + i), modifier: null);
                    if (expectedCode == code)
                    {
                        device.LastUsedTime = SystemClock.Instance.GetCurrentInstant();
                        await _authDbContext.SaveChangesAsync();

                        return(true);
                    }
                }
            }

            return(false);
        }
Exemplo n.º 2
0
 public override Task <NewAuthenticatorSecret> GetNewAuthenticatorSecret(Empty request, ServerCallContext context)
 {
     return(Task.FromResult(new NewAuthenticatorSecret
     {
         Secret = Base32.ToBase32(Rfc6238AuthenticationService.GenerateRandomKey()),
     }));
 }
Exemplo n.º 3
0
        public override async Task <bool> ValidateAsync(string purpose, string token, UserManager <AppUser> manager, AppUser user)
        {
            int code;

            if (!int.TryParse(token, out code))
            {
                return(false);
            }

            List <string> keys = await _authDbContext.UserTotpDevices
                                 .AsNoTracking()
                                 .Where(u => u.User == user)
                                 .Select(t => t.SharedSecret)
                                 .ToListAsync();

            var unixTimestamp = Convert.ToInt64(Math.Round((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds));
            var timestep      = Convert.ToInt64(unixTimestamp / 30);

            foreach (string key in keys)
            {
                var hash = new HMACSHA1(Base32.FromBase32(key));

                for (int i = -2; i <= 2; i++)
                {
                    var expectedCode = Rfc6238AuthenticationService.ComputeTotp(hash, (ulong)(timestep + i), modifier: null);
                    if (expectedCode == code)
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
Exemplo n.º 4
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="purpose"></param>
        /// <param name="token"></param>
        /// <param name="manager"></param>
        /// <param name="user"></param>
        /// <returns></returns>
        public virtual async Task <bool> ValidateAsync(string purpose, string token, UserManager <TUser> manager, TUser user)
        {
            var key = await manager.GetAuthenticatorKeyAsync(user);

            int code;

            if (!int.TryParse(token, out code))
            {
                return(false);
            }

            var hash          = new HMACSHA1(Base32.FromBase32(key));
            var unixTimestamp = Convert.ToInt64(Math.Round((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds));
            var timestep      = Convert.ToInt64(unixTimestamp / 30);

            // Allow codes from 90s in each direction (we could make this configurable?)
            for (int i = -2; i <= 2; i++)
            {
                var expectedCode = Rfc6238AuthenticationService.ComputeTotp(hash, (ulong)(timestep + i), modifier: null);
                if (expectedCode == code)
                {
                    return(true);
                }
            }
            return(false);
        }
Exemplo n.º 5
0
        public static string ComputeCode(string key)
        {
            var hash          = new HMACSHA1(Base32.FromBase32(key));
            var unixTimestamp = Convert.ToInt64(Math.Round((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds));
            var timestep      = Convert.ToInt64(unixTimestamp / 30);
            var topt          = Rfc6238AuthenticationService.ComputeTotp(hash, (ulong)timestep, modifier: null);

            return(topt.ToString("D6", CultureInfo.InvariantCulture));
        }
Exemplo n.º 6
0
    public static string ComputeCode(string key)
    {
        var keyBytes      = Base32.FromBase32(key);
        var unixTimestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
        var timestep      = Convert.ToInt64(unixTimestamp / 30);
        var topt          = Rfc6238AuthenticationService.ComputeTotp(keyBytes, (ulong)timestep, modifier: null);

        return(topt.ToString("D6", CultureInfo.InvariantCulture));
    }
    /// <summary>
    /// Generates a token for the specified <paramref name="user"/> and <paramref name="purpose"/>.
    /// </summary>
    /// <param name="purpose">The purpose the token will be used for.</param>
    /// <param name="manager">The <see cref="UserManager{TUser}"/> that can be used to retrieve user properties.</param>
    /// <param name="user">The user a token should be generated for.</param>
    /// <returns>
    /// The <see cref="Task"/> that represents the asynchronous operation, containing the token for the specified
    /// <paramref name="user"/> and <paramref name="purpose"/>.
    /// </returns>
    /// <remarks>
    /// The <paramref name="purpose"/> parameter allows a token generator to be used for multiple types of token whilst
    /// insuring a token for one purpose cannot be used for another. For example if you specified a purpose of "Email"
    /// and validated it with the same purpose a token with the purpose of TOTP would not pass the check even if it was
    /// for the same user.
    ///
    /// Implementations of <see cref="IUserTwoFactorTokenProvider{TUser}"/> should validate that purpose is not null or empty to
    /// help with token separation.
    /// </remarks>
    public virtual async Task <string> GenerateAsync(string purpose, UserManager <TUser> manager, TUser user)
    {
        if (manager == null)
        {
            throw new ArgumentNullException(nameof(manager));
        }
        var token = await manager.CreateSecurityTokenAsync(user).ConfigureAwait(false);

        var modifier = await GetUserModifierAsync(purpose, manager, user).ConfigureAwait(false);

        return(Rfc6238AuthenticationService.GenerateCode(token, modifier).ToString("D6", CultureInfo.InvariantCulture));
    }
Exemplo n.º 8
0
        public User ValidateCode(int userId, int code, string newEmail)
        {
            var user          = Find(userId);
            var securityToken = new SecurityToken(Encoding.Unicode.GetBytes(user.SecurityStamp));

            if (Rfc6238AuthenticationService.ValidateCode(securityToken, code, newEmail))
            {
                user.Email = newEmail;
                Update(user);
                return(user);
            }
            return(null);
        }
Exemplo n.º 9
0
 /// <summary>
 /// Creates a new instance of <see cref="OtpAuthenticateExtensionGrantValidator"/>.
 /// </summary>
 /// <param name="validator">Validates an access token.</param>
 /// <param name="userManager">Provides the APIs for managing user in a persistence store.</param>
 /// <param name="totpOptions">Configuration used in <see cref="System.Security.Rfc6238AuthenticationService"/> service.</param>
 /// <param name="identityMessageDescriber">Provides an extensibility point for altering localizing used inside the package.</param>
 /// <param name="totpService">Used to generate, send and verify time based one time passwords.</param>
 public OtpAuthenticateExtensionGrantValidator(
     ITokenValidator validator,
     UserManager <User> userManager,
     TotpOptions totpOptions,
     IdentityMessageDescriber identityMessageDescriber,
     ITotpService totpService
     )
 {
     _tokenValidator               = validator ?? throw new ArgumentNullException(nameof(validator));
     _userManager                  = userManager ?? throw new ArgumentNullException(nameof(userManager));
     _identityMessageDescriber     = identityMessageDescriber ?? throw new ArgumentNullException(nameof(identityMessageDescriber));
     _totpService                  = totpService ?? throw new ArgumentNullException(nameof(totpService));
     _rfc6238AuthenticationService = new Rfc6238AuthenticationService(totpOptions.Timestep, totpOptions.CodeLength);
 }
Exemplo n.º 10
0
        public OperationResult <string> GenerateCode(int userId, string newEmail)
        {
            var user = Find(userId);

            if (Exist(newEmail))
            {
                return(new OperationResult <string>(false, "该邮箱已注册"));
            }
            var securityToken = new SecurityToken(Encoding.Unicode.GetBytes(user.SecurityStamp));
            int code          = Rfc6238AuthenticationService.GenerateCode(securityToken, newEmail);

            EmailService.SendEmail(EmailType.ResetEmail, newEmail, user.UserName, "", code.ToString());
            return(new OperationResult <string>(true, "验证码已发送至你的新邮箱"));
        }
    /// <summary>
    /// Returns a flag indicating whether the specified <paramref name="token"/> is valid for the given
    /// <paramref name="user"/> and <paramref name="purpose"/>.
    /// </summary>
    /// <param name="purpose">The purpose the token will be used for.</param>
    /// <param name="token">The token to validate.</param>
    /// <param name="manager">The <see cref="UserManager{TUser}"/> that can be used to retrieve user properties.</param>
    /// <param name="user">The user a token should be validated for.</param>
    /// <returns>
    /// The <see cref="Task"/> that represents the asynchronous operation, containing the a flag indicating the result
    /// of validating the <paramref name="token"> for the specified </paramref><paramref name="user"/> and <paramref name="purpose"/>.
    /// The task will return true if the token is valid, otherwise false.
    /// </returns>
    public virtual async Task <bool> ValidateAsync(string purpose, string token, UserManager <TUser> manager, TUser user)
    {
        if (manager == null)
        {
            throw new ArgumentNullException(nameof(manager));
        }
        int code;

        if (!int.TryParse(token, out code))
        {
            return(false);
        }
        var securityToken = await manager.CreateSecurityTokenAsync(user).ConfigureAwait(false);

        var modifier = await GetUserModifierAsync(purpose, manager, user).ConfigureAwait(false);

        return(securityToken != null && Rfc6238AuthenticationService.ValidateCode(securityToken, code, modifier));
    }
Exemplo n.º 12
0
 /// <summary>
 /// Constructs the <see cref="TotpService"/>.
 /// </summary>
 /// <param name="userManager">Provides the APIs for managing user in a persistence store.</param>
 /// <param name="smsServiceFactory">Sms Service Factory</param>
 /// <param name="pushNotificationService">Push Notification service</param>
 /// <param name="distributedCache">Represents a distributed cache of serialized values.</param>
 /// <param name="localizer">Represents a service that provides localized strings.</param>
 /// <param name="logger">Represents a type used to perform logging.</param>
 /// <param name="rfc6238AuthenticationService">Time-Based One-Time Password Algorithm service.</param>
 public TotpService(
     UserManager <User> userManager,
     ISmsServiceFactory smsServiceFactory,
     IPushNotificationService pushNotificationService,
     IDistributedCache distributedCache,
     IStringLocalizer <TotpService> localizer,
     ILogger <TotpService> logger,
     Rfc6238AuthenticationService rfc6238AuthenticationService
     )
 {
     _userManager             = userManager ?? throw new ArgumentNullException(nameof(userManager));
     _smsServiceFactory       = smsServiceFactory ?? throw new ArgumentNullException(nameof(smsServiceFactory));
     _pushNotificationService = pushNotificationService;
     _cache     = distributedCache ?? throw new ArgumentNullException(nameof(distributedCache));
     _localizer = localizer ?? throw new ArgumentNullException(nameof(localizer));
     _logger    = logger ?? throw new ArgumentNullException(nameof(logger));
     _rfc6238AuthenticationService = rfc6238AuthenticationService ?? throw new ArgumentNullException(nameof(rfc6238AuthenticationService));
 }
 /// <summary>
 /// Creates a new instance of <see cref="ExtendedPhoneNumberTokenProvider{TUser}"/>.
 /// </summary>
 /// <param name="rfc6238AuthenticationService">Time-Based One-Time Password Algorithm service.</param>
 public ExtendedPhoneNumberTokenProvider(Rfc6238AuthenticationService rfc6238AuthenticationService)
 {
     Rfc6238AuthenticationService = rfc6238AuthenticationService ?? throw new ArgumentNullException(nameof(rfc6238AuthenticationService));
 }
Exemplo n.º 14
0
 /// <summary>
 /// Creates a new instance of <see cref="ExtendedPhoneNumberTokenProvider{TUser}"/>.
 /// </summary>
 /// <param name="rfc6238AuthenticationService">Time-Based One-Time Password Algorithm service.</param>
 public DeveloperPhoneNumberTokenProvider(Rfc6238AuthenticationService rfc6238AuthenticationService) : base(rfc6238AuthenticationService)
 {
 }
Exemplo n.º 15
0
 /// <summary>
 /// Constructs the <see cref="TotpService"/>.
 /// </summary>
 /// <param name="userManager">Provides the APIs for managing user in a persistence store.</param>
 /// <param name="smsService">Sms service.</param>
 /// <param name="distributedCache">Represents a distributed cache of serialized values.</param>
 /// <param name="localizer">Represents a service that provides localized strings.</param>
 /// <param name="logger">Represents a type used to perform logging.</param>
 /// <param name="rfc6238AuthenticationService">Time-Based One-Time Password Algorithm service.</param>
 public TotpService(UserManager <User> userManager, ISmsService smsService, IDistributedCache distributedCache, IStringLocalizer <TotpService> localizer, ILogger <TotpService> logger, Rfc6238AuthenticationService rfc6238AuthenticationService)
 {
     UserManager = userManager ?? throw new ArgumentNullException(nameof(userManager));
     SmsService  = smsService ?? throw new ArgumentNullException(nameof(smsService));
     Cache       = distributedCache ?? throw new ArgumentNullException(nameof(distributedCache));
     Localizer   = localizer ?? throw new ArgumentNullException(nameof(localizer));
     Logger      = logger ?? throw new ArgumentNullException(nameof(logger));
     Rfc6238AuthenticationService = rfc6238AuthenticationService ?? throw new ArgumentNullException(nameof(rfc6238AuthenticationService));
 }