Skip to content
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

allow JWT token to be sent as a cookie #2974

Closed

Conversation

mvanholsteijn
Copy link
Contributor

Summary

Added support for passing the JWT in a cookie. When one or more 'cookie_names' are specified, the plugin will try to retrieve the jwt from the specified cookies in order.

There are a number of pull requests open which seem to be aborted. I will take it on me to get it done.

Full changelog

  • When the jwt plugin is configured with the property 'cookie_names', the plugin will
    attempt to retrieve the jwt token from one of the named cookies.

Issues resolved

#2911
#2894
#2363

When the jwt plugin is configured with the property cookie_names, the plugin will
get the jwt token from one of the named cookies.
@mvanholsteijn
Copy link
Contributor Author

I have a getkong.org documentation change too. https://github.com/mvanholsteijn/getkong.org/tree/jwt-authentication-in-cookies

@danotrampus
Copy link

Nice work!! I already implemented you solution and works great.
+1

@mvanholsteijn
Copy link
Contributor Author

Hmm, that is strange. There is an error travis-ci on code that I did not touch..

@hishamhm
Copy link
Contributor

Hmm, that is strange. There is an error travis-ci on code that I did not touch..

We are aware that some tests in Travis CI are occasionally producing flaky results (they usually pass when re-running) but we're working on fixing this, sorry about the noise it occasionally produces.

@mvanholsteijn
Copy link
Contributor Author

Thanks for fixing the integration test! Can you review to code too? there is already two happy users ;-)

Copy link
Contributor

@hishamhm hishamhm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mvanholsteijn Sure! Adding a new config field requires a migration to the database for updating the default value of the new field in existing tables. See commits 2040ede and fb55de3 for an example of adding a migration.

@hishamhm hishamhm added the pr/changes requested Changes were requested to this PR by a maintainer. Please address them and ping back once done. label Oct 24, 2017
@mvanholsteijn
Copy link
Contributor Author

mvanholsteijn commented Oct 25, 2017

@hishamhm I manually tested the migrations from kong 0.11.0 to this branch on both postgres and cassandra. There is no automated CI test for it, is there?

@hishamhm
Copy link
Contributor

@mvanholsteijn thank you! unfortunately no automated tests for migrations at the moments. It's in our to-do list, though!

@hishamhm hishamhm added pr/ready This PR is considered ready and can be merged at anytime (given it received no subsequent changes) and removed pr/changes requested Changes were requested to this PR by a maintainer. Please address them and ping back once done. labels Oct 26, 2017
@@ -28,6 +28,13 @@ local function retrieve_token(request, conf)
end
end

for _, v in ipairs(conf.cookie_names) do
local jwt_cookie = ngx.unescape_uri(ngx.var["cookie_" .. v])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The access to the ngx global in a loop in such a hot code path warrants a caching of the unescape_uri function at the top of this module:

local unescape_uri = ngx.unescape_uri

The same way, the ngx.var access should be cached locally at the function's level:

local var = ngx.var

for _, v in ipairs(conf.cookie_names) do
  local escaped_cookie = var["cookie_" .. v]
  if escaped_cookie then
    return unescape_uri(escaped_cookie)
  end
end

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on second looks; the jwt itself is safe-base64 encoded, so the unescape_uri call is not required.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, was also having second thoughts about it. Curious to hear @mvanholsteijn 's take on why this seemed to be required?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the unescape_uri code ; I do not believe it is necessary too.

for _, v in ipairs(conf.cookie_names) do
local jwt_cookie = ngx.unescape_uri(ngx.var["cookie_" .. v])
if jwt_cookie and jwt_cookie ~= "" then
return jwt_cookie, nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for the second return value (nil) here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.

@@ -14,7 +14,7 @@ local JwtHandler = BasePlugin:extend()
JwtHandler.PRIORITY = 1005

--- Retrieve a JWT in a request.
-- Checks for the JWT in URI parameters, then in the `Authorization` header.
-- Checks for the JWT in URI parameters, then for a JWT token in a cookie names and then the `Authorization` header.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please try to keep lines under 80 character long, as per our contribution guidelines :) Thank you!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.

}
})
assert.res_status(200, res)
end)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While the state of the code today implies that a fallback on the Authorization header will also imply an HTTP 403 will occur when necessary, this might not be the case in the future, say, if a refactor of the code occurs. I'd feel more comfortable if we included a test for HTTP 403 on a plugin with cookie_names, when not sending cookies nor an Authorization header.

What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it should be a 401 (Unauthenticated). I added the test to include this case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, sorry - sent this review from a meeting... I think the new one you added is a nice addition, thanks. I also think we need the HTTP 403 case (Forbidden) which is present in other tests paths, but not the one from a cookie.

Copy link
Contributor Author

@mvanholsteijn mvanholsteijn Oct 27, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added one in the JWT cookie case. I left it out before, as all the other tests already validate the proper operation after a token was found. The added tests for cookie_names merely focused on finding the cookie token. Anyway, it is in there!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, those are integration tests and leaving such a test out would mean testing this behavior with expectations and assumptions made about the underlying implementation. Preferably, integration tests don't make any assumptions about the tested code and does assume that the system is a black box. Thank you for adding it.

end)
it("reports a 401 if the JWT in cookie is corrupt", function()
PAYLOAD.iss = jwt_secret.key
local jwt = 'no-way-this-works' .. jwt_encoder.encode(PAYLOAD, jwt_secret.secret)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Please only use double quotes when possible, thank you!)

@@ -6,6 +6,7 @@ local jwt_decoder = require "kong.plugins.jwt.jwt_parser"
local string_format = string.format
local ngx_re_gmatch = ngx.re.gmatch

local ngx_var = ngx.var
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it is a good idea to cache ngx.var (a per-request variable) value at the module level... This is why I suggested caching it in the function (as per other parts of our codebase do).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand. I moved it into the function.

thibaultcha pushed a commit that referenced this pull request Oct 27, 2017
When the JWT plugin is configured with the property cookie_names, the
plugin will get the JWT token from one of the named cookies.

* add `config.cookie_names` ocnfiguration option
* add migration for previous records of this plugin
* add integration test suite

From #2974
Fix #2911 #2894

Signed-off-by: Thibault Charbonnier <thibaultcha@me.com>
@thibaultcha
Copy link
Member

@mvanholsteijn Thank you for helping us and driving this! I just merged this feature as a (slightly modified) squashed commit in next. Will you please open a PR against Kong/getkong.org with the changes you made to the documentation? Thank you!

@mvanholsteijn
Copy link
Contributor Author

sure will do!

thibaultcha pushed a commit to Kong/docs.konghq.com that referenced this pull request Dec 19, 2017
See Kong/kong#2974
From #539

Signed-off-by: Thibault Charbonnier <thibaultcha@me.com>
thibaultcha pushed a commit to Kong/docs.konghq.com that referenced this pull request Jan 12, 2018
See Kong/kong#2974
From #539

Signed-off-by: Thibault Charbonnier <thibaultcha@me.com>
thibaultcha pushed a commit to Kong/docs.konghq.com that referenced this pull request Jan 16, 2018
See Kong/kong#2974
From #539

Signed-off-by: Thibault Charbonnier <thibaultcha@me.com>
thibaultcha pushed a commit to Kong/docs.konghq.com that referenced this pull request Jan 16, 2018
See Kong/kong#2974
From #539

Signed-off-by: Thibault Charbonnier <thibaultcha@me.com>
thibaultcha pushed a commit that referenced this pull request Jan 16, 2018
When the JWT plugin is configured with the property cookie_names, the
plugin will get the JWT token from one of the named cookies.

* add `config.cookie_names` ocnfiguration option
* add migration for previous records of this plugin
* add integration test suite

From #2974
Fix #2911 #2894

Signed-off-by: Thibault Charbonnier <thibaultcha@me.com>
thibaultcha pushed a commit that referenced this pull request Jan 19, 2018
When the JWT plugin is configured with the property cookie_names, the
plugin will get the JWT token from one of the named cookies.

* add `config.cookie_names` ocnfiguration option
* add migration for previous records of this plugin
* add integration test suite

From #2974
Fix #2911 #2894

Signed-off-by: Thibault Charbonnier <thibaultcha@me.com>
mvanholsteijn added a commit to mvanholsteijn/kong that referenced this pull request Mar 27, 2018
When the JWT plugin is configured with the property cookie_names, the
plugin will get the JWT token from one of the named cookies.

* add `config.cookie_names` ocnfiguration option
* add migration for previous records of this plugin
* add integration test suite

From Kong#2974
Fix Kong#2911 Kong#2894

Signed-off-by: Thibault Charbonnier <thibaultcha@me.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pr/ready This PR is considered ready and can be merged at anytime (given it received no subsequent changes)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants