Skip to content

Commit ae1023f

Browse files
feat: add kid-based signature validation with enhanced error handling (#8)
* feat: add kid-based signature validation with enhanced error handling * feat: add automatic key selection when kid header is absent Implements fallback key selection based on JWT algorithm and key metadata when kid header is missing. Plugin now attempts to find a single unambiguous matching key by comparing JWT algorithm (RS256/384/512, PS256/384/512, ES256/384/512) with key metadata (alg, kty, use). Rejects tokens when multiple keys match or no matching key is found. Adds key_metadata tracking throughout the key retrieval chain and comprehensive test coverage for various * chore: add explicit docker network configuration for service isolation Defines kong-net bridge network and assigns all services to it for improved network isolation and DNS resolution. Adds diagnostic network connectivity test script that validates DNS resolution for kong, kc, and httpbin services during test initialization. * chore: add diagnostic logging to GitHub Actions test workflow Adds Docker version information output and failure diagnostics that display container status and logs for kong, keycloak, and test services when tests fail. Improves troubleshooting capabilities for CI test failures. * fix: add signature validator module to rockspec build configuration Registers the new validators.signature module in the rockspec build modules list and aligns formatting of validator module entries for consistency. * fix: set all fetching public keys security events to ua221 * Update src/handler.lua Co-authored-by: Luis Pflamminger <luis.pflamminger@gmail.com> * 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. * chore: bump plugin version to 1.7.0-1 --------- Co-authored-by: Luis Pflamminger <luis.pflamminger@gmail.com>
1 parent 10acf68 commit ae1023f

16 files changed

+729
-35
lines changed

.github/workflows/test.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,27 @@ jobs:
2727
- uses: actions/checkout@v4
2828
with:
2929
submodules: "true"
30+
31+
- name: Show Docker info
32+
run: |
33+
docker --version
34+
docker compose version
35+
3036
- name: Run Tests
3137
run: docker compose build --no-cache && docker compose up --exit-code-from tests tests
38+
39+
- name: Show container status
40+
if: failure()
41+
run: docker compose ps
42+
43+
- name: Show Kong logs
44+
if: failure()
45+
run: docker compose logs kong
46+
47+
- name: Show Keycloak logs
48+
if: failure()
49+
run: docker compose logs kc
50+
51+
- name: Show test logs
52+
if: failure()
53+
run: docker compose logs tests

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ RUN if [ -x "$(command -v apk)" ]; then apk add --no-cache $FIX_DEPENDENCIES; \
4444
elif [ -x "$(command -v apt-get)" ]; then apt-get remove --purge -y $FIX_DEPENDENCIES; \
4545
fi
4646

47-
ARG PLUGIN_VERSION=1.6.0-1
47+
ARG PLUGIN_VERSION=1.7.0-1
4848
RUN luarocks install /tmp/kong-plugin-jwt-keycloak-${PLUGIN_VERSION}.all.rock
4949

5050
USER kong

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,15 @@ luarocks install kong-plugin-jwt-keycloak
8888
#### Packing the rock
8989

9090
```bash
91-
export PLUGIN_VERSION=1.6.0-1
91+
export PLUGIN_VERSION=1.7.0-1
9292
luarocks make
9393
luarocks pack kong-plugin-jwt-keycloak ${PLUGIN_VERSION}
9494
```
9595

9696
#### Installing the rock
9797

9898
```bash
99-
export PLUGIN_VERSION=1.6.0-1
99+
export PLUGIN_VERSION=1.7.0-1
100100
luarocks install jwt-keycloak-${PLUGIN_VERSION}.all.rock
101101
```
102102

docker-compose.yml

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ x-kong-image: &kong-image
88
dockerfile: Dockerfile
99
args:
1010
KONG_VERSION: ${KONG_VERSION:-3.9.1}
11-
PLUGIN_VERSION: 1.6.0-1
11+
PLUGIN_VERSION: 1.7.0-1
1212
environment:
1313
KONG_DATABASE: postgres
1414
KONG_PG_HOST: postgres
@@ -30,6 +30,8 @@ services:
3030
depends_on:
3131
- postgres
3232
entrypoint: [ "/bin/sh", "-c", "until kong migrations bootstrap; do echo waiting for database; sleep 2; done;" ]
33+
networks:
34+
- kong-net
3335
kong:
3436
<<: *kong-image
3537
depends_on:
@@ -39,6 +41,8 @@ services:
3941
ports:
4042
- "8000:8000"
4143
- "8001:8001"
44+
networks:
45+
- kong-net
4246
postgres:
4347
image: postgres:16
4448
environment:
@@ -47,6 +51,8 @@ services:
4751
POSTGRES_PASSWORD: kong
4852
volumes:
4953
- pg_data:/var/lib/postgresql/data
54+
networks:
55+
- kong-net
5056
kc-pg:
5157
image: postgres:16
5258
environment:
@@ -55,6 +61,8 @@ services:
5561
POSTGRES_PASSWORD: postgres
5662
volumes:
5763
- pg_kc_data:/var/lib/postgresql/data
64+
networks:
65+
- kong-net
5866
kc:
5967
image: quay.io/keycloak/keycloak:${KEYCLOAK_VERSION:-26.2}
6068
depends_on:
@@ -75,6 +83,8 @@ services:
7583
- KC_HOSTNAME_STRICT=false
7684
- KC_HTTP_RELATIVE_PATH=/auth
7785
- KC_HTTP_ENABLED=true
86+
networks:
87+
- kong-net
7888

7989
tests:
8090
build:
@@ -91,12 +101,27 @@ services:
91101
environment:
92102
- LUA_PATH=/opt/kong-plugin-jwt-keycloak/src/?.lua;/opt/kong-plugin-jwt-keycloak/?.lua;;
93103
- LUA_CPATH=/usr/local/lib/lua/5.1/?.so;;
104+
- HTTP_PROXY=
105+
- HTTPS_PROXY=
106+
- NO_PROXY="localhost,127.0.0.1"
107+
- http_proxy=
108+
- https_proxy=
109+
- no_proxy="localhost,127.0.0.1"
110+
networks:
111+
- kong-net
94112
entrypoint: [ "/bin/sh", "-c", "cd /opt/tests && /bin/sh ./run_tests.sh" ]
95113

96114
httpbin:
97115
image: mccutchen/go-httpbin:2.18.3
98116
ports:
99117
- "8080"
118+
networks:
119+
- kong-net
120+
121+
networks:
122+
kong-net:
123+
driver: bridge
124+
100125
volumes:
101126
pg_data:
102127
pg_kc_data:
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
local plugin_name = "jwt-keycloak"
22
local package_name = "kong-plugin-" .. plugin_name
3-
local package_version = "1.6.0"
3+
local package_version = "1.7.0"
44
local rockspec_revision = "1"
55

66
local github_account_name = "telekom"
@@ -38,8 +38,9 @@ build = {
3838
["kong.plugins."..plugin_name..".keycloak_keys"] = "src/keycloak_keys.lua",
3939
["kong.plugins."..plugin_name..".key_conversion"] = "src/key_conversion.lua",
4040
["kong.plugins."..plugin_name..".gateway.securitylog"] = "src/gateway/securitylog.lua",
41-
["kong.plugins."..plugin_name..".validators.issuers"] = "src/validators/issuers.lua",
42-
["kong.plugins."..plugin_name..".validators.roles"] = "src/validators/roles.lua",
43-
["kong.plugins."..plugin_name..".validators.scope"] = "src/validators/scope.lua",
41+
["kong.plugins."..plugin_name..".validators.issuers"] = "src/validators/issuers.lua",
42+
["kong.plugins."..plugin_name..".validators.roles"] = "src/validators/roles.lua",
43+
["kong.plugins."..plugin_name..".validators.scope"] = "src/validators/scope.lua",
44+
["kong.plugins."..plugin_name..".validators.signature"] = "src/validators/signature.lua",
4445
}
4546
}
File renamed without changes.

spec/01-unit/keycloak_keys_spec.lua

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,24 @@ describe("Plugin: jwt-keycloak (keycloak_keys)", function()
5454
assert.is_function(keycloak_keys.get_request)
5555
end)
5656
end)
57+
58+
describe("get_issuer_keys", function()
59+
it("should return keys and aligned kids from JWKS", function()
60+
local well_known_endpoint = "https://keycloak.example.com/auth/realms/test/.well-known/openid-configuration"
61+
62+
local keys, kids, err, key_metadata = keycloak_keys.get_issuer_keys(well_known_endpoint)
63+
64+
assert.is_nil(err)
65+
assert.is_table(keys)
66+
assert.is_table(kids)
67+
assert.is_table(key_metadata)
68+
assert.equals(2, #keys)
69+
assert.equals(2, #kids)
70+
assert.equals(2, #key_metadata)
71+
assert.same({ "kid1", "kid2" }, kids)
72+
-- Verify metadata structure
73+
assert.is_table(key_metadata[1])
74+
assert.is_table(key_metadata[2])
75+
end)
76+
end)
5777
end)

0 commit comments

Comments
 (0)