Skip to content

Commit 43c0db6

Browse files
authored
Allow clients to control the how the cache key is generated from a token. (DuendeArchive#131)
* DuendeArchive#130 Allow clients to control the how the cache key is generated from a token. If a client can rely on IDistributedCache, a client can then have direct control over downstream caching functionality like Remove cache item. Use Case: The token that came in via the request has been mutated downstream, hence the claims that were generated from that token are no longer valid. The claims in the cache vs the claims that the token is now pointing to are out of sync. The downstream mutation flow must be able to remove the token from the cache so not to incur needless mutations for each new request for the duration of the cache. * Fixed XML Comments. No code change
1 parent c31dbf2 commit 43c0db6

4 files changed

Lines changed: 41 additions & 7 deletions

File tree

src/Infrastructure/CacheExtensions.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@ static CacheExtensions()
2929
Options.Converters.Add(new ClaimConverter());
3030
}
3131

32-
public static async Task<IEnumerable<Claim>> GetClaimsAsync(this IDistributedCache cache, string cacheKeyPrefix, string token)
32+
public static async Task<IEnumerable<Claim>> GetClaimsAsync(this IDistributedCache cache, OAuth2IntrospectionOptions options, string token)
3333
{
34-
var bytes = await cache.GetAsync($"{cacheKeyPrefix}{token.Sha256()}").ConfigureAwait(false);
34+
var cacheKey = options.CacheKeyGenerator(options,token);
35+
var bytes = await cache.GetAsync(cacheKey).ConfigureAwait(false);
3536

3637
if (bytes == null)
3738
{
@@ -42,7 +43,7 @@ public static async Task<IEnumerable<Claim>> GetClaimsAsync(this IDistributedCac
4243
return JsonSerializer.Deserialize<IEnumerable<Claim>>(json, Options);
4344
}
4445

45-
public static async Task SetClaimsAsync(this IDistributedCache cache, string cacheKeyPrefix, string token, IEnumerable<Claim> claims, TimeSpan duration, ILogger logger)
46+
public static async Task SetClaimsAsync(this IDistributedCache cache, OAuth2IntrospectionOptions options, string token, IEnumerable<Claim> claims, TimeSpan duration, ILogger logger)
4647
{
4748
var expClaim = claims.FirstOrDefault(c => c.Type == JwtClaimTypes.Expiration);
4849
if (expClaim == null)
@@ -76,7 +77,8 @@ public static async Task SetClaimsAsync(this IDistributedCache cache, string cac
7677
var bytes = Encoding.UTF8.GetBytes(json);
7778

7879
logger.LogDebug("Setting cache item expiration to {expiration}", absoluteLifetime);
79-
await cache.SetAsync($"{cacheKeyPrefix}{token.Sha256()}", bytes, new DistributedCacheEntryOptions { AbsoluteExpiration = absoluteLifetime }).ConfigureAwait(false);
80+
var cacheKey = options.CacheKeyGenerator(options, token);
81+
await cache.SetAsync(cacheKey, bytes, new DistributedCacheEntryOptions { AbsoluteExpiration = absoluteLifetime }).ConfigureAwait(false);
8082
}
8183
}
8284
}

src/Infrastructure/CacheUtils.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (c) Dominick Baier & Brock Allen. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Text;
7+
8+
namespace IdentityModel.AspNetCore.OAuth2Introspection.Infrastructure
9+
{
10+
/// <summary>
11+
/// Defines some common cache utilities
12+
/// </summary>
13+
public static class CacheUtils
14+
{
15+
/// <summary>
16+
/// Generates a cache key based opon input from OAuth2IntrospectionOptions and the token.
17+
/// </summary>
18+
/// <returns></returns>
19+
public static Func<OAuth2IntrospectionOptions,string, string> CacheKeyFromToken()
20+
{
21+
return (options, token) =>
22+
{
23+
return $"{options.CacheKeyPrefix}{token.Sha256()}";
24+
};
25+
}
26+
}
27+
}

src/OAuth2IntrospectionHandler.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
8787
// if caching is enable - let's check if we have a cached introspection
8888
if (Options.EnableCaching)
8989
{
90-
var claims = await _cache.GetClaimsAsync(Options.CacheKeyPrefix, token).ConfigureAwait(false);
90+
var claims = await _cache.GetClaimsAsync(Options, token).ConfigureAwait(false);
9191
if (claims != null)
9292
{
9393
// find out if it is a cached inactive token
@@ -127,7 +127,7 @@ Lazy<Task<TokenIntrospectionResponse>> GetTokenIntrospectionResponseLazy(string
127127
{
128128
if (Options.EnableCaching)
129129
{
130-
await _cache.SetClaimsAsync(Options.CacheKeyPrefix, token, response.Claims, Options.CacheDuration, _logger).ConfigureAwait(false);
130+
await _cache.SetClaimsAsync(Options, token, response.Claims, Options.CacheDuration, _logger).ConfigureAwait(false);
131131
}
132132

133133
return await CreateTicket(response.Claims, token, Context, Scheme, Events, Options);
@@ -140,7 +140,7 @@ Lazy<Task<TokenIntrospectionResponse>> GetTokenIntrospectionResponseLazy(string
140140
var claimsWithExp = response.Claims.ToList();
141141
claimsWithExp.Add(new Claim("exp",
142142
DateTimeOffset.UtcNow.Add(Options.CacheDuration).ToUnixTimeSeconds().ToString()));
143-
await _cache.SetClaimsAsync(Options.CacheKeyPrefix, token, claimsWithExp, Options.CacheDuration, _logger)
143+
await _cache.SetClaimsAsync(Options, token, claimsWithExp, Options.CacheDuration, _logger)
144144
.ConfigureAwait(false);
145145
}
146146

src/OAuth2IntrospectionOptions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,11 @@ public OAuth2IntrospectionOptions()
113113
/// </summary>
114114
public string CacheKeyPrefix { get; set; } = string.Empty;
115115

116+
/// <summary>
117+
/// Specifies the method how to generate the cache key from the token
118+
/// </summary>
119+
public Func<OAuth2IntrospectionOptions,string, string> CacheKeyGenerator { get; set; } = CacheUtils.CacheKeyFromToken();
120+
116121
/// <summary>
117122
/// Specifies the method how to retrieve the token from the HTTP request
118123
/// </summary>

0 commit comments

Comments
 (0)