Skip to content

Commit c78adca

Browse files
test: remove kty-based key matching and simplify algorithm validation
Removes key type (kty) field from key metadata tracking and eliminates kty-based key matching logic. Simplifies algorithm validation to only check explicit alg field matches when present. Updates test descriptions to reflect that keys match when no alg is specified rather than matching by kty. Removes PS256 algorithm test and kid-optional integration test notes that are now covered by unit tests.
1 parent 7019567 commit c78adca

File tree

4 files changed

+19
-70
lines changed

4 files changed

+19
-70
lines changed

spec/01-unit/validators/signature_spec.lua

Lines changed: 13 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ describe("Plugin: jwt-keycloak (signature validator)", function()
2828
local public_keys = {
2929
keys = { "KEY_FOR_RS256" },
3030
kids = { "kid1" },
31-
key_metadata = { { alg = "RS256", use = "sig", kty = "RSA" } }
31+
key_metadata = { { alg = "RS256", use = "sig" } }
3232
}
3333

3434
local err = signature_validator.validate_signature_with_kid({}, jwt, public_keys)
@@ -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", kty = "RSA" },
49-
{ alg = "RS256", use = "sig", kty = "RSA" }
48+
{ alg = "RS256", use = "sig" },
49+
{ alg = "RS256", use = "sig" }
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", kty = "EC" } }
68+
key_metadata = { { alg = "ES256", use = "sig" } }
6969
}
7070

7171
local err = signature_validator.validate_signature_with_kid({}, jwt, public_keys)
@@ -92,7 +92,7 @@ describe("Plugin: jwt-keycloak (signature validator)", function()
9292
assert.equals("Unable to find public key for token kid", err.message)
9393
end)
9494

95-
it("should reject when kid is not found in public keys", function()
95+
it("should reject when kid is not found in public keys and no match by alg is found", function()
9696
local jwt = {
9797
header = { alg = "RS256", kid = "kidX" },
9898
}
@@ -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 key by kty when kid is missing (EC key)", function()
157+
it("should match any key when kid is missing and no alg specified", 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-
{ kty = "RSA" },
170-
{ kty = "EC" }
169+
{},
170+
{}
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", kty = "RSA" },
192-
{ alg = "RS256", use = "sig", kty = "RSA" }
191+
{ alg = "RS256", use = "enc" },
192+
{ alg = "RS256", use = "sig" }
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 but kty matches", function()
201+
it("should match when metadata has no alg specified", 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-
{ kty = "RSA" } -- no alg specified
213+
{} -- 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", kty = "RSA" }
234+
{ alg = "RS256", use = "sig" }
235235
}
236236
}
237237

@@ -276,25 +276,4 @@ 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)
300279
end)

src/keycloak_keys.lua

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,7 @@ 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,
73-
kty = key.kty
72+
use = key.use
7473
}
7574
end
7675

src/validators/signature.lua

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,11 @@ local function key_matches_algorithm(key_metadata, jwt_alg)
1717
end
1818

1919
-- If key has alg specified, it must match JWT alg
20-
if key_metadata.alg and key_metadata.alg ~= jwt_alg then
21-
return false
22-
end
23-
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
20+
if key_metadata.alg then
21+
return key_metadata.alg == jwt_alg
3722
end
3823

24+
-- No alg specified on key, accept it
3925
return true
4026
end
4127

@@ -49,7 +35,7 @@ end
4935
-- public_keys - table with fields:
5036
-- keys = { <decoded_key1>, <decoded_key2>, ... }
5137
-- kids = { "kid1", "kid2", ... }
52-
-- key_metadata = { {alg=..., use=..., kty=...}, ... }
38+
-- key_metadata = { {alg=..., use=...}, ... }
5339
--
5440
-- Returns:
5541
-- nil on success (signature valid)

tests/test_kid_optional.sh

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -51,19 +51,4 @@ if ! retry_test_after_plugin_change "Token with kid validation" "200" \
5151
fi
5252
echo "✅ Test 1 passed: Token with kid works"
5353

54-
# Note: Creating a token without kid requires:
55-
# 1. Either modifying Keycloak configuration to not include kid
56-
# 2. Or creating a custom JWT with a valid signature from the JWKS
57-
# 3. Or using a test issuer that doesn't include kid
58-
59-
echo ""
60-
echo "📝 Note: To fully test kid-optional behavior:"
61-
echo " - Configure Keycloak to issue tokens without kid, or"
62-
echo " - Create custom test tokens signed with JWKS keys but without kid header"
63-
echo " - When JWKS has a single key, tokens without kid should validate"
64-
echo " - When JWKS has multiple keys of the same type, tokens without kid should be rejected"
65-
66-
echo ""
67-
echo "✅ Kid-optional infrastructure is in place"
68-
echo "✅ Unit tests verify the kid-optional logic thoroughly"
69-
echo "✅ Integration tests confirm existing behavior (with kid) still works"
54+
echo "⚠️ The test for kid-optional JWT validation is only covered in unit tests / spec validation"

0 commit comments

Comments
 (0)