-
Notifications
You must be signed in to change notification settings - Fork 170
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
THREESCALE-9009 fix OIDC jwt key verification #1389
Conversation
6713c46
to
22559eb
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just a change to the error message printed which would be super helpful in future troubleshooting and a minor change to the description of the integration test so we can check the scenarios tested as well in future.
The rest looks good otherwise.
gateway/src/apicast/oauth/oidc.lua
Outdated
@@ -185,8 +185,12 @@ function _M:verify(jwt, cache_key) | |||
-- Find jwk with matching kid for current JWT in request | |||
local jwk_obj = find_jwk(jwt, self.keys) | |||
|
|||
if jwk_obj == nil then | |||
return false, '[jwk] jwk not found, token might not belong to right realm' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest the following log message which would be more explicit and accurate:
ngx.log(ngx.ERR, "[jwt] failed verification for kid: ", jwt.header.kid)
return false, '[jwk] not found, token might belong to a different realm'
This would help customers identify the issue quicker and without having to enable debug log level.
t/apicast-oidc.t
Outdated
@@ -362,3 +362,43 @@ my $jwt = 'eyJraWQiOiJzb21la2lkIiwiYWxnIjoiSFMyNTYifQ.'. | |||
"Authorization: Bearer $jwt" | |||
--- error_log | |||
[jwt] alg mismatch | |||
|
|||
=== TEST 8: Key not available | |||
(Happens when the token belongs to a different realm) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the more accurate test description is that the "token was signed by a different key". The same key could be used accross multiple realms but with this fix the iss
claim will be correctly validated against the issuer
field in the proxy config. Equally if the kid
s don't match then it won't even find the jwk.
In fact we can see that further down in this test, we have different realms but the logic never gets that far in the validation process because it fails before that with "[jwk] jwk not found"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added a test for the verification of the expected issuer
t/apicast-oidc.t
Outdated
exp => time + 3600 }, key => \$::private_key, alg => 'RS256', extra_headers => { kid => 'otherkid' }); | ||
"Authorization: Bearer $jwt" | ||
--- error_log | ||
[jwk] jwk not found |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you use the same error message suggested in my review then this should be updated to look for [jwk] not found
, to save you from a failing test you would need to fix 😉
Thanks for the review @kevprice83. All comments addressed. Ready for a new review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like that additional last test yes! Also it's using the reason field on the verification object so I think this makes the test super clear. Nice improvement :)
Everything else looks good 🥇
what
Fixes THREESCALE-9009 Token generated for a realm associated with a different 3scale Product is able to reach the upstream with no verification performed
When a oidc JWT belonging to realm A is used in a request targeting a 3scale service configured with OIDC authentication with clients configured in realm B, the first conflict APIcast finds is that the referenced public key (in the JWT) does not exist. This PR address this issue adding a check on the JWKey object.
In the absence of this check, the lua code was working with a
nil
object and raised an error (runtime error: nil pointer dereference) captured only by the policy chain manager.When this error is raised, the current policy processing stage is halted and skipped, moving on to the next policy in the chain. The token is not even verified with the JWT library as it should be in the next step
That causes the APIcast context to enter in a inconsistent state. Specifically, nginx
ctx.credentials
is not populated. Maybe more info but I have not gone through all of them because it is inconsistent, hence unpredictable behavior:app_id
. Backend responds with404 Not Found
(as expected) but APICast ignores this and returns 200 OK to the downstream client.404 Not Found
to the upstream client. Additionally, APIcast sends a request to backend with a missingapp_id
. Backend responds with404 Not Found
(as expected).With the check on the JWKey object, APIcast deals with a managed error (the token is invalid) and the behavior is expected, returning
403 Forbidden
to the downstream client as expected. In that case, backend is not called.Verification steps
HTTP/1.1 403 Forbidden