/// <summary> /// Gets all authorization codes that matches the specified redirect uri and expires after the /// specified date. Called when authenticating an authorization code. /// </summary> /// <param name="redirectUri">The redirect uri.</param> /// <param name="expires">The expire date.</param> /// <returns>The authorization codes.</returns> public async Task <IEnumerable <IAuthorizationCode> > GetAuthorizationCodes(string redirectUri, DateTimeOffset expires) { var db = this.GetDatabase(); var min = expires.ToUnixTime(); var codes = new List <IAuthorizationCode>(); var nonExpiredKeys = db.SortedSetRangeByScore($"{this.Configuration.AuthorizationCodePrefix}:_index:expires", min, DateTimeMax); var redirectUriKeys = db.HashGetAll($"{this.Configuration.AuthorizationCodePrefix}:_index:redirecturi:{redirectUri}"); var unionKeys = nonExpiredKeys.Join(redirectUriKeys, x => x, y => y.Name, (x, y) => x); foreach (var key in unionKeys) { var hashEntries = await db.HashGetAllAsync(key.ToString()); if (hashEntries.Any()) { var code = new RedisAuthorizationCode(hashEntries); if (code.ValidTo > expires) { codes.Add(code); } } } return(codes); }
/// <summary>Deletes the specified authorization code.</summary> /// <param name="identifier">The identifier.</param> /// <returns><c>True</c> if successful, <c>false</c> otherwise.</returns> public async Task <bool> DeleteAuthorizationCode(string identifier) { if (string.IsNullOrEmpty(identifier)) { throw new ArgumentNullException(nameof(identifier)); } var db = this.GetDatabase(); var tran = db.CreateTransaction(); // Remove items from indexes tran.SortedSetRemoveAsync($"{this.Configuration.AuthorizationCodePrefix}:_index:expires", $"{this.Configuration.AuthorizationCodePrefix}:{identifier}"); var hashEntries = await db.HashGetAllAsync(identifier); if (hashEntries.Any()) { var code = new RedisAuthorizationCode(hashEntries); tran.HashDeleteAsync($"{this.Configuration.AuthorizationCodePrefix}:_index:redirecturi:{code.RedirectUri}", identifier); } // Remove key tran.KeyDeleteAsync($"{this.Configuration.AuthorizationCodePrefix}:{identifier}"); return(await tran.ExecuteAsync(CommandFlags.HighPriority)); }
/// <summary> /// Deletes the authorization codes that expires before the specified expire date. Called when /// creating an authorization code to cleanup. /// </summary> /// <param name="expires">The expire date.</param> /// <returns>The number of deleted codes.</returns> public async Task <int> DeleteAuthorizationCodes(DateTimeOffset expires) { var db = this.GetDatabase(); var tran = db.CreateTransaction(); var keysToDelete = await db.SortedSetRangeByScoreAsync($"{this.Configuration.AuthorizationCodePrefix}:_index:expires", 0, expires.ToUnixTime()); // Remove items from index tran.SortedSetRemoveRangeByScoreAsync($"{this.Configuration.AuthorizationCodePrefix}:_index:expires", 0, expires.ToUnixTime()); // Remove keys foreach (var key in keysToDelete) { var hashEntries = await db.HashGetAllAsync(key.ToString()); if (hashEntries.Any()) { var code = new RedisAuthorizationCode(hashEntries); tran.HashDeleteAsync($"{this.Configuration.AuthorizationCodePrefix}:_index:redirecturi:{code.RedirectUri}", key); } tran.KeyDeleteAsync(key.ToString()); } var result = await tran.ExecuteAsync(CommandFlags.HighPriority); if (result) { return(keysToDelete.Length); } return(0); }
/// <summary> /// Inserts the specified authorization code. Called when creating an authorization code. /// </summary> /// <param name="authorizationCode">The authorization code.</param> /// <returns> /// The inserted authorization code. <c>null</c> if the insertion was unsuccessful. /// </returns> public async Task <IAuthorizationCode> InsertAuthorizationCode(IAuthorizationCode authorizationCode) { var code = new RedisAuthorizationCode(authorizationCode); if (!code.IsValid()) { throw new ArgumentException($"The authorization code is invalid: {JsonConvert.SerializeObject(code)}", nameof(authorizationCode)); } var key = this.GenerateKeyPath(code); var db = this.GetDatabase(); var tran = db.CreateTransaction(); try { this.Configuration.Log.DebugFormat("Inserting authorization code hash in key {0}", key); // Add hash to key tran.HashSetAsync(key, code.ToHashEntries()); var expires = code.ValidTo.ToUnixTime(); this.Configuration.Log.DebugFormat("Inserting key {0} to authorization code set with score {1}", key, expires); // Add key to sorted set for future reference. The score is the expire time in seconds since epoch. tran.SortedSetAddAsync($"{this.Configuration.AuthorizationCodePrefix}:_index:expires", key, expires); tran.HashSetAsync($"{this.Configuration.AuthorizationCodePrefix}:_index:redirecturi:{authorizationCode.RedirectUri}", key, expires); this.Configuration.Log.DebugFormat("Making key {0} expire at {1}", key, code.ValidTo); // Make the key expire when the code times out tran.KeyExpireAsync(key, code.ValidTo.UtcDateTime); await tran.ExecuteAsync(); return(code); } catch (Exception ex) { this.Configuration.Log.Error("Error when inserting authorization code", ex); } return(null); }
/// <summary>Gets the specified authorization code.</summary> /// <param name="identifier">The identifier.</param> /// <returns>The authorization code.</returns> public async Task <IAuthorizationCode> GetAuthorizationCode(string identifier) { if (string.IsNullOrEmpty(identifier)) { throw new ArgumentNullException(nameof(identifier)); } var db = this.GetDatabase(); var key = $"{this.Configuration.AuthorizationCodePrefix}:{Convert.ToBase64String(Encoding.UTF8.GetBytes(identifier))}"; var hashEntries = await db.HashGetAllAsync(key); if (hashEntries.Any()) { var code = new RedisAuthorizationCode(hashEntries); return(code); } return(null); }
/// <summary>Generates a key.</summary> /// <param name="authorizationCode">The authorization code.</param> /// <returns>The key.</returns> protected string GenerateKeyPath(RedisAuthorizationCode authorizationCode) { return(this.Configuration.AuthorizationCodePrefix + ":" + Convert.ToBase64String(Encoding.UTF8.GetBytes(authorizationCode.GetIdentifier()))); }