예제 #1
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);
        }
        /// <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);

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

            return(Rfc6238AuthenticationService.GenerateCode(token, modifier).ToString("D6", CultureInfo.InvariantCulture));
        }
        /// <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);

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

            return(securityToken != null && Rfc6238AuthenticationService.ValidateCode(securityToken, code, modifier));
        }