Skip to content

Commit 07b1102

Browse files
test: add kty field to key metadata and enhance algorithm family matching
1 parent fdd532d commit 07b1102

File tree

3 files changed

+53
-15
lines changed

3 files changed

+53
-15
lines changed

spec/01-unit/validators/signature_spec.lua

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ describe("Plugin: jwt-keycloak (signature validator)", function()
4545
keys = { "key1", "key2" },
4646
kids = { "kid1", "kid2" },
4747
key_metadata = {
48-
{ alg = "RS256", use = "sig" },
49-
{ alg = "RS256", use = "sig" }
48+
{ alg = "RS256", use = "sig", kty = "RSA" },
49+
{ alg = "RS256", use = "sig", kty = "RSA" }
5050
}
5151
}
5252

@@ -65,7 +65,7 @@ describe("Plugin: jwt-keycloak (signature validator)", function()
6565
local public_keys = {
6666
keys = { "key1" },
6767
kids = { "kid1" },
68-
key_metadata = { { alg = "ES256", use = "sig" } }
68+
key_metadata = { { alg = "ES256", use = "sig", kty = "EC" } }
6969
}
7070

7171
local err = signature_validator.validate_signature_with_kid({}, jwt, public_keys)
@@ -154,7 +154,7 @@ describe("Plugin: jwt-keycloak (signature validator)", function()
154154
assert.equals("Invalid token signature", err.message)
155155
end)
156156

157-
it("should match any key when kid is missing and no alg specified", function()
157+
it("should match key by kty when kid is missing (EC key)", function()
158158
local jwt = {
159159
header = { alg = "ES256" },
160160
verify_signature = function(self, key)
@@ -166,8 +166,8 @@ describe("Plugin: jwt-keycloak (signature validator)", function()
166166
keys = { "RSA_KEY", "EC_KEY" },
167167
kids = { "kid1", "kid2" },
168168
key_metadata = {
169-
{},
170-
{}
169+
{ kty = "RSA" },
170+
{ kty = "EC" }
171171
}
172172
}
173173

@@ -188,8 +188,8 @@ describe("Plugin: jwt-keycloak (signature validator)", function()
188188
keys = { "ENC_KEY", "SIG_KEY" },
189189
kids = { "kid1", "kid2" },
190190
key_metadata = {
191-
{ alg = "RS256", use = "enc" },
192-
{ alg = "RS256", use = "sig" }
191+
{ alg = "RS256", use = "enc", kty = "RSA" },
192+
{ alg = "RS256", use = "sig", kty = "RSA" }
193193
}
194194
}
195195

@@ -198,7 +198,7 @@ describe("Plugin: jwt-keycloak (signature validator)", function()
198198
assert.is_nil(err)
199199
end)
200200

201-
it("should match when metadata has no alg specified", function()
201+
it("should match when metadata has no alg but kty matches", function()
202202
local jwt = {
203203
header = { alg = "RS256" },
204204
verify_signature = function(self, key)
@@ -210,7 +210,7 @@ describe("Plugin: jwt-keycloak (signature validator)", function()
210210
keys = { "RSA_KEY" },
211211
kids = { "kid1" },
212212
key_metadata = {
213-
{} -- no alg specified
213+
{ kty = "RSA" } -- no alg specified
214214
}
215215
}
216216

@@ -231,7 +231,7 @@ describe("Plugin: jwt-keycloak (signature validator)", function()
231231
keys = { "KEY_FOR_RS256" },
232232
kids = { "kid1" },
233233
key_metadata = {
234-
{ alg = "RS256", use = "sig" }
234+
{ alg = "RS256", use = "sig", kty = "RSA" }
235235
}
236236
}
237237

@@ -276,4 +276,26 @@ describe("Plugin: jwt-keycloak (signature validator)", function()
276276
assert.equals(401, err.status)
277277
assert.equals("No public keys available", err.message)
278278
end)
279+
280+
it("should support PS256 (RSA-PSS) algorithm matching", function()
281+
local jwt = {
282+
header = { alg = "PS256" },
283+
verify_signature = function(self, key)
284+
return key == "RSA_PSS_KEY"
285+
end
286+
}
287+
288+
local public_keys = {
289+
keys = { "RSA_PSS_KEY" },
290+
kids = { "kid1" },
291+
key_metadata = {
292+
{ kty = "RSA" }
293+
}
294+
}
295+
296+
local err = signature_validator.validate_signature_with_kid({}, jwt, public_keys)
297+
298+
assert.is_nil(err)
299+
end)
300+
279301
end)

src/keycloak_keys.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ local function get_issuer_keys(well_known_endpoint)
6969
-- Store metadata for fallback key selection when kid is absent
7070
key_metadata[i] = {
7171
alg = key.alg,
72-
use = key.use
72+
use = key.use,
73+
kty = key.kty
7374
}
7475
end
7576

src/validators/signature.lua

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,23 @@ local function key_matches_algorithm(key_metadata, jwt_alg)
2121
return key_metadata.alg == jwt_alg
2222
end
2323

24-
-- No alg specified on key, accept it
25-
return true
24+
-- Check kty matches algorithm family
25+
if jwt_alg then
26+
if jwt_alg:sub(1, 2) == "RS" or jwt_alg:sub(1, 2) == "PS" then
27+
-- RSA algorithms
28+
if key_metadata.kty and key_metadata.kty ~= "RSA" then
29+
return false
30+
end
31+
elseif jwt_alg:sub(1, 2) == "ES" then
32+
-- ECDSA algorithms
33+
if key_metadata.kty and key_metadata.kty ~= "EC" then
34+
return false
35+
end
36+
end
37+
end
38+
39+
-- If we get here, the key neither matches the algorithm family nor has a matching alg field, so reject it
40+
return false
2641
end
2742

2843
-- Validates a JWT signature using a key selected by kid from the provided
@@ -35,7 +50,7 @@ end
3550
-- public_keys - table with fields:
3651
-- keys = { <decoded_key1>, <decoded_key2>, ... }
3752
-- kids = { "kid1", "kid2", ... }
38-
-- key_metadata = { {alg=..., use=...}, ... }
53+
-- key_metadata = { {alg=..., use=..., kty=...}, ... }
3954
--
4055
-- Returns:
4156
-- nil on success (signature valid)

0 commit comments

Comments
 (0)