You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by GitBox <gi...@apache.org> on 2022/03/17 02:33:33 UTC

[GitHub] [apisix] spacewander commented on a change in pull request #6586: feat: add support for password grant in keycloak plugin

spacewander commented on a change in pull request #6586:
URL: https://github.com/apache/apisix/pull/6586#discussion_r828692698



##########
File path: apisix/plugins/authz-keycloak.lua
##########
@@ -695,8 +700,87 @@ local function fetch_jwt_token(ctx)
     return token
 end
 
+-- To get new access token by calling get token api
+local function generate_token_using_password_grant(conf,ctx)
+    log.debug("generate_token_using_password_grant Function Called")
+
+    local body, err = core.request.get_body()
+    if err or not body then
+        log.error("Failed to get request body: ", err)
+        return 503
+    end
+    local parameters = ngx.decode_args(body)
+
+    local username = parameters["username"]
+    local password = parameters["password"]
+
+    if not username then
+        local err = "username is missing."
+        log.error(err)
+        return 422, err
+    end
+    if not password then
+        local err = "password is missing."
+        log.error(err)
+        return 422, err
+    end
+
+    local client_id = authz_keycloak_get_client_id(conf)
+
+    local token_endpoint = authz_keycloak_get_token_endpoint(conf)
+
+    if not token_endpoint then
+        local err = "Unable to determine token endpoint."
+        log.error(err)
+        return 500, err
+    end
+    local httpc = authz_keycloak_get_http_client(conf)
+
+    local params = {
+        method = "POST",
+        body =  ngx.encode_args({

Review comment:
       ```suggestion
           body = ngx.encode_args({
   ```

##########
File path: apisix/plugins/authz-keycloak.lua
##########
@@ -695,8 +700,87 @@ local function fetch_jwt_token(ctx)
     return token
 end
 
+-- To get new access token by calling get token api
+local function generate_token_using_password_grant(conf,ctx)
+    log.debug("generate_token_using_password_grant Function Called")
+
+    local body, err = core.request.get_body()
+    if err or not body then
+        log.error("Failed to get request body: ", err)
+        return 503
+    end
+    local parameters = ngx.decode_args(body)
+
+    local username = parameters["username"]
+    local password = parameters["password"]
+
+    if not username then
+        local err = "username is missing."
+        log.error(err)
+        return 422, err
+    end
+    if not password then
+        local err = "password is missing."
+        log.error(err)
+        return 422, err
+    end
+
+    local client_id = authz_keycloak_get_client_id(conf)
+
+    local token_endpoint = authz_keycloak_get_token_endpoint(conf)
+
+    if not token_endpoint then
+        local err = "Unable to determine token endpoint."
+        log.error(err)
+        return 500, err

Review comment:
       ```suggestion
           return 503, err
   ```
   
   New feature is encouraged to avoid 500

##########
File path: t/plugin/authz-keycloak.t
##########
@@ -621,3 +622,104 @@ GET /t
 --- response_headers
 Location: http://127.0.0.1/test
 --- error_code: 307
+
+
+
+=== TEST 18: Add https endpoint with password_grant_token_generation_incoming_uri
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/routes/1',
+                 ngx.HTTP_PUT,
+                 [[{
+                        "plugins": {
+                            "authz-keycloak": {
+                                "token_endpoint": "https://127.0.0.1:8443/auth/realms/University/protocol/openid-connect/token",
+                                "permissions": ["course_resource#view"],
+                                "client_id": "course_management",
+                                "client_secret": "d1ec69e9-55d2-4109-a3ea-befa071579d5",
+                                "grant_type": "urn:ietf:params:oauth:grant-type:uma-ticket",
+                                "timeout": 3000,
+                                "ssl_verify": false,
+                                "password_grant_token_generation_incoming_uri": "/api/token"
+                            }
+                        },
+                        "upstream": {
+                            "nodes": {
+                                "127.0.0.1:1982": 1
+                            },
+                            "type": "roundrobin"
+                        },
+                        "uri": "/api/token"
+                }]],
+                [[{

Review comment:
       We need to remove the echo response data as https://github.com/apache/apisix/pull/6545

##########
File path: apisix/plugins/authz-keycloak.lua
##########
@@ -695,8 +700,87 @@ local function fetch_jwt_token(ctx)
     return token
 end
 
+-- To get new access token by calling get token api
+local function generate_token_using_password_grant(conf,ctx)
+    log.debug("generate_token_using_password_grant Function Called")
+
+    local body, err = core.request.get_body()
+    if err or not body then
+        log.error("Failed to get request body: ", err)
+        return 503
+    end
+    local parameters = ngx.decode_args(body)
+
+    local username = parameters["username"]
+    local password = parameters["password"]
+
+    if not username then
+        local err = "username is missing."
+        log.error(err)
+        return 422, err
+    end
+    if not password then
+        local err = "password is missing."
+        log.error(err)
+        return 422, err
+    end
+
+    local client_id = authz_keycloak_get_client_id(conf)
+
+    local token_endpoint = authz_keycloak_get_token_endpoint(conf)
+
+    if not token_endpoint then
+        local err = "Unable to determine token endpoint."
+        log.error(err)
+        return 500, err
+    end
+    local httpc = authz_keycloak_get_http_client(conf)
+
+    local params = {
+        method = "POST",
+        body =  ngx.encode_args({
+            grant_type = "password",
+            client_id = client_id,
+            client_secret = conf.client_secret,
+            username = username,
+            password = password
+        }),
+        headers = {
+            ["Content-Type"] = "application/x-www-form-urlencoded"
+        }
+    }
+
+    params = authz_keycloak_configure_params(params, conf)
+
+    local res, err = httpc:request_uri(token_endpoint, params)
+
+    if not res then
+        err = "Accessing token endpoint URL (" .. token_endpoint
+              .. ") failed: " .. err
+        log.error(err)
+        return 401, {message = err}
+    end
+
+    log.debug("Response data: " .. res.body)
+    local json, err = authz_keycloak_parse_json_response(res)
+
+    if not json then
+        err = "Could not decode JSON from response"
+              .. (err and (": " .. err) or '.')
+        log.error(err)
+        return 401, {message = err}
+    end
+
+    return res.status, res.body
+end
 
 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

Review comment:
       Is it required to compare case-insensitive?
   Also, the `var.request_uri` will contain `?argument=part`, is it desirable?

##########
File path: apisix/plugins/authz-keycloak.lua
##########
@@ -695,8 +700,87 @@ local function fetch_jwt_token(ctx)
     return token
 end
 
+-- To get new access token by calling get token api
+local function generate_token_using_password_grant(conf,ctx)
+    log.debug("generate_token_using_password_grant Function Called")
+
+    local body, err = core.request.get_body()
+    if err or not body then
+        log.error("Failed to get request body: ", err)
+        return 503
+    end
+    local parameters = ngx.decode_args(body)
+
+    local username = parameters["username"]
+    local password = parameters["password"]
+
+    if not username then
+        local err = "username is missing."
+        log.error(err)
+        return 422, err
+    end
+    if not password then
+        local err = "password is missing."
+        log.error(err)
+        return 422, err
+    end
+
+    local client_id = authz_keycloak_get_client_id(conf)
+
+    local token_endpoint = authz_keycloak_get_token_endpoint(conf)
+
+    if not token_endpoint then
+        local err = "Unable to determine token endpoint."
+        log.error(err)
+        return 500, err
+    end
+    local httpc = authz_keycloak_get_http_client(conf)
+
+    local params = {
+        method = "POST",
+        body =  ngx.encode_args({
+            grant_type = "password",
+            client_id = client_id,
+            client_secret = conf.client_secret,
+            username = username,
+            password = password
+        }),
+        headers = {
+            ["Content-Type"] = "application/x-www-form-urlencoded"
+        }
+    }
+
+    params = authz_keycloak_configure_params(params, conf)
+
+    local res, err = httpc:request_uri(token_endpoint, params)
+
+    if not res then
+        err = "Accessing token endpoint URL (" .. token_endpoint
+              .. ") failed: " .. err
+        log.error(err)
+        return 401, {message = err}
+    end
+
+    log.debug("Response data: " .. res.body)
+    local json, err = authz_keycloak_parse_json_response(res)
+
+    if not json then
+        err = "Could not decode JSON from response"
+              .. (err and (": " .. err) or '.')
+        log.error(err)
+        return 401, {message = err}
+    end
+
+    return res.status, res.body
+end
 
 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
+        core.request.get_method() == "POST" then

Review comment:
       We should also check the "Content-Type"?




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@apisix.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org