Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Add `APICAST_LUA_SOCKET_KEEPALIVE_REQUESTS` to limit the number of requests a single keepalive socket can handle [PR #1496](https://github.com/3scale/APIcast/pull/1496) [THREESCALE-11321](https://issues.redhat.com/browse/THREESCALE-11321)
- Replace internal OPENSSL module with lua-resty-openssl [PR #1502](https://github.com/3scale/APIcast/pull/1502) [THREESCALE-11412](https://issues.redhat.com/browse/THREESCALE-11412)
- Remove opentracing support [PR #1520](https://github.com/3scale/APIcast/pull/1520) [THREESCALE-11603](https://issues.redhat.com/browse/THREESCALE-11603)
- JWT signature verification, support for ES256/ES512 #1533 [PR #1533](https://github.com/3scale/APIcast/pull/1533) [THREESCALE-11474](https://issues.redhat.com/browse/THREESCALE-11474)

## [3.15.0] 2024-04-04

Expand Down
11 changes: 9 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM registry.access.redhat.com/ubi8:8.5

ARG OPENRESTY_RPM_VERSION="1.21.4-1.el8"
ARG LUAROCKS_VERSION="2.3.0"
ARG LUAROCKS_VERSION="3.11.1"
ARG JAEGERTRACING_CPP_CLIENT_RPM_VERSION="0.3.1-13.el8"

LABEL summary="The 3scale API gateway (APIcast) is an OpenResty application, which consists of two parts: NGINX configuration and Lua files." \
Expand Down Expand Up @@ -47,7 +47,6 @@ ENV PATH="./lua_modules/bin:/usr/local/openresty/luajit/bin/:${PATH}" \
RUN luarocks install --deps-mode=none --tree /usr/local https://luarocks.org/manifests/pintsized/lua-resty-http-0.17.1-0.src.rock
RUN luarocks install --deps-mode=none --tree /usr/local https://luarocks.org/manifests/kikito/router-2.1-0.src.rock
RUN luarocks install --deps-mode=none --tree /usr/local https://luarocks.org/manifests/kikito/inspect-3.1.1-0.src.rock
RUN luarocks install --deps-mode=none --tree /usr/local https://luarocks.org/manifests/cdbattags/lua-resty-jwt-0.2.0-0.src.rock
RUN luarocks install --deps-mode=none --tree /usr/local https://luarocks.org/manifests/3scale/lua-resty-url-0.3.5-1.src.rock
RUN luarocks install --deps-mode=none --tree /usr/local https://luarocks.org/manifests/3scale/lua-resty-env-0.4.0-1.src.rock
RUN luarocks install --deps-mode=none --tree /usr/local https://luarocks.org/manifests/3scale/liquid-0.2.0-2.src.rock
Expand All @@ -63,6 +62,14 @@ RUN luarocks install --deps-mode=none --tree /usr/local https://luarocks.org/man
RUN luarocks install --deps-mode=none --tree /usr/local https://luarocks.org/manifests/membphis/lua-resty-ipmatcher-0.6.1-0.src.rock
RUN luarocks install --deps-mode=none --tree /usr/local https://luarocks.org/manifests/fffonion/lua-resty-openssl-1.5.1-1.src.rock

# Install lua-resty-jwt from source due to Authentication Bypass bug
# See https://github.com/cdbattags/lua-resty-jwt/issues/61
RUN cd /tmp \
&& git clone --recurse-submodules https://github.com/cdbattags/lua-resty-jwt \
&& cd lua-resty-jwt \
&& git reset --hard d1558e2 \
&& luarocks make --tree /usr/local lua-resty-jwt-dev-0.rockspec

RUN yum -y remove libyaml-devel m4 openssl-devel git gcc luarocks && \
rm -rf /var/cache/yum && yum clean all -y && \
rm -rf ./*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Source0: licenses.xml
Source1: lua-resty-http-0.17.1-0.src.rock
Source2: router-2.1-0.src.rock
Source3: inspect-3.1.1-0.src.rock
Source4: lua-resty-jwt-0.2.0-0.src.rock
Source4: lua-resty-jwt-0.2.3-1.src.rock
Source5: lua-resty-url-0.3.5-1.src.rock
Source6: lua-resty-env-0.4.0-1.src.rock
Source7: liquid-0.2.0-2.src.rock
Expand Down Expand Up @@ -80,6 +80,8 @@ rm -rf %{buildroot}
%license licenses.xml

%changelog
* Mon Jan 03 2025 An Tran <atra@redhat.com> - 2.10.0-2
- Upgrade lua-resty-jwt to v0.2.3-1

* Fri Dec 02 2022 Yorgos Saslis <gsaslisl@redhat.com> - 2.10.0-1
- Minor version bump to clarify lua-liquid dependency bump that already happened in 2.9.6-12
Expand Down
2 changes: 1 addition & 1 deletion dependencies/rpm-specs/gateway-rockspecs/rockspecs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
https://luarocks.org/manifests/pintsized/lua-resty-http-0.17.1-0.rockspec
https://luarocks.org/manifests/kikito/router-2.1-0.rockspec
https://luarocks.org/manifests/kikito/inspect-3.1.1-0.rockspec
https://luarocks.org/manifests/cdbattags/lua-resty-jwt-0.2.0-0.rockspec
https://luarocks.org/manifests/cdbattags/lua-resty-jwt-0.2.3-0.rockspec
https://luarocks.org/manifests/3scale/lua-resty-url-0.3.5-1.rockspec
https://luarocks.org/manifests/3scale/lua-resty-env-0.4.0-1.rockspec
https://luarocks.org/manifests/3scale/liquid-0.2.0-2.rockspec
Expand Down
Binary file not shown.
Binary file not shown.
2 changes: 1 addition & 1 deletion gateway/Roverfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ lua-resty-http 0.17.1-0|4ab4269cf442ba52507aa2c718f606054452fcad|production
lua-resty-ipmatcher 0.6.1-0|62d4c44d67227e8f3fe02331c2f8b90fe0d7ccd1|production
lua-resty-iputils 0.3.0-2|6110b41eaa52efd25e56f89e34412ab95f700d57|production
lua-resty-jit-uuid 0.0.7-2|64ae38de75c9d58f330d89e140ac872771c19223|production
lua-resty-jwt 0.2.0-0|2a62ff95eae91df6bd8655080a4b9b04c61bec6b|production
lua-resty-jwt 0.2.3-0|b3d5c085643fa95099e72a609c57095802106ff9|production
lua-resty-openssl 1.5.1-1|a900c5f5897448c181dd58073e51cdeeb3fd0029|production
lua-resty-repl 0.0.6-0|3878f41b7e8f97b1c96919db19dbee9496569dda|development
lua-resty-url 0.3.5-1||production
Expand Down
2 changes: 1 addition & 1 deletion gateway/apicast-scm-1.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ dependencies = {
'inspect',
'lyaml',
'router',
'lua-resty-jwt == 0.2.0',
'lua-resty-jwt',
'lua-resty-url',
'lua-resty-env',
'lua-resty-execvp',
Expand Down
49 changes: 49 additions & 0 deletions spec/fixtures/certs.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
return {
rsa_public_key = [[
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALClz96cDQ965ENYMfZzG+Acu25lpx2K
NpAALBQ+catCA59us7+uLY5rjQR6SOgZpCz5PJiKNAdRPDJMXSmXqM0CAwEAAQ==
-----END PUBLIC KEY-----
]],
rsa_private_key = [[
-----BEGIN RSA PRIVATE KEY-----
MIIBPAIBAAJBALClz96cDQ965ENYMfZzG+Acu25lpx2KNpAALBQ+catCA59us7+u
LY5rjQR6SOgZpCz5PJiKNAdRPDJMXSmXqM0CAwEAAQJBAJnwZa4BIACVf8aQXToA
JhKv90bFn1TG1bW38LHTmQs8EM9XCmghLWCje7d/NbUrUceotIOnjtv/xHTywGt2
NwECIQDhvMZDQ+ZRRbbwONcvO9G7h6hFgy0okiv6JciZccvtxQIhAMhUTAWgV1hQ
O2yWTRYRQZosEIsFB3kZfsLMeTKjk8dpAiEAslsZ92m9n3dKrJDsjFhiRR5ROOMF
Gior7xBNZ9e+vdUCIDsjf4nNqttcXB6TRFB2aapsxbl0k58xYpV5LXJAjfi5AiEA
vRaSauBfRCP3JgXHNgcDSW017/BtbwGiz8aITv6B0Fw=
-----END RSA PRIVATE KEY-----
]],
es256_public_key = [[
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERm/e/qZmgIyVSksHrHh1lzf9F6WT
oTKnyWLfLdz8SZiaLVaI1GW3GekLwVlbKZUkmqUnKfrNs2U9DuJ3jSyX8A==
-----END PUBLIC KEY-----
]],
es256_private_key = [[
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIA8Bv35dnS289gK/lBbp0bj3LzFuvFvZowNClcUW4E84oAoGCCqGSM49
AwEHoUQDQgAERm/e/qZmgIyVSksHrHh1lzf9F6WToTKnyWLfLdz8SZiaLVaI1GW3
GekLwVlbKZUkmqUnKfrNs2U9DuJ3jSyX8A==
-----END EC PRIVATE KEY-----
]],
es512_public_key = [[
-----BEGIN PUBLIC KEY-----
MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQB85b81Iol6jVQwVuusRR4SYHUN6oP
KhLWWyobYydIJ/VAmmEHg5Wi/VcYpP3/qlatMhuQPKjC/j4lfLal716byRoAcEtS
+V4w6yT1pIszwAovp8u4PJpEoe3f9JosV3Wvmzauk+o0uaW/cFiarb81hQDTD/Go
xFWEYfqgS1kv+NpEJAA=
-----END PUBLIC KEY-----
]],
es512_private_key = [[
-----BEGIN EC PRIVATE KEY-----
MIHcAgEBBEIBEsogZYirhy12UPSwJx3ps/6j9fRHdIrqzUfz8uDz1xZ4KGm1uzyQ
oB355ifR/5IriiWzai1LZM+dyR1uS8wV2qKgBwYFK4EEACOhgYkDgYYABAHzlvzU
iiXqNVDBW66xFHhJgdQ3qg8qEtZbKhtjJ0gn9UCaYQeDlaL9Vxik/f+qVq0yG5A8
qML+PiV8tqXvXpvJGgBwS1L5XjDrJPWkizPACi+ny7g8mkSh7d/0mixXda+bNq6T
6jS5pb9wWJqtvzWFANMP8ajEVYRh+qBLWS/42kQkAA==
-----END EC PRIVATE KEY-----
]],
}
19 changes: 0 additions & 19 deletions spec/fixtures/rsa.lua

This file was deleted.

92 changes: 72 additions & 20 deletions spec/oauth/oidc_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ local _M = require('apicast.oauth.oidc')
local jwt_validators = require('resty.jwt-validators')
local jwt = require('resty.jwt')

local rsa = require('fixtures.rsa')
local certs = require('fixtures.certs')
local ngx_variable = require('apicast.policy.ngx_variable')

describe('OIDC', function()
Expand Down Expand Up @@ -43,19 +43,29 @@ describe('OIDC', function()
local oidc_config = {
issuer = 'https://example.com/auth/realms/apicast',
config = { id_token_signing_alg_values_supported = { 'RS256', 'HS256' } },
keys = { somekid = { pem = rsa.pub, alg = 'RS256' } },
keys = { somekid = { pem = certs.rsa_public_key, alg = 'RS256' } },
}
local es256_oidc_config = {
issuer = 'https://example.com/auth/realms/apicast',
config = { id_token_signing_alg_values_supported = { 'ES256'} },
keys = { somekid = { pem = certs.es256_public_key, alg = 'ES256' } },
}
local es512_oidc_config = {
issuer = 'https://example.com/auth/realms/apicast',
config = { id_token_signing_alg_values_supported = { 'ES512' } },
keys = { somekid = { pem = certs.es512_public_key, alg = 'ES512' } },
}
local oidc_config_no_alg = {
issuer = 'https://example.com/auth/realms/apicast',
config = { id_token_signing_alg_values_supported = { 'RS256', 'HS256' } },
keys = { somekid = { pem = rsa.pub } },
keys = { somekid = { pem = certs.rsa_public_key } },
}

before_each(function() jwt_validators.set_system_clock(function() return 0 end) end)

it('successfully verifies token', function()
it('successfully verifies token using RS256', function()
local oidc = _M.new(oidc_config)
local access_token = jwt:sign(rsa.private, {
local access_token = jwt:sign(certs.rsa_private_key, {
header = { typ = 'JWT', alg = 'RS256', kid = 'somekid' },
payload = {
iss = oidc_config.issuer,
Expand All @@ -74,9 +84,51 @@ describe('OIDC', function()
assert.equal(10, ttl)
end)

it('successfully verifies token using ES256', function()
local oidc = _M.new(es256_oidc_config)
local access_token = jwt:sign(certs.es256_private_key, {
header = { typ = 'JWT', alg = 'ES256', kid = 'somekid' },
payload = {
iss = oidc_config.issuer,
aud = 'notused',
azp = 'ce3b2e5e',
sub = 'someone',
exp = ngx.now() + 10,
},
})

local credentials, ttl, _, err = oidc:transform_credentials({ access_token = access_token })

assert(credentials, err)

assert.same({ app_id = "ce3b2e5e" }, credentials)
assert.equal(10, ttl)
end)

it('successfully verifies token using ES512', function()
local oidc = _M.new(es512_oidc_config)
local access_token = jwt:sign(certs.es512_private_key, {
header = { typ = 'JWT', alg = 'ES512', kid = 'somekid' },
payload = {
iss = oidc_config.issuer,
aud = 'notused',
azp = 'ce3b2e5e',
sub = 'someone',
exp = ngx.now() + 10,
},
})

local credentials, ttl, _, err = oidc:transform_credentials({ access_token = access_token })

assert(credentials, err)

assert.same({ app_id = "ce3b2e5e" }, credentials)
assert.equal(10, ttl)
end)

it('caches verification', function()
local oidc = _M.new(oidc_config)
local access_token = jwt:sign(rsa.private, {
local access_token = jwt:sign(certs.rsa_private_key, {
header = { typ = 'JWT', alg = 'RS256', kid = 'somekid' },
payload = {
iss = oidc_config.issuer,
Expand All @@ -103,7 +155,7 @@ describe('OIDC', function()

it('verifies iss', function()
local oidc = _M.new(oidc_config)
local access_token = jwt:sign(rsa.private, {
local access_token = jwt:sign(certs.rsa_private_key, {
header = { typ = 'JWT', alg = 'RS256', kid = 'somekid' },
payload = {
iss = oidc_config.issuer,
Expand All @@ -124,7 +176,7 @@ describe('OIDC', function()
stub(ngx, 'now', now)

local oidc = _M.new(oidc_config)
local access_token = jwt:sign(rsa.private, {
local access_token = jwt:sign(certs.rsa_private_key, {
header = { typ = 'JWT', alg = 'RS256', kid = 'somekid' },
payload = {
iss = oidc_config.issuer,
Expand All @@ -142,7 +194,7 @@ describe('OIDC', function()

it('verifies iat', function()
local oidc = _M.new(oidc_config)
local access_token = jwt:sign(rsa.private, {
local access_token = jwt:sign(certs.rsa_private_key, {
header = { typ = 'JWT', alg = 'RS256', kid = 'somekid' },
payload = {
iss = oidc_config.issuer,
Expand All @@ -160,7 +212,7 @@ describe('OIDC', function()

it('verifies exp', function()
local oidc = _M.new(oidc_config, {})
local access_token = jwt:sign(rsa.private, {
local access_token = jwt:sign(certs.rsa_private_key, {
header = { typ = 'JWT', alg = 'RS256', kid = 'somekid' },
payload = {
iss = oidc_config.issuer,
Expand All @@ -184,7 +236,7 @@ describe('OIDC', function()

it('verifies alg', function()
local oidc = _M.new(oidc_config)
local access_token = jwt:sign(rsa.private, {
local access_token = jwt:sign(certs.rsa_private_key, {
header = { typ = 'JWT', alg = 'HS512' },
payload = { },
})
Expand All @@ -197,7 +249,7 @@ describe('OIDC', function()

it('validation fails when typ is invalid', function()
local oidc = _M.new(oidc_config)
local access_token = jwt:sign(rsa.private, {
local access_token = jwt:sign(certs.rsa_private_key, {
header = { typ = 'JWT', alg = 'RS256', kid = 'somekid' },
payload = {
iss = oidc_config.issuer,
Expand All @@ -217,7 +269,7 @@ describe('OIDC', function()

it('validation is successful when typ is included and is Bearer', function()
local oidc = _M.new(oidc_config)
local access_token = jwt:sign(rsa.private, {
local access_token = jwt:sign(certs.rsa_private_key, {
header = { typ = 'JWT', alg = 'RS256', kid = 'somekid' },
payload = {
iss = oidc_config.issuer,
Expand All @@ -236,7 +288,7 @@ describe('OIDC', function()

it('validation fails when jwk.alg does not match jwt.header.alg', function()
local oidc = _M.new(oidc_config)
local access_token = jwt:sign(rsa.private, {
local access_token = jwt:sign(certs.rsa_private_key, {
header = { typ = 'JWT', alg = 'HS256', kid = 'somekid' },
payload = {
iss = oidc_config.issuer,
Expand All @@ -256,7 +308,7 @@ describe('OIDC', function()

it('validation passes when jwk.alg matches jwt.header.alg', function()
local oidc = _M.new(oidc_config)
local access_token = jwt:sign(rsa.private, {
local access_token = jwt:sign(certs.rsa_private_key, {
header = { typ = 'JWT', alg = 'RS256', kid = 'somekid' },
payload = {
iss = oidc_config.issuer,
Expand All @@ -275,7 +327,7 @@ describe('OIDC', function()

it('validation passes when jwk.alg does not exist', function()
local oidc = _M.new(oidc_config_no_alg)
local access_token = jwt:sign(rsa.private, {
local access_token = jwt:sign(certs.rsa_private_key, {
header = { typ = 'JWT', alg = 'RS256', kid = 'somekid' },
payload = {
iss = oidc_config.issuer,
Expand All @@ -294,7 +346,7 @@ describe('OIDC', function()

it('token was signed by a different key', function()
local oidc = _M.new(oidc_config)
local access_token = jwt:sign(rsa.private, {
local access_token = jwt:sign(certs.rsa_private_key, {
header = { typ = 'JWT', alg = 'RS256', kid = 'otherkid' },
payload = {
iss = oidc_config.issuer,
Expand All @@ -312,7 +364,7 @@ describe('OIDC', function()

it('token was signed by a different issuer', function()
local oidc = _M.new(oidc_config)
local access_token = jwt:sign(rsa.private, {
local access_token = jwt:sign(certs.rsa_private_key, {
header = { typ = 'JWT', alg = 'RS256', kid = 'somekid' },
payload = {
iss = 'other_issuer',
Expand All @@ -334,7 +386,7 @@ describe('OIDC', function()
stub(ngx_variable, 'available_context', function(context) return context end)
end)

local access_token = jwt:sign(rsa.private, {
local access_token = jwt:sign(certs.rsa_private_key, {
header = { typ = 'JWT', alg = 'RS256', kid = 'somekid' },
payload = {
iss = oidc_config.issuer,
Expand All @@ -350,7 +402,7 @@ describe('OIDC', function()
local config = {
issuer = 'https://example.com/auth/realms/apicast',
config = { id_token_signing_alg_values_supported = { 'RS256' } },
keys = { somekid = { pem = rsa.pub, alg = 'RS256' } }}
keys = { somekid = { pem = certs.rsa_public_key, alg = 'RS256' } }}

for key,value in pairs(params) do
config[key] = value
Expand Down
4 changes: 2 additions & 2 deletions spec/policy/3scale_batcher/keys_helper_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ local keys_helper = require 'apicast.policy.3scale_batcher.keys_helper'
local Usage = require 'apicast.usage'
local Transaction = require 'apicast.policy.3scale_batcher.transaction'
local JWT = require('resty.jwt')
local rsa = require('fixtures.rsa')
local certs = require('fixtures.certs')

local access_token = setmetatable({
header = { typ = 'JWT', alg = 'RS256', kid = 'somekid' },
Expand All @@ -12,7 +12,7 @@ local access_token = setmetatable({
aud = 'one',
exp = ngx.now() + 3600,
},
}, { __tostring = function(jwt) return JWT:sign(rsa.private, jwt) end })
}, { __tostring = function(jwt) return JWT:sign(certs.rsa_private_key, jwt) end })

describe('Keys Helper', function()
describe('.key_for_cached_auth', function()
Expand Down
Loading