Skip to content

Commit 01afe36

Browse files
feature(#22): enhance JWT authentication to resolve signing keys based on realm and secret filters
1 parent 95ea97e commit 01afe36

1 file changed

Lines changed: 59 additions & 8 deletions

File tree

Applications/Backend/Source/HttpsRichardy.Federation.WebApi/Extensions/AuthenticationExtension.cs

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,72 @@ public static class AuthenticationExtension
66
public static IServiceCollection AddJwtAuthentication(this IServiceCollection services)
77
{
88
var serviceProvider = services.BuildServiceProvider();
9-
var secretRepository = serviceProvider.GetRequiredService<ISecretCollection>();
9+
var accessor = serviceProvider.GetRequiredService<IHttpContextAccessor>();
1010

11-
var secret = secretRepository.GetSecretAsync()
12-
.GetAwaiter()
13-
.GetResult();
14-
15-
var publicKey = Common.Utilities.RsaHelper.CreateSecurityKeyFromPublicKey(secret.PublicKey);
1611
var validationParameters = new TokenValidationParameters
1712
{
1813
ValidateIssuer = false,
1914
ValidateAudience = false,
2015
ValidateLifetime = true,
2116
ValidateIssuerSigningKey = true,
22-
IssuerSigningKey = publicKey,
23-
ClockSkew = TimeSpan.Zero
17+
ClockSkew = TimeSpan.FromSeconds(30),
18+
IssuerSigningKeyResolver = (token, _, kid, _) =>
19+
{
20+
var context = accessor.HttpContext;
21+
if (context is null || string.IsNullOrWhiteSpace(token))
22+
return [];
23+
24+
var secretCollection = context.RequestServices.GetRequiredService<ISecretCollection>();
25+
var realmCollection = context.RequestServices.GetRequiredService<IRealmCollection>();
26+
27+
var jsonWebToken = new Microsoft.IdentityModel.JsonWebTokens.JsonWebToken(token);
28+
var realmId = jsonWebToken.Claims.FirstOrDefault(claim => claim.Type == Infrastructure.Constants.IdentityClaimNames.RealmId)?.Value;
29+
30+
if (string.IsNullOrWhiteSpace(realmId))
31+
{
32+
var realmName = jsonWebToken.Claims.FirstOrDefault(claim => claim.Type == Infrastructure.Constants.IdentityClaimNames.Realm)?.Value;
33+
34+
if (string.IsNullOrWhiteSpace(realmName))
35+
return [];
36+
37+
var realmFilters = RealmFilters.WithSpecifications()
38+
.WithName(realmName)
39+
.Build();
40+
41+
var realms = realmCollection
42+
.GetRealmsAsync(realmFilters, context.RequestAborted)
43+
.GetAwaiter()
44+
.GetResult();
45+
46+
realmId = realms.FirstOrDefault()?.Id;
47+
}
48+
49+
if (string.IsNullOrWhiteSpace(realmId))
50+
return [];
51+
52+
var secretFilters = SecretFilters.WithSpecifications()
53+
.WithRealm(realmId)
54+
.WithCanValidate()
55+
.Build();
56+
57+
var secrets = secretCollection
58+
.GetSecretsAsync(secretFilters, context.RequestAborted)
59+
.GetAwaiter()
60+
.GetResult();
61+
62+
if (!string.IsNullOrWhiteSpace(kid))
63+
{
64+
secrets = [.. secrets.Where(secret => secret.Id == kid)];
65+
}
66+
67+
return [.. secrets.Select(secret =>
68+
{
69+
var key = Common.Utilities.RsaHelper.CreateSecurityKeyFromPublicKey(secret.PublicKey);
70+
key.KeyId = secret.Id;
71+
72+
return key;
73+
})];
74+
}
2475
};
2576

2677
var builder = services.AddAuthentication(options =>

0 commit comments

Comments
 (0)