feat: add support for password grant in authz-keycloak plugin#6586
Conversation
Squashed commit: [99ff9f4] refactor: Removing unnecessary properties (apache#6574) Removing unnecessary properties and test codes. And also improve document for Token generation feature. feat: apache#6574 [22c8d8e] feat: Support of password grant type for token generation (apache#6574) Committing changes after adding new feature for generating token based on `user id/password` and also taking support of grant type `password` feat: apache#6574
|
you should sing the CLA first |
|
Missing unit tests |
e555a00 to
3d1e27b
Compare
Better variable names. Documentation updated as per guideline.
3d1e27b to
fc96102
Compare
|
Hi, I will need little guidance for the CLA signing process from your side. In PR, I have made the following changes.
Please let me know the next actions for me. |
…using password_grant_token_generation_incoming_uri. I have removed some more errors reported by git workflow build process.
There is no CLA file for APISIX :)
As the keycloak environment is set up by @sshniro, |
|
I checked the logs of above test runs. I have used following settings in my test scenario: I took the above settings from other Keycloak test cases. And it worked properly. Another issue is reported as: "ERROR: apisix/plugins/authz-keycloak.lua: line 719: getting the Lua global "string"" For which I made fix "local str_find = string.find", so it should be fixed now. |
|
|
||
| -- To get new access token by calling get token api | ||
| local function generate_token_using_password_grant(conf,ctx) | ||
| log.warn("generate_token_using_password_grant Function Called") |
There was a problem hiding this comment.
Why should we use warn level ?
There was a problem hiding this comment.
Agree... it should be debug level log. I changed it.
| --Read Body | ||
| ngx.req.read_body() | ||
| --Get Body Data | ||
| local request_body=ngx.req.get_body_data() |
There was a problem hiding this comment.
You can use core.request.get_body() instead.
There was a problem hiding this comment.
Done. I changed it.
| return 401, {message = err} | ||
| end | ||
|
|
||
| return res.status, res.body |
There was a problem hiding this comment.
| return res.status, res.body | |
| return res.status, res.body |
|
|
||
| if conf.password_grant_token_generation_incoming_uri then | ||
| if ngx.var.request_uri:upper() | ||
| == conf.password_grant_token_generation_incoming_uri:upper() then |
There was a problem hiding this comment.
Good Suggestion and changed it to use and for all three conditions.
| local username = nil | ||
| local password = nil | ||
| --split by & | ||
| local parameters_array = util.split(request_body, "&") |
There was a problem hiding this comment.
Why the username, password in the request body and use & to concat.
There was a problem hiding this comment.
As url encoded parameters were coming, they were automatically appended using '&'. Having said that, your comment helped me to utilize "ngx.decode_args" which makes code much cleaner. Thanks!
Used ngx.decode_args for input arguments.
Hi, are you getting the same error when you run the docker image instance (sshniro/keycloak-apisix:latest) locally? |
|
@sshniro I have got the idea what things might cause that. Earlier I was using '&' to split the incoming parameters. but now I am using "ngx.decode_args" ( #6586 (comment) ). Because of that earlier, username (which is email) wouldn't parse properly. |
| if conf.password_grant_token_generation_incoming_uri and | ||
| ngx.var.request_uri:upper() == | ||
| conf.password_grant_token_generation_incoming_uri:upper() and | ||
| ctx.curr_req_matched["_method"]:upper() == "POST" then |
There was a problem hiding this comment.
ctx.curr_req_matched["_method"]:upper() looks strange.
I think you can use core.req.get_method instead.
| end | ||
|
|
||
| function _M.access(conf, ctx) | ||
|
|
|
|
||
| ### Password Grant Token Generation Incoming URI | ||
|
|
||
| If you want to generate a token using `password` grant, you can set value of `password_grant_token_generation_incoming_uri`. |
There was a problem hiding this comment.
| If you want to generate a token using `password` grant, you can set value of `password_grant_token_generation_incoming_uri`. | |
| If you want to generate a token using `password` grant, you can set the value of `password_grant_token_generation_incoming_uri`. |
|
|
||
| If you want to generate a token using `password` grant, you can set value of `password_grant_token_generation_incoming_uri`. | ||
|
|
||
| Incoming request URI will be matched with this value and if matched, it will generate token using `Token Endpoint`. |
There was a problem hiding this comment.
| Incoming request URI will be matched with this value and if matched, it will generate token using `Token Endpoint`. | |
| Incoming request URI will be matched with this value and if matched, it will generate a token using `Token Endpoint`. |
| If you want to generate a token using `password` grant, you can set value of `password_grant_token_generation_incoming_uri`. | ||
|
|
||
| Incoming request URI will be matched with this value and if matched, it will generate token using `Token Endpoint`. | ||
| It will also check, if REST method is `POST`. |
There was a problem hiding this comment.
| It will also check, if REST method is `POST`. | |
| It will also check if the request method is `POST`. |
|
|
||
| local params = { | ||
| method = "POST", | ||
| body = ngx.encode_args({ |
There was a problem hiding this comment.
| body = ngx.encode_args({ | |
| body = ngx.encode_args({ |
There was a problem hiding this comment.
done and also incorporated this in the same file at other places.
| if not token_endpoint then | ||
| local err = "Unable to determine token endpoint." | ||
| log.error(err) | ||
| return 500, err |
There was a problem hiding this comment.
| return 500, err | |
| return 503, err |
New feature is encouraged to avoid 500
There was a problem hiding this comment.
Valid point. I updated it. I didn't update at other places because there can be backward compatibility issues and there should be separate PR for the same.
| if conf.password_grant_token_generation_incoming_uri and | ||
| ngx.var.request_uri:upper() == | ||
| conf.password_grant_token_generation_incoming_uri:upper() and | ||
| core.request.get_method() == "POST" then |
There was a problem hiding this comment.
We should also check the "Content-Type"?
There was a problem hiding this comment.
Yes. it was missed. I introduced that now.
| function _M.access(conf, ctx) | ||
| if conf.password_grant_token_generation_incoming_uri and | ||
| ngx.var.request_uri:upper() == | ||
| conf.password_grant_token_generation_incoming_uri:upper() and |
There was a problem hiding this comment.
Is it required to compare case-insensitive?
Also, the var.request_uri will contain ?argument=part, is it desirable?
There was a problem hiding this comment.
URL should be case sensitive so removed that "upper" from code.
For the part of request_uri, I believe, as we are checking uri, method, and header, all three parts, this should be fine.
Basically for the operation of token generation, exact uri matching will be helpful.
Your thoughts?
There was a problem hiding this comment.
The request_uri will contain the query string part of the uri. For example,
With request /path?query=string
The ngx.var.request_uri will return /path?query=string, and ctx.var.uri will return /path. By looking at the doc of password_grant_token_generation_incoming_uri, I guess we can use ctx.var.uri so both /path?query=string and /path can match.
There was a problem hiding this comment.
@spacewander I understood your idea. I am curious, as to why we should treat both strings (/path?query=string or /path) the same way and proceed with token generation.
Token generation is a very specific use case, and shouldn't we say if and only if a specific URL will be submitted then we will generate token and submit result back.
if the request is made with /path?query=string, it shouldn't be assumed for token generation and it should be treated the same as any other request. (e.g. proceed to forward to upstream for further processing).
Please share your view. Accordingly, I can make changes, if needed.
| }, | ||
| "uri": "/api/token" | ||
| }]], | ||
| [[{ |
There was a problem hiding this comment.
Alright. I removed it from this new test case.
spacewander
left a comment
There was a problem hiding this comment.
Approved except #6586 (comment)
6f04d1a to
c1d1c8d
Compare
| function _M.access(conf, ctx) | ||
| local headers = core.request.headers(ctx) | ||
| local need_grant_token = conf.password_grant_token_generation_incoming_uri and | ||
| ngx.var.request_uri == conf.password_grant_token_generation_incoming_uri and |
There was a problem hiding this comment.
| ngx.var.request_uri == conf.password_grant_token_generation_incoming_uri and | |
| ctx.var.request_uri == conf.password_grant_token_generation_incoming_uri and |
would be better, which provides a cache of the var.
There was a problem hiding this comment.
Done. Made the change.
|
Hi @azilentech , thank you for your contribution! Here is the Contributor T-shirt form[1], if you're interested, kindly take a look :) |
Support of password grant type for token generation (#6574)
Committing changes after adding new feature for generating token based on
user id/passwordand also taking support of grant typepasswordfeat: #6574
Pre-submission checklist: