Beispiel #1
0
        /// <summary>
        /// Deletes the refresh tokens that expires before the specified expire date. Called when
        /// creating a refresh token to cleanup.
        /// </summary>
        /// <param name="expires">The expire date.</param>
        /// <returns>The number of deleted tokens.</returns>
        public async Task <int> DeleteRefreshTokens(DateTimeOffset expires)
        {
            var db   = this.GetDatabase();
            var tran = db.CreateTransaction();

            var keysToDelete = await db.SortedSetRangeByScoreAsync($"{this.Configuration.RefreshTokenPrefix}:_index:expires", 0, expires.ToUnixTime());

            // Remove items from indexes
            tran.SortedSetRemoveRangeByScoreAsync($"{this.Configuration.RefreshTokenPrefix}:_index:expires", 0, expires.ToUnixTime());

            // Remove items
            foreach (var key in keysToDelete)
            {
                var data = await db.HashGetAllAsync(key.ToString());

                var token = new RedisRefreshToken(data);

                tran.HashDeleteAsync($"{this.Configuration.RefreshTokenPrefix}:_index:client:{token.ClientId}", key);
                tran.HashDeleteAsync($"{this.Configuration.RefreshTokenPrefix}:_index:redirecturi:{token.RedirectUri}", key);
                tran.HashDeleteAsync($"{this.Configuration.RefreshTokenPrefix}:_index:subject:{token.Subject}", key);
                tran.KeyDeleteAsync(key.ToString());
            }

            var result = await tran.ExecuteAsync(CommandFlags.HighPriority);

            if (result)
            {
                return(keysToDelete.Length);
            }

            return(0);
        }
Beispiel #2
0
        /// <summary>
        /// Gets all refresh tokens for the specified user that expires **after** the specified date.
        /// </summary>
        /// <param name="subject">The subject.</param>
        /// <param name="expires">The expire date.</param>
        /// <returns>The refresh tokens.</returns>
        public async Task <IEnumerable <IRefreshToken> > GetUserRefreshTokens(string subject, DateTimeOffset expires)
        {
            var db = this.GetDatabase();

            var min    = expires.ToUnixTime();
            var tokens = new List <IRefreshToken>();

            var keys = db.SortedSetRangeByScore($"{this.Configuration.RefreshTokenPrefix}:_index:expires", min, DateTimeMax);

            foreach (var key in keys)
            {
                var hashEntries = await db.HashGetAllAsync(key.ToString());

                if (hashEntries.Any())
                {
                    var token = new RedisRefreshToken(hashEntries);

                    if (token.Subject == subject && token.ValidTo > expires)
                    {
                        tokens.Add(token);
                    }
                }
            }

            return(tokens);
        }
Beispiel #3
0
        /// <summary>Inserts the specified refresh token. Called when creating a refresh token.</summary>
        /// <param name="refreshToken">The refresh token.</param>
        /// <returns>The inserted refresh token. <c>null</c> if the insertion was unsuccessful.</returns>
        public async Task <IRefreshToken> InsertRefreshToken(IRefreshToken refreshToken)
        {
            var token = new RedisRefreshToken(refreshToken);

            if (!token.IsValid())
            {
                throw new ArgumentException($"The refresh token is invalid: {JsonConvert.SerializeObject(token)}", nameof(refreshToken));
            }

            var key = this.GenerateKeyPath(token);

            var db   = this.GetDatabase();
            var tran = db.CreateTransaction();

            try
            {
                this.Configuration.Log.DebugFormat("Inserting refresh token hash in key {0}", key);

                // Add hash to key
                tran.HashSetAsync(key, token.ToHashEntries());

                var expires = token.ValidTo.ToUnixTime();

                this.Configuration.Log.DebugFormat("Inserting key {0} to refresh token set with score {1}", key, expires);

                // Add key to index for future reference. The score is the expire time in seconds since epoch.
                tran.SortedSetAddAsync($"{this.Configuration.RefreshTokenPrefix}:_index:expires", key, expires);

                // Add key to hashed set for future reference by client id, redirect uri or subject. The value is the expire time in seconds since epoch.
                tran.HashSetAsync($"{this.Configuration.RefreshTokenPrefix}:_index:client:{token.ClientId}", key, expires);
                tran.HashSetAsync($"{this.Configuration.RefreshTokenPrefix}:_index:redirecturi:{token.RedirectUri}", key, expires);
                tran.HashSetAsync($"{this.Configuration.RefreshTokenPrefix}:_index:subject:{token.Subject}", key, expires);

                this.Configuration.Log.DebugFormat("Making key {0} expire at {1}", key, token.ValidTo);

                // Make the key expire when the code times out
                tran.KeyExpireAsync(key, token.ValidTo.UtcDateTime);

                await tran.ExecuteAsync();

                return(token);
            }
            catch (Exception ex)
            {
                this.Configuration.Log.Error("Error when inserting refresh token", ex);
            }

            return(null);
        }
Beispiel #4
0
        /// <summary>
        /// Deletes the specified refresh token. Called when authenticating a refresh token to prevent re-
        /// use.
        /// </summary>
        /// <param name="refreshToken">The refresh token.</param>
        /// <returns><c>True</c> if successful, <c>false</c> otherwise.</returns>
        public async Task <bool> DeleteRefreshToken(IRefreshToken refreshToken)
        {
            var token = new RedisRefreshToken(refreshToken);

            var key = this.GenerateKeyPath(token);

            var db   = this.GetDatabase();
            var tran = db.CreateTransaction();

            // Remove items from indexes
            tran.SortedSetRemoveAsync($"{this.Configuration.RefreshTokenPrefix}:_index:expires", key);
            tran.HashDeleteAsync($"{this.Configuration.RefreshTokenPrefix}:_index:client:{token.ClientId}", key);
            tran.HashDeleteAsync($"{this.Configuration.RefreshTokenPrefix}:_index:redirecturi:{token.RedirectUri}", key);
            tran.HashDeleteAsync($"{this.Configuration.RefreshTokenPrefix}:_index:subject:{token.Subject}", key);

            // Remove keys
            tran.KeyDeleteAsync(key);

            return(await tran.ExecuteAsync(CommandFlags.HighPriority));
        }
Beispiel #5
0
        /// <summary>Gets the specified refresh token.</summary>
        /// <param name="identifier">The identifier.</param>
        /// <returns>The refresh token.</returns>
        public async Task <IRefreshToken> GetRefreshToken(string identifier)
        {
            if (string.IsNullOrEmpty(identifier))
            {
                throw new ArgumentNullException(nameof(identifier));
            }

            var db  = this.GetDatabase();
            var key = $"{this.Configuration.RefreshTokenPrefix}:{Convert.ToBase64String(Encoding.UTF8.GetBytes(identifier))}";

            var hashEntries = await db.HashGetAllAsync(key);

            if (hashEntries.Any())
            {
                var token = new RedisRefreshToken(hashEntries);

                return(token);
            }

            return(null);
        }
Beispiel #6
0
 /// <summary>Generates a key.</summary>
 /// <param name="refreshToken">The refresh token.</param>
 /// <returns>The key.</returns>
 protected string GenerateKeyPath(RedisRefreshToken refreshToken)
 {
     return(this.Configuration.RefreshTokenPrefix + ":" + Convert.ToBase64String(Encoding.UTF8.GetBytes(refreshToken.GetIdentifier())));
 }