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 2020/01/30 07:29:30 UTC

[GitHub] [incubator-apisix] iGeeky opened a new pull request #1095: feature: Add wolf rbac plugin

iGeeky opened a new pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095
 
 
   
   ### Summary
   
   `wolf-rbac` is an authentication and authorization (rbac) plugin. 
   The rbac feature is provided by [wolf](https://github.com/iGeeky/wolf). For more information about wolf, please refer to [wolf documentation](https://github.com/iGeeky/wolf).
   

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] iGeeky commented on issue #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
iGeeky commented on issue #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#issuecomment-584121609
 
 
   @moonming @membphis thx. 
   I created a new pr to add it.

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373752905
 
 

 ##########
 File path: doc/plugins/wolf-rbac-cn.md
 ##########
 @@ -0,0 +1,207 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+-->
+
+[English](wolf-rbac.md)
+
+# 目录
+
+- [**名字**](#名字)
+- [**属性**](#属性)
+- [**依赖项**](#依赖项)
+- [**如何启用**](#如何启用)
+- [**测试插件**](#测试插件)
+- [**禁用插件**](#禁用插件)
+
+## 名字
+
+`wolf-rbac`是一个认证及授权(rbac)插件,它需要与 `consumer` 一起配合才能工作。同时需要添加 `wolf-rbac` 到一个 `service` 或 `route`中。
+rbac功能由[wolf](https://github.com/iGeeky/wolf)提供, 有关wolf的更多信息, 请参考[wolf文档](https://github.com/iGeeky/wolf)。
 
 Review comment:
   Add a space between Chinese and English.
   
   Please also fix other similar points.

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on issue #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on issue #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#issuecomment-582818578
 
 
   @iGeeky many thx

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373753693
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,380 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local cjson = require("cjson")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local ngx_time = ngx.time
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {type = "string"},
+        server = { type = 'string'},
+    }
+}
+
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token) 
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err=err}
+    end
+
+    if res[1] ~= token_version then
+        return { err='invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body=body, ssl_verify=false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode({method=method, uri=uri, body=body, headers=myheaders}), " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    if not conf.appid then
+        conf.appid = 'unset'
+    end
+    if not conf.server then
+        conf.server = 'http://127.0.0.1:10080'
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token()
+    local args = ngx.req.get_uri_args()
 
 Review comment:
   we can use `ctx.var` to fetch it. eg: `ctx.var.arg_ rbac_token`, `ctx.var.http_ Authorization`, ``ctx.var.cookie_x-rbac-token`

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373753324
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,380 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local cjson = require("cjson")
 
 Review comment:
   Maybe `core.json` is enough?

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373754018
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,380 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local cjson = require("cjson")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local ngx_time = ngx.time
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {type = "string"},
+        server = { type = 'string'},
+    }
+}
+
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token) 
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err=err}
+    end
+
+    if res[1] ~= token_version then
+        return { err='invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body=body, ssl_verify=false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode({method=method, uri=uri, body=body, headers=myheaders}), " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    if not conf.appid then
+        conf.appid = 'unset'
+    end
+    if not conf.server then
+        conf.server = 'http://127.0.0.1:10080'
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token()
+    local args = ngx.req.get_uri_args()
+    if args and args.rbac_token then
+        return args.rbac_token
+    end
+
+    local headers = ngx.req.get_headers()
+    if headers.Authorization then
+        return headers.Authorization
+    end
+    if headers['x-rbac-token'] then
+        return headers['x-rbac-token']
+    end
+    local cookie, err = ck:new()
+    if not cookie then
+        return nil, err
+    end
+    local val, err = cookie:get("x-rbac-token")
+    return val, err
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return cjson.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil;
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP=clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(100)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status=500, err="request to wolf-server failed, err:" .. tostring(err)}
+    elseif res.status == 200 or res.status == 401 then
+        local body, err = loadjson(res.body)
+	    if err then
+            errmsg = 'check permission failed! parse response json failed!'
+            core.log.error( "loadjson(", res.body, ") failed! err:", err)
+            return {status=res.status, err=errmsg}
+        else
+            if body.data then
+                userInfo = body.data.userInfo
+            end
+            errmsg = body.reason
+            return {status=res.status, err=errmsg, userInfo=userInfo}
+        end
+    else
+        return {status=500, err='request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action=action, url = url, clientIP = clientIP}
 
 Review comment:
   `action=action,` to `action = action,`

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373754088
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,380 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local cjson = require("cjson")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local ngx_time = ngx.time
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {type = "string"},
+        server = { type = 'string'},
+    }
+}
+
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token) 
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err=err}
+    end
+
+    if res[1] ~= token_version then
+        return { err='invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body=body, ssl_verify=false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode({method=method, uri=uri, body=body, headers=myheaders}), " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    if not conf.appid then
+        conf.appid = 'unset'
+    end
+    if not conf.server then
+        conf.server = 'http://127.0.0.1:10080'
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token()
+    local args = ngx.req.get_uri_args()
+    if args and args.rbac_token then
+        return args.rbac_token
+    end
+
+    local headers = ngx.req.get_headers()
+    if headers.Authorization then
+        return headers.Authorization
+    end
+    if headers['x-rbac-token'] then
+        return headers['x-rbac-token']
+    end
+    local cookie, err = ck:new()
+    if not cookie then
+        return nil, err
+    end
+    local val, err = cookie:get("x-rbac-token")
+    return val, err
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return cjson.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil;
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP=clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(100)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status=500, err="request to wolf-server failed, err:" .. tostring(err)}
+    elseif res.status == 200 or res.status == 401 then
+        local body, err = loadjson(res.body)
+	    if err then
+            errmsg = 'check permission failed! parse response json failed!'
+            core.log.error( "loadjson(", res.body, ") failed! err:", err)
+            return {status=res.status, err=errmsg}
+        else
+            if body.data then
+                userInfo = body.data.userInfo
+            end
+            errmsg = body.reason
+            return {status=res.status, err=errmsg, userInfo=userInfo}
+        end
+    else
+        return {status=500, err='request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action=action, url = url, clientIP = clientIP}
+
+	local rbac_token, err = fetch_rbac_token()
+	if rbac_token == nil then
+		core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo =parse_rbac_token(rbac_token)
 
 Review comment:
   please add a space before `parse_rbac_token`

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373777024
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,376 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {
+            type = "string",
+            default = "unset"
+        },
+        server = {
+            type = "string",
+            default = "http://127.0.0.1:10080"
+        },
+    }
+}
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token)
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err = err}
+    end
+
+    if #res ~= 3 or res[1] ~= token_version then
+        return { err = 'invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body = body, ssl_verify = false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode(
+            {method = method, uri = uri, body = body, headers = myheaders}),
+            " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token(ctx)
+    if ctx.var.arg_rbac_token then
+        return ngx.unescape_uri(ctx.var.arg_rbac_token)
+    end
+
+    if ctx.var.http_authorization then
+        return ctx.var.http_authorization
+    end
+
+    if ctx.var.http_x_rbac_token then
+        return ctx.var.http_x_rbac_token
+    end
+
+    return ctx.var['cookie_x-rbac-token']
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return json.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP = clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(0.1)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status = 500, err = "request to wolf-server failed, err:" .. tostring(err)}
+    end
+
+    if res.status ~= 200 and res.status ~= 401 then
+        return {status = 500, err = 'request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+
+    local body, err = loadjson(res.body)
+    if err then
+        errmsg = 'check permission failed! parse response json failed!'
+        core.log.error( "loadjson(", res.body, ") failed! err:", err)
+        return {status = res.status, err = errmsg}
+    else
+        if body.data then
+            userInfo = body.data.userInfo
+        end
+        errmsg = body.reason
+        return {status = res.status, err = errmsg, userInfo = userInfo}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action = action, url = url, clientIP = clientIP}
+
+    local rbac_token = fetch_rbac_token(ctx)
+    if rbac_token == nil then
+        core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo = parse_rbac_token(rbac_token)
+    core.log.info("token info: ", core.json.delay_encode(tokenInfo))
+    if tokenInfo.err then
+        return 401, {message = 'invalid rbac token: parse failed'}
+    end
+
+
+    local appid = tokenInfo.appid
+    local wolf_token = tokenInfo.wolf_token
+    permItem.appid = appid
+    permItem.wolf_token = wolf_token
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return 401, {message = "Missing related consumer"}
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.error("consumer [", appid, "] not found")
+        return 401, {message = "Invalid appid in rbac token"}
+    end
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+    local server = consumer.auth_conf.server
+
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {appid = appid, action = action, url = url, clientIP = clientIP, wolf_token = wolf_token}
+
+    local res = check_url_permission(server, appid, action, url, clientIP, wolf_token)
+    core.log.info(" check_url_permission(", core.json.delay_encode(permItem), ") res: ",core.json.delay_encode(res))
+
+    local username = nil
+    local nickname = nil
+    if type(res.userInfo) == 'table' then
+        local userInfo = res.userInfo
+        core.response.set_header("X-UserId", userInfo.id)
+        core.response.set_header("X-Username", userInfo.username)
+        core.response.set_header("X-Nickname", ngx.escape_uri(userInfo.nickname) or userInfo.username)
+        ctx.userInfo = userInfo
+        username = userInfo.username
+        nickname = userInfo.nickname
+    end
+
+    if res.status == 200 then
+        ---
+    else
+        -- no permission.
+        core.log.error(" check_url_permission(", core.json.delay_encode(permItem), ") failed, res: ",core.json.delay_encode(res))
+        return 401, {message = res.err, username = username, nickname = nickname}
+    end
+    core.log.info("hit wolf-rbac rewrite")
+end
+
+local function get_args()
+    local args, err
+    ngx.req.read_body()
+    if string.find(ngx.req.get_headers()["Content-Type"] or "","application/json", 0) then
+        args, err = json.decode(ngx.req.get_body_data())
+        if err then
+            core.log.error("json.decode(", ngx.req.get_body_data(), ") failed! ", err)
+        end
+    else
+        args = ngx.req.get_post_args()
+    end
+    return args
+end
+
+local function login()
+    local args = get_args()
+    if not args then
+        return core.response.exit(400, {message = "invalid request"})
+    end
+    if not args.appid then
+        return core.response.exit(400, {message = "appid is missing"})
+    end
+
+    local appid = args.appid
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return core.response.exit(500)
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.info("request appid [", appid, "] not found")
+        return core.response.exit(400, {message = "appid [" .. tostring(appid) .. "] not found"})
+    end
+
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+
+    local uri = consumer.auth_conf.server .. '/wolf/rbac/login.rest'
+    local headers = new_headers()
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local timeout = 1000 * 5
+    local request_debug = core.json.delay_encode(
+        {method = 'POST', uri = uri, body = args, headers = headers,timeout = timeout})
+    core.log.info("login request [", request_debug, "] ....")
+    local res, err = http_post(uri, core.json.encode(args), headers, timeout)
+    if err or not res then
+        core.log.error("login request [", request_debug, "] failed! err: ", err)
+        return core.response.exit(500, {message = "request to wolf-server failed! " .. tostring(err)})
+    end
+    core.log.info("login request [", request_debug, "] status: ", res.status, ", body: ", res.body)
+
+    if res.status ~= 200 then
+        core.log.error("login request [", request_debug, "] failed! status: ", res.status)
+        return core.response.exit(500, {message = "request to wolf-server failed! status:" .. tostring(res.status) })
+    end
+    local body = json.decode(res.body)
 
 Review comment:
   `local body, err = ...`

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373816708
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,376 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {
+            type = "string",
+            default = "unset"
+        },
+        server = {
+            type = "string",
+            default = "http://127.0.0.1:10080"
+        },
+    }
+}
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token)
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err = err}
+    end
+
+    if #res ~= 3 or res[1] ~= token_version then
+        return { err = 'invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body = body, ssl_verify = false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode(
+            {method = method, uri = uri, body = body, headers = myheaders}),
+            " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token(ctx)
+    if ctx.var.arg_rbac_token then
+        return ngx.unescape_uri(ctx.var.arg_rbac_token)
+    end
+
+    if ctx.var.http_authorization then
+        return ctx.var.http_authorization
+    end
+
+    if ctx.var.http_x_rbac_token then
+        return ctx.var.http_x_rbac_token
+    end
+
+    return ctx.var['cookie_x-rbac-token']
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return json.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP = clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(0.1)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status = 500, err = "request to wolf-server failed, err:" .. tostring(err)}
+    end
+
+    if res.status ~= 200 and res.status ~= 401 then
+        return {status = 500, err = 'request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+
+    local body, err = loadjson(res.body)
+    if err then
+        errmsg = 'check permission failed! parse response json failed!'
+        core.log.error( "loadjson(", res.body, ") failed! err:", err)
+        return {status = res.status, err = errmsg}
+    else
+        if body.data then
+            userInfo = body.data.userInfo
+        end
+        errmsg = body.reason
+        return {status = res.status, err = errmsg, userInfo = userInfo}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action = action, url = url, clientIP = clientIP}
+
+    local rbac_token = fetch_rbac_token(ctx)
+    if rbac_token == nil then
+        core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo = parse_rbac_token(rbac_token)
+    core.log.info("token info: ", core.json.delay_encode(tokenInfo))
+    if tokenInfo.err then
+        return 401, {message = 'invalid rbac token: parse failed'}
+    end
+
+
+    local appid = tokenInfo.appid
+    local wolf_token = tokenInfo.wolf_token
+    permItem.appid = appid
+    permItem.wolf_token = wolf_token
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return 401, {message = "Missing related consumer"}
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.error("consumer [", appid, "] not found")
+        return 401, {message = "Invalid appid in rbac token"}
+    end
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+    local server = consumer.auth_conf.server
+
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {appid = appid, action = action, url = url, clientIP = clientIP, wolf_token = wolf_token}
+
+    local res = check_url_permission(server, appid, action, url, clientIP, wolf_token)
+    core.log.info(" check_url_permission(", core.json.delay_encode(permItem), ") res: ",core.json.delay_encode(res))
+
+    local username = nil
+    local nickname = nil
+    if type(res.userInfo) == 'table' then
+        local userInfo = res.userInfo
+        core.response.set_header("X-UserId", userInfo.id)
+        core.response.set_header("X-Username", userInfo.username)
+        core.response.set_header("X-Nickname", ngx.escape_uri(userInfo.nickname) or userInfo.username)
+        ctx.userInfo = userInfo
+        username = userInfo.username
+        nickname = userInfo.nickname
+    end
+
+    if res.status == 200 then
+        ---
+    else
+        -- no permission.
+        core.log.error(" check_url_permission(", core.json.delay_encode(permItem), ") failed, res: ",core.json.delay_encode(res))
 
 Review comment:
   Done

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373753432
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,380 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local cjson = require("cjson")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local ngx_time = ngx.time
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {type = "string"},
+        server = { type = 'string'},
+    }
+}
+
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token) 
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err=err}
+    end
+
+    if res[1] ~= token_version then
+        return { err='invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body=body, ssl_verify=false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode({method=method, uri=uri, body=body, headers=myheaders}), " ] failed! res is nil, err:", err)
 
 Review comment:
   this line is too long.

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373753713
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,380 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local cjson = require("cjson")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local ngx_time = ngx.time
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {type = "string"},
+        server = { type = 'string'},
+    }
+}
+
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token) 
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err=err}
+    end
+
+    if res[1] ~= token_version then
+        return { err='invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body=body, ssl_verify=false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode({method=method, uri=uri, body=body, headers=myheaders}), " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    if not conf.appid then
+        conf.appid = 'unset'
+    end
+    if not conf.server then
+        conf.server = 'http://127.0.0.1:10080'
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token()
+    local args = ngx.req.get_uri_args()
+    if args and args.rbac_token then
+        return args.rbac_token
+    end
+
+    local headers = ngx.req.get_headers()
+    if headers.Authorization then
+        return headers.Authorization
+    end
+    if headers['x-rbac-token'] then
+        return headers['x-rbac-token']
+    end
+    local cookie, err = ck:new()
 
 Review comment:
   please add a blank line

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373766772
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,380 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local cjson = require("cjson")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local ngx_time = ngx.time
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {type = "string"},
+        server = { type = 'string'},
+    }
+}
+
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token) 
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err=err}
+    end
+
+    if res[1] ~= token_version then
+        return { err='invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body=body, ssl_verify=false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode({method=method, uri=uri, body=body, headers=myheaders}), " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    if not conf.appid then
+        conf.appid = 'unset'
+    end
+    if not conf.server then
+        conf.server = 'http://127.0.0.1:10080'
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token()
+    local args = ngx.req.get_uri_args()
+    if args and args.rbac_token then
+        return args.rbac_token
+    end
+
+    local headers = ngx.req.get_headers()
+    if headers.Authorization then
+        return headers.Authorization
+    end
+    if headers['x-rbac-token'] then
+        return headers['x-rbac-token']
+    end
+    local cookie, err = ck:new()
+    if not cookie then
+        return nil, err
+    end
+    local val, err = cookie:get("x-rbac-token")
+    return val, err
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return cjson.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil;
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP=clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(100)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status=500, err="request to wolf-server failed, err:" .. tostring(err)}
+    elseif res.status == 200 or res.status == 401 then
+        local body, err = loadjson(res.body)
+	    if err then
+            errmsg = 'check permission failed! parse response json failed!'
+            core.log.error( "loadjson(", res.body, ") failed! err:", err)
+            return {status=res.status, err=errmsg}
+        else
+            if body.data then
+                userInfo = body.data.userInfo
+            end
+            errmsg = body.reason
+            return {status=res.status, err=errmsg, userInfo=userInfo}
+        end
+    else
+        return {status=500, err='request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action=action, url = url, clientIP = clientIP}
+
+	local rbac_token, err = fetch_rbac_token()
+	if rbac_token == nil then
+		core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo =parse_rbac_token(rbac_token)
+    core.log.info("token info: ", core.json.delay_encode(tokenInfo))
+    if tokenInfo.err then
+        return 401, {message = 'invalid rbac token: parse failed'}
+    end
+
+
+    local appid = tokenInfo.appid
+    local wolf_token = tokenInfo.wolf_token
+    permItem.appid = appid
+    permItem.wolf_token = wolf_token
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return 401, {message = "Missing related consumer"}
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.error("consumer [", appid, "] not found")
+        return 401, {message = "Invalid appid in rbac token"}
+    end
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+    local server = consumer.auth_conf.server
+
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {appid=appid, action=action, url = url, clientIP = clientIP, wolf_token=wolf_token}
+
+    local res = check_url_permission(server, appid, action, url, clientIP, wolf_token)
+	core.log.info(" check_url_permission(", core.json.delay_encode(permItem), ") res: ",core.json.delay_encode(res))
+
+	local username = nil
+    local nickname = nil
+    if type(res.userInfo) == 'table' then
+        local userInfo = res.userInfo
+        core.response.set_header("X-UserId", userInfo.id)
+        core.response.set_header("X-Username", userInfo.username)
+        core.response.set_header("X-Nickname", ngx.escape_uri(userInfo.nickname) or userInfo.username)
+        ctx.userInfo = userInfo
+		username = userInfo.username
+        nickname = userInfo.nickname
+	end
+
+	if res.status == 200 then
 
 Review comment:
   Done

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373898439
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,386 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+local core     = require("apisix.core")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local tostring = tostring
+local rawget   = rawget
+local rawset   = rawset
+local setmetatable = setmetatable
+local type     = type
+local string   = string
+
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {
+            type = "string",
+            default = "unset"
+        },
+        server = {
+            type = "string",
+            default = "http://127.0.0.1:10080"
+        },
+    }
+}
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token)
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err = err}
+    end
+
+    if #res ~= 3 or res[1] ~= token_version then
+        return { err = 'invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body = body, ssl_verify = false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode(
+            {method = method, uri = uri, body = body, headers = myheaders}),
+            " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token(ctx)
+    if ctx.var.arg_rbac_token then
+        return ngx.unescape_uri(ctx.var.arg_rbac_token)
+    end
+
+    if ctx.var.http_authorization then
+        return ctx.var.http_authorization
+    end
+
+    if ctx.var.http_x_rbac_token then
+        return ctx.var.http_x_rbac_token
+    end
+
+    return ctx.var['cookie_x-rbac-token']
+end
+
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg
+    local userInfo
+    local res
+    local err
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP = clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status,
+                            ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(0.1)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status = 500, err = "request to wolf-server failed, err:" .. tostring(err)}
+    end
+
+    if res.status ~= 200 and res.status ~= 401 then
+        return {status = 500, err = 'request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+
+    local body, err = json.decode(res.body)
+    if err then
+        errmsg = 'check permission failed! parse response json failed!'
+        core.log.error( "json.decode(", res.body, ") failed! err:", err)
+        return {status = res.status, err = errmsg}
+    else
+        if body.data then
+            userInfo = body.data.userInfo
+        end
+        errmsg = body.reason
+        return {status = res.status, err = errmsg, userInfo = userInfo}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action = action, url = url, clientIP = clientIP}
+    core.log.info("hit wolf-rbac rewrite")
+
+    local rbac_token = fetch_rbac_token(ctx)
+    if rbac_token == nil then
+        core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo = parse_rbac_token(rbac_token)
+    core.log.info("token info: ", core.json.delay_encode(tokenInfo))
+    if tokenInfo.err then
+        return 401, {message = 'invalid rbac token: parse failed'}
 
 Review comment:
   `{message = 'invalid rbac token: parse failed, ' .. err}`
   
   Should we return the error message?

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373767106
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,380 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local cjson = require("cjson")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local ngx_time = ngx.time
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {type = "string"},
+        server = { type = 'string'},
+    }
+}
+
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token) 
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err=err}
+    end
+
+    if res[1] ~= token_version then
+        return { err='invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body=body, ssl_verify=false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode({method=method, uri=uri, body=body, headers=myheaders}), " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    if not conf.appid then
 
 Review comment:
   Done

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373753796
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,380 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local cjson = require("cjson")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local ngx_time = ngx.time
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {type = "string"},
+        server = { type = 'string'},
+    }
+}
+
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token) 
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err=err}
+    end
+
+    if res[1] ~= token_version then
+        return { err='invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body=body, ssl_verify=false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode({method=method, uri=uri, body=body, headers=myheaders}), " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    if not conf.appid then
+        conf.appid = 'unset'
+    end
+    if not conf.server then
+        conf.server = 'http://127.0.0.1:10080'
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token()
+    local args = ngx.req.get_uri_args()
+    if args and args.rbac_token then
+        return args.rbac_token
+    end
+
+    local headers = ngx.req.get_headers()
+    if headers.Authorization then
+        return headers.Authorization
+    end
+    if headers['x-rbac-token'] then
+        return headers['x-rbac-token']
+    end
+    local cookie, err = ck:new()
+    if not cookie then
+        return nil, err
+    end
+    local val, err = cookie:get("x-rbac-token")
+    return val, err
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return cjson.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil;
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP=clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(100)
 
 Review comment:
   `100` sec to too long, need a shorter time

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373816704
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,376 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {
+            type = "string",
+            default = "unset"
+        },
+        server = {
+            type = "string",
+            default = "http://127.0.0.1:10080"
+        },
+    }
+}
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token)
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err = err}
+    end
+
+    if #res ~= 3 or res[1] ~= token_version then
+        return { err = 'invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body = body, ssl_verify = false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode(
+            {method = method, uri = uri, body = body, headers = myheaders}),
+            " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token(ctx)
+    if ctx.var.arg_rbac_token then
+        return ngx.unescape_uri(ctx.var.arg_rbac_token)
+    end
+
+    if ctx.var.http_authorization then
+        return ctx.var.http_authorization
+    end
+
+    if ctx.var.http_x_rbac_token then
+        return ctx.var.http_x_rbac_token
+    end
+
+    return ctx.var['cookie_x-rbac-token']
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return json.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP = clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(0.1)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status = 500, err = "request to wolf-server failed, err:" .. tostring(err)}
+    end
+
+    if res.status ~= 200 and res.status ~= 401 then
+        return {status = 500, err = 'request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+
+    local body, err = loadjson(res.body)
+    if err then
+        errmsg = 'check permission failed! parse response json failed!'
+        core.log.error( "loadjson(", res.body, ") failed! err:", err)
+        return {status = res.status, err = errmsg}
+    else
+        if body.data then
+            userInfo = body.data.userInfo
+        end
+        errmsg = body.reason
+        return {status = res.status, err = errmsg, userInfo = userInfo}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action = action, url = url, clientIP = clientIP}
+
+    local rbac_token = fetch_rbac_token(ctx)
+    if rbac_token == nil then
+        core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo = parse_rbac_token(rbac_token)
+    core.log.info("token info: ", core.json.delay_encode(tokenInfo))
+    if tokenInfo.err then
+        return 401, {message = 'invalid rbac token: parse failed'}
+    end
+
+
+    local appid = tokenInfo.appid
+    local wolf_token = tokenInfo.wolf_token
+    permItem.appid = appid
+    permItem.wolf_token = wolf_token
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return 401, {message = "Missing related consumer"}
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.error("consumer [", appid, "] not found")
+        return 401, {message = "Invalid appid in rbac token"}
+    end
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+    local server = consumer.auth_conf.server
+
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {appid = appid, action = action, url = url, clientIP = clientIP, wolf_token = wolf_token}
+
+    local res = check_url_permission(server, appid, action, url, clientIP, wolf_token)
+    core.log.info(" check_url_permission(", core.json.delay_encode(permItem), ") res: ",core.json.delay_encode(res))
+
+    local username = nil
+    local nickname = nil
+    if type(res.userInfo) == 'table' then
+        local userInfo = res.userInfo
+        core.response.set_header("X-UserId", userInfo.id)
+        core.response.set_header("X-Username", userInfo.username)
+        core.response.set_header("X-Nickname", ngx.escape_uri(userInfo.nickname) or userInfo.username)
+        ctx.userInfo = userInfo
+        username = userInfo.username
+        nickname = userInfo.nickname
+    end
+
+    if res.status == 200 then
+        ---
+    else
+        -- no permission.
+        core.log.error(" check_url_permission(", core.json.delay_encode(permItem), ") failed, res: ",core.json.delay_encode(res))
+        return 401, {message = res.err, username = username, nickname = nickname}
+    end
+    core.log.info("hit wolf-rbac rewrite")
 
 Review comment:
   Done

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373776930
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,376 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {
+            type = "string",
+            default = "unset"
+        },
+        server = {
+            type = "string",
+            default = "http://127.0.0.1:10080"
+        },
+    }
+}
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token)
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err = err}
+    end
+
+    if #res ~= 3 or res[1] ~= token_version then
+        return { err = 'invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body = body, ssl_verify = false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode(
+            {method = method, uri = uri, body = body, headers = myheaders}),
+            " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token(ctx)
+    if ctx.var.arg_rbac_token then
+        return ngx.unescape_uri(ctx.var.arg_rbac_token)
+    end
+
+    if ctx.var.http_authorization then
+        return ctx.var.http_authorization
+    end
+
+    if ctx.var.http_x_rbac_token then
+        return ctx.var.http_x_rbac_token
+    end
+
+    return ctx.var['cookie_x-rbac-token']
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return json.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP = clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(0.1)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status = 500, err = "request to wolf-server failed, err:" .. tostring(err)}
+    end
+
+    if res.status ~= 200 and res.status ~= 401 then
+        return {status = 500, err = 'request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+
+    local body, err = loadjson(res.body)
+    if err then
+        errmsg = 'check permission failed! parse response json failed!'
+        core.log.error( "loadjson(", res.body, ") failed! err:", err)
+        return {status = res.status, err = errmsg}
+    else
+        if body.data then
+            userInfo = body.data.userInfo
+        end
+        errmsg = body.reason
+        return {status = res.status, err = errmsg, userInfo = userInfo}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action = action, url = url, clientIP = clientIP}
+
+    local rbac_token = fetch_rbac_token(ctx)
+    if rbac_token == nil then
+        core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo = parse_rbac_token(rbac_token)
+    core.log.info("token info: ", core.json.delay_encode(tokenInfo))
+    if tokenInfo.err then
+        return 401, {message = 'invalid rbac token: parse failed'}
+    end
+
+
+    local appid = tokenInfo.appid
+    local wolf_token = tokenInfo.wolf_token
+    permItem.appid = appid
+    permItem.wolf_token = wolf_token
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return 401, {message = "Missing related consumer"}
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.error("consumer [", appid, "] not found")
+        return 401, {message = "Invalid appid in rbac token"}
+    end
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+    local server = consumer.auth_conf.server
+
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {appid = appid, action = action, url = url, clientIP = clientIP, wolf_token = wolf_token}
+
+    local res = check_url_permission(server, appid, action, url, clientIP, wolf_token)
+    core.log.info(" check_url_permission(", core.json.delay_encode(permItem), ") res: ",core.json.delay_encode(res))
+
+    local username = nil
+    local nickname = nil
+    if type(res.userInfo) == 'table' then
+        local userInfo = res.userInfo
+        core.response.set_header("X-UserId", userInfo.id)
+        core.response.set_header("X-Username", userInfo.username)
+        core.response.set_header("X-Nickname", ngx.escape_uri(userInfo.nickname) or userInfo.username)
+        ctx.userInfo = userInfo
+        username = userInfo.username
+        nickname = userInfo.nickname
+    end
+
+    if res.status == 200 then
+        ---
+    else
+        -- no permission.
+        core.log.error(" check_url_permission(", core.json.delay_encode(permItem), ") failed, res: ",core.json.delay_encode(res))
+        return 401, {message = res.err, username = username, nickname = nickname}
+    end
+    core.log.info("hit wolf-rbac rewrite")
+end
+
+local function get_args()
+    local args, err
+    ngx.req.read_body()
+    if string.find(ngx.req.get_headers()["Content-Type"] or "","application/json", 0) then
 
 Review comment:
   `ctx.var.http_content_type` you can make a try in this way which is faster.

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373898779
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,386 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+local core     = require("apisix.core")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local tostring = tostring
+local rawget   = rawget
+local rawset   = rawset
+local setmetatable = setmetatable
+local type     = type
+local string   = string
+
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {
+            type = "string",
+            default = "unset"
+        },
+        server = {
+            type = "string",
+            default = "http://127.0.0.1:10080"
+        },
+    }
+}
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token)
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err = err}
+    end
+
+    if #res ~= 3 or res[1] ~= token_version then
+        return { err = 'invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body = body, ssl_verify = false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode(
+            {method = method, uri = uri, body = body, headers = myheaders}),
+            " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token(ctx)
+    if ctx.var.arg_rbac_token then
+        return ngx.unescape_uri(ctx.var.arg_rbac_token)
+    end
+
+    if ctx.var.http_authorization then
+        return ctx.var.http_authorization
+    end
+
+    if ctx.var.http_x_rbac_token then
+        return ctx.var.http_x_rbac_token
+    end
+
+    return ctx.var['cookie_x-rbac-token']
+end
+
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg
+    local userInfo
+    local res
+    local err
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP = clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status,
+                            ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(0.1)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status = 500, err = "request to wolf-server failed, err:" .. tostring(err)}
+    end
+
+    if res.status ~= 200 and res.status ~= 401 then
+        return {status = 500, err = 'request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+
+    local body, err = json.decode(res.body)
+    if err then
+        errmsg = 'check permission failed! parse response json failed!'
+        core.log.error( "json.decode(", res.body, ") failed! err:", err)
+        return {status = res.status, err = errmsg}
+    else
+        if body.data then
+            userInfo = body.data.userInfo
+        end
+        errmsg = body.reason
+        return {status = res.status, err = errmsg, userInfo = userInfo}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action = action, url = url, clientIP = clientIP}
+    core.log.info("hit wolf-rbac rewrite")
+
+    local rbac_token = fetch_rbac_token(ctx)
+    if rbac_token == nil then
+        core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo = parse_rbac_token(rbac_token)
+    core.log.info("token info: ", core.json.delay_encode(tokenInfo))
+    if tokenInfo.err then
+        return 401, {message = 'invalid rbac token: parse failed'}
+    end
+
+    local appid = tokenInfo.appid
+    local wolf_token = tokenInfo.wolf_token
+    permItem.appid = appid
+    permItem.wolf_token = wolf_token
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return 401, {message = "Missing related consumer"}
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.error("consumer [", appid, "] not found")
+        return 401, {message = "Invalid appid in rbac token"}
+    end
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+    local server = consumer.auth_conf.server
+
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {appid = appid, action = action, url = url, clientIP = clientIP, wolf_token = wolf_token}
+
+    local res = check_url_permission(server, appid, action, url, clientIP, wolf_token)
+    core.log.info(" check_url_permission(", core.json.delay_encode(permItem), ") res: ",core.json.delay_encode(res))
+
+    local username = nil
+    local nickname = nil
+    if type(res.userInfo) == 'table' then
+        local userInfo = res.userInfo
+        core.response.set_header("X-UserId", userInfo.id)
+        core.response.set_header("X-Username", userInfo.username)
+        core.response.set_header("X-Nickname", ngx.escape_uri(userInfo.nickname) or userInfo.username)
+        ctx.userInfo = userInfo
+        username = userInfo.username
+        nickname = userInfo.nickname
+    end
+
+    if res.status ~= 200 then
+        -- no permission.
+        core.log.error(" check_url_permission(", core.json.delay_encode(permItem),
+            ") failed, res: ",core.json.delay_encode(res))
+        return 401, {message = res.err, username = username, nickname = nickname}
+    end
+    core.log.info("wolf-rbac check permission passed")
+end
+
+local function get_args()
+    local ctx = ngx.ctx.api_ctx
+    local args, err
+    ngx.req.read_body()
+    if string.find(ctx.var.http_content_type or "","application/json", 1, true) then
+        args, err = json.decode(ngx.req.get_body_data())
+        if err then
+            core.log.error("json.decode(", ngx.req.get_body_data(), ") failed! ", err)
+        end
+    else
+        args = ngx.req.get_post_args()
+    end
+    return args
+end
+
+local function login()
+    local args = get_args()
+    if not args then
+        return core.response.exit(400, {message = "invalid request"})
+    end
+    if not args.appid then
+        return core.response.exit(400, {message = "appid is missing"})
+    end
+
+    local appid = args.appid
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return core.response.exit(500)
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.info("request appid [", appid, "] not found")
+        return core.response.exit(400, {message = "appid [" .. tostring(appid) .. "] not found"})
+    end
+
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+
+    local uri = consumer.auth_conf.server .. '/wolf/rbac/login.rest'
+    local headers = new_headers()
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local timeout = 1000 * 5
+    local request_debug = core.json.delay_encode(
 
 Review comment:
   ```lua
   local request_debug = core.json.delay_encode(
           {method = 'POST', uri = uri, body = args, headers = headers,timeout = timeout}
   )
   ```
   
   this style is clearer

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373816599
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,376 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {
+            type = "string",
+            default = "unset"
+        },
+        server = {
+            type = "string",
+            default = "http://127.0.0.1:10080"
+        },
+    }
+}
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token)
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err = err}
+    end
+
+    if #res ~= 3 or res[1] ~= token_version then
+        return { err = 'invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body = body, ssl_verify = false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode(
+            {method = method, uri = uri, body = body, headers = myheaders}),
+            " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token(ctx)
+    if ctx.var.arg_rbac_token then
+        return ngx.unescape_uri(ctx.var.arg_rbac_token)
+    end
+
+    if ctx.var.http_authorization then
+        return ctx.var.http_authorization
+    end
+
+    if ctx.var.http_x_rbac_token then
+        return ctx.var.http_x_rbac_token
+    end
+
+    return ctx.var['cookie_x-rbac-token']
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return json.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP = clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(0.1)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status = 500, err = "request to wolf-server failed, err:" .. tostring(err)}
+    end
+
+    if res.status ~= 200 and res.status ~= 401 then
+        return {status = 500, err = 'request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+
+    local body, err = loadjson(res.body)
+    if err then
+        errmsg = 'check permission failed! parse response json failed!'
+        core.log.error( "loadjson(", res.body, ") failed! err:", err)
+        return {status = res.status, err = errmsg}
+    else
+        if body.data then
+            userInfo = body.data.userInfo
+        end
+        errmsg = body.reason
+        return {status = res.status, err = errmsg, userInfo = userInfo}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action = action, url = url, clientIP = clientIP}
+
+    local rbac_token = fetch_rbac_token(ctx)
+    if rbac_token == nil then
+        core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo = parse_rbac_token(rbac_token)
+    core.log.info("token info: ", core.json.delay_encode(tokenInfo))
+    if tokenInfo.err then
+        return 401, {message = 'invalid rbac token: parse failed'}
+    end
+
+
+    local appid = tokenInfo.appid
+    local wolf_token = tokenInfo.wolf_token
+    permItem.appid = appid
+    permItem.wolf_token = wolf_token
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return 401, {message = "Missing related consumer"}
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.error("consumer [", appid, "] not found")
+        return 401, {message = "Invalid appid in rbac token"}
+    end
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+    local server = consumer.auth_conf.server
+
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {appid = appid, action = action, url = url, clientIP = clientIP, wolf_token = wolf_token}
+
+    local res = check_url_permission(server, appid, action, url, clientIP, wolf_token)
+    core.log.info(" check_url_permission(", core.json.delay_encode(permItem), ") res: ",core.json.delay_encode(res))
+
+    local username = nil
+    local nickname = nil
+    if type(res.userInfo) == 'table' then
+        local userInfo = res.userInfo
+        core.response.set_header("X-UserId", userInfo.id)
+        core.response.set_header("X-Username", userInfo.username)
+        core.response.set_header("X-Nickname", ngx.escape_uri(userInfo.nickname) or userInfo.username)
+        ctx.userInfo = userInfo
+        username = userInfo.username
+        nickname = userInfo.nickname
+    end
+
+    if res.status == 200 then
+        ---
+    else
+        -- no permission.
+        core.log.error(" check_url_permission(", core.json.delay_encode(permItem), ") failed, res: ",core.json.delay_encode(res))
+        return 401, {message = res.err, username = username, nickname = nickname}
+    end
+    core.log.info("hit wolf-rbac rewrite")
+end
+
+local function get_args()
+    local args, err
+    ngx.req.read_body()
+    if string.find(ngx.req.get_headers()["Content-Type"] or "","application/json", 0) then
+        args, err = json.decode(ngx.req.get_body_data())
+        if err then
+            core.log.error("json.decode(", ngx.req.get_body_data(), ") failed! ", err)
+        end
+    else
+        args = ngx.req.get_post_args()
+    end
+    return args
+end
+
+local function login()
+    local args = get_args()
+    if not args then
+        return core.response.exit(400, {message = "invalid request"})
+    end
+    if not args.appid then
+        return core.response.exit(400, {message = "appid is missing"})
+    end
+
+    local appid = args.appid
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return core.response.exit(500)
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.info("request appid [", appid, "] not found")
+        return core.response.exit(400, {message = "appid [" .. tostring(appid) .. "] not found"})
+    end
+
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+
+    local uri = consumer.auth_conf.server .. '/wolf/rbac/login.rest'
+    local headers = new_headers()
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local timeout = 1000 * 5
+    local request_debug = core.json.delay_encode(
+        {method = 'POST', uri = uri, body = args, headers = headers,timeout = timeout})
+    core.log.info("login request [", request_debug, "] ....")
+    local res, err = http_post(uri, core.json.encode(args), headers, timeout)
+    if err or not res then
+        core.log.error("login request [", request_debug, "] failed! err: ", err)
+        return core.response.exit(500, {message = "request to wolf-server failed! " .. tostring(err)})
+    end
+    core.log.info("login request [", request_debug, "] status: ", res.status, ", body: ", res.body)
+
+    if res.status ~= 200 then
+        core.log.error("login request [", request_debug, "] failed! status: ", res.status)
+        return core.response.exit(500, {message = "request to wolf-server failed! status:" .. tostring(res.status) })
+    end
+    local body = json.decode(res.body)
 
 Review comment:
   Done

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373767144
 
 

 ##########
 File path: doc/plugins/wolf-rbac-cn.md
 ##########
 @@ -0,0 +1,207 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+-->
+
+[English](wolf-rbac.md)
+
+# 目录
+
+- [**名字**](#名字)
+- [**属性**](#属性)
+- [**依赖项**](#依赖项)
+- [**如何启用**](#如何启用)
+- [**测试插件**](#测试插件)
+- [**禁用插件**](#禁用插件)
+
+## 名字
+
+`wolf-rbac`是一个认证及授权(rbac)插件,它需要与 `consumer` 一起配合才能工作。同时需要添加 `wolf-rbac` 到一个 `service` 或 `route`中。
+rbac功能由[wolf](https://github.com/iGeeky/wolf)提供, 有关wolf的更多信息, 请参考[wolf文档](https://github.com/iGeeky/wolf)。
 
 Review comment:
   Done

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373767077
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,380 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local cjson = require("cjson")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local ngx_time = ngx.time
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {type = "string"},
+        server = { type = 'string'},
+    }
+}
+
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token) 
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err=err}
+    end
+
+    if res[1] ~= token_version then
+        return { err='invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body=body, ssl_verify=false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode({method=method, uri=uri, body=body, headers=myheaders}), " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    if not conf.appid then
+        conf.appid = 'unset'
+    end
+    if not conf.server then
+        conf.server = 'http://127.0.0.1:10080'
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token()
+    local args = ngx.req.get_uri_args()
+    if args and args.rbac_token then
+        return args.rbac_token
+    end
+
+    local headers = ngx.req.get_headers()
+    if headers.Authorization then
+        return headers.Authorization
+    end
+    if headers['x-rbac-token'] then
+        return headers['x-rbac-token']
+    end
+    local cookie, err = ck:new()
+    if not cookie then
+        return nil, err
+    end
+    local val, err = cookie:get("x-rbac-token")
+    return val, err
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return cjson.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil;
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP=clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(100)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status=500, err="request to wolf-server failed, err:" .. tostring(err)}
+    elseif res.status == 200 or res.status == 401 then
+        local body, err = loadjson(res.body)
+	    if err then
+            errmsg = 'check permission failed! parse response json failed!'
+            core.log.error( "loadjson(", res.body, ") failed! err:", err)
+            return {status=res.status, err=errmsg}
+        else
+            if body.data then
+                userInfo = body.data.userInfo
+            end
+            errmsg = body.reason
+            return {status=res.status, err=errmsg, userInfo=userInfo}
+        end
+    else
+        return {status=500, err='request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action=action, url = url, clientIP = clientIP}
+
+	local rbac_token, err = fetch_rbac_token()
+	if rbac_token == nil then
+		core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo =parse_rbac_token(rbac_token)
+    core.log.info("token info: ", core.json.delay_encode(tokenInfo))
+    if tokenInfo.err then
+        return 401, {message = 'invalid rbac token: parse failed'}
+    end
+
+
+    local appid = tokenInfo.appid
+    local wolf_token = tokenInfo.wolf_token
+    permItem.appid = appid
+    permItem.wolf_token = wolf_token
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return 401, {message = "Missing related consumer"}
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.error("consumer [", appid, "] not found")
+        return 401, {message = "Invalid appid in rbac token"}
+    end
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+    local server = consumer.auth_conf.server
+
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {appid=appid, action=action, url = url, clientIP = clientIP, wolf_token=wolf_token}
+
+    local res = check_url_permission(server, appid, action, url, clientIP, wolf_token)
+	core.log.info(" check_url_permission(", core.json.delay_encode(permItem), ") res: ",core.json.delay_encode(res))
 
 Review comment:
   Done

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373766772
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,380 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local cjson = require("cjson")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local ngx_time = ngx.time
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {type = "string"},
+        server = { type = 'string'},
+    }
+}
+
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token) 
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err=err}
+    end
+
+    if res[1] ~= token_version then
+        return { err='invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body=body, ssl_verify=false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode({method=method, uri=uri, body=body, headers=myheaders}), " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    if not conf.appid then
+        conf.appid = 'unset'
+    end
+    if not conf.server then
+        conf.server = 'http://127.0.0.1:10080'
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token()
+    local args = ngx.req.get_uri_args()
+    if args and args.rbac_token then
+        return args.rbac_token
+    end
+
+    local headers = ngx.req.get_headers()
+    if headers.Authorization then
+        return headers.Authorization
+    end
+    if headers['x-rbac-token'] then
+        return headers['x-rbac-token']
+    end
+    local cookie, err = ck:new()
+    if not cookie then
+        return nil, err
+    end
+    local val, err = cookie:get("x-rbac-token")
+    return val, err
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return cjson.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil;
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP=clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(100)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status=500, err="request to wolf-server failed, err:" .. tostring(err)}
+    elseif res.status == 200 or res.status == 401 then
+        local body, err = loadjson(res.body)
+	    if err then
+            errmsg = 'check permission failed! parse response json failed!'
+            core.log.error( "loadjson(", res.body, ") failed! err:", err)
+            return {status=res.status, err=errmsg}
+        else
+            if body.data then
+                userInfo = body.data.userInfo
+            end
+            errmsg = body.reason
+            return {status=res.status, err=errmsg, userInfo=userInfo}
+        end
+    else
+        return {status=500, err='request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action=action, url = url, clientIP = clientIP}
+
+	local rbac_token, err = fetch_rbac_token()
+	if rbac_token == nil then
+		core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo =parse_rbac_token(rbac_token)
+    core.log.info("token info: ", core.json.delay_encode(tokenInfo))
+    if tokenInfo.err then
+        return 401, {message = 'invalid rbac token: parse failed'}
+    end
+
+
+    local appid = tokenInfo.appid
+    local wolf_token = tokenInfo.wolf_token
+    permItem.appid = appid
+    permItem.wolf_token = wolf_token
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return 401, {message = "Missing related consumer"}
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.error("consumer [", appid, "] not found")
+        return 401, {message = "Invalid appid in rbac token"}
+    end
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+    local server = consumer.auth_conf.server
+
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {appid=appid, action=action, url = url, clientIP = clientIP, wolf_token=wolf_token}
+
+    local res = check_url_permission(server, appid, action, url, clientIP, wolf_token)
+	core.log.info(" check_url_permission(", core.json.delay_encode(permItem), ") res: ",core.json.delay_encode(res))
+
+	local username = nil
+    local nickname = nil
+    if type(res.userInfo) == 'table' then
+        local userInfo = res.userInfo
+        core.response.set_header("X-UserId", userInfo.id)
+        core.response.set_header("X-Username", userInfo.username)
+        core.response.set_header("X-Nickname", ngx.escape_uri(userInfo.nickname) or userInfo.username)
+        ctx.userInfo = userInfo
+		username = userInfo.username
+        nickname = userInfo.nickname
+	end
+
+	if res.status == 200 then
 
 Review comment:
   Done

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373815874
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,376 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {
+            type = "string",
+            default = "unset"
+        },
+        server = {
+            type = "string",
+            default = "http://127.0.0.1:10080"
+        },
+    }
+}
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token)
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err = err}
+    end
+
+    if #res ~= 3 or res[1] ~= token_version then
+        return { err = 'invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body = body, ssl_verify = false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode(
+            {method = method, uri = uri, body = body, headers = myheaders}),
+            " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token(ctx)
+    if ctx.var.arg_rbac_token then
+        return ngx.unescape_uri(ctx.var.arg_rbac_token)
+    end
+
+    if ctx.var.http_authorization then
+        return ctx.var.http_authorization
+    end
+
+    if ctx.var.http_x_rbac_token then
+        return ctx.var.http_x_rbac_token
+    end
+
+    return ctx.var['cookie_x-rbac-token']
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return json.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP = clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(0.1)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status = 500, err = "request to wolf-server failed, err:" .. tostring(err)}
+    end
+
+    if res.status ~= 200 and res.status ~= 401 then
+        return {status = 500, err = 'request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+
+    local body, err = loadjson(res.body)
+    if err then
+        errmsg = 'check permission failed! parse response json failed!'
+        core.log.error( "loadjson(", res.body, ") failed! err:", err)
+        return {status = res.status, err = errmsg}
+    else
+        if body.data then
+            userInfo = body.data.userInfo
+        end
+        errmsg = body.reason
+        return {status = res.status, err = errmsg, userInfo = userInfo}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action = action, url = url, clientIP = clientIP}
+
+    local rbac_token = fetch_rbac_token(ctx)
+    if rbac_token == nil then
+        core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo = parse_rbac_token(rbac_token)
+    core.log.info("token info: ", core.json.delay_encode(tokenInfo))
+    if tokenInfo.err then
+        return 401, {message = 'invalid rbac token: parse failed'}
+    end
+
+
+    local appid = tokenInfo.appid
+    local wolf_token = tokenInfo.wolf_token
+    permItem.appid = appid
+    permItem.wolf_token = wolf_token
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return 401, {message = "Missing related consumer"}
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.error("consumer [", appid, "] not found")
+        return 401, {message = "Invalid appid in rbac token"}
+    end
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+    local server = consumer.auth_conf.server
+
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {appid = appid, action = action, url = url, clientIP = clientIP, wolf_token = wolf_token}
+
+    local res = check_url_permission(server, appid, action, url, clientIP, wolf_token)
+    core.log.info(" check_url_permission(", core.json.delay_encode(permItem), ") res: ",core.json.delay_encode(res))
+
+    local username = nil
+    local nickname = nil
+    if type(res.userInfo) == 'table' then
+        local userInfo = res.userInfo
+        core.response.set_header("X-UserId", userInfo.id)
+        core.response.set_header("X-Username", userInfo.username)
+        core.response.set_header("X-Nickname", ngx.escape_uri(userInfo.nickname) or userInfo.username)
+        ctx.userInfo = userInfo
+        username = userInfo.username
+        nickname = userInfo.nickname
+    end
+
+    if res.status == 200 then
+        ---
+    else
+        -- no permission.
+        core.log.error(" check_url_permission(", core.json.delay_encode(permItem), ") failed, res: ",core.json.delay_encode(res))
+        return 401, {message = res.err, username = username, nickname = nickname}
+    end
+    core.log.info("hit wolf-rbac rewrite")
+end
+
+local function get_args()
+    local args, err
+    ngx.req.read_body()
+    if string.find(ngx.req.get_headers()["Content-Type"] or "","application/json", 0) then
 
 Review comment:
   how to get the `ctx` in a api function?

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373898239
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,386 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+local core     = require("apisix.core")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local tostring = tostring
+local rawget   = rawget
+local rawset   = rawset
+local setmetatable = setmetatable
+local type     = type
+local string   = string
+
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {
+            type = "string",
+            default = "unset"
+        },
+        server = {
+            type = "string",
+            default = "http://127.0.0.1:10080"
+        },
+    }
+}
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token)
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err = err}
+    end
+
+    if #res ~= 3 or res[1] ~= token_version then
+        return { err = 'invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body = body, ssl_verify = false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode(
+            {method = method, uri = uri, body = body, headers = myheaders}),
+            " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token(ctx)
+    if ctx.var.arg_rbac_token then
+        return ngx.unescape_uri(ctx.var.arg_rbac_token)
+    end
+
+    if ctx.var.http_authorization then
+        return ctx.var.http_authorization
+    end
+
+    if ctx.var.http_x_rbac_token then
+        return ctx.var.http_x_rbac_token
+    end
+
+    return ctx.var['cookie_x-rbac-token']
+end
+
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg
+    local userInfo
+    local res
+    local err
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP = clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status,
+                            ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(0.1)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status = 500, err = "request to wolf-server failed, err:" .. tostring(err)}
+    end
+
+    if res.status ~= 200 and res.status ~= 401 then
+        return {status = 500, err = 'request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+
+    local body, err = json.decode(res.body)
+    if err then
+        errmsg = 'check permission failed! parse response json failed!'
+        core.log.error( "json.decode(", res.body, ") failed! err:", err)
+        return {status = res.status, err = errmsg}
+    else
+        if body.data then
+            userInfo = body.data.userInfo
+        end
+        errmsg = body.reason
+        return {status = res.status, err = errmsg, userInfo = userInfo}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action = action, url = url, clientIP = clientIP}
+    core.log.info("hit wolf-rbac rewrite")
+
+    local rbac_token = fetch_rbac_token(ctx)
+    if rbac_token == nil then
+        core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo = parse_rbac_token(rbac_token)
 
 Review comment:
   `local token, err = parse_rbac_token(rbac_token)`
   
   this style is better

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373766769
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,380 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local cjson = require("cjson")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local ngx_time = ngx.time
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {type = "string"},
+        server = { type = 'string'},
+    }
+}
+
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token) 
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err=err}
+    end
+
+    if res[1] ~= token_version then
+        return { err='invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body=body, ssl_verify=false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode({method=method, uri=uri, body=body, headers=myheaders}), " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    if not conf.appid then
+        conf.appid = 'unset'
+    end
+    if not conf.server then
+        conf.server = 'http://127.0.0.1:10080'
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token()
+    local args = ngx.req.get_uri_args()
+    if args and args.rbac_token then
+        return args.rbac_token
+    end
+
+    local headers = ngx.req.get_headers()
+    if headers.Authorization then
+        return headers.Authorization
+    end
+    if headers['x-rbac-token'] then
+        return headers['x-rbac-token']
+    end
+    local cookie, err = ck:new()
+    if not cookie then
+        return nil, err
+    end
+    local val, err = cookie:get("x-rbac-token")
+    return val, err
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return cjson.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil;
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP=clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(100)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status=500, err="request to wolf-server failed, err:" .. tostring(err)}
+    elseif res.status == 200 or res.status == 401 then
+        local body, err = loadjson(res.body)
+	    if err then
+            errmsg = 'check permission failed! parse response json failed!'
+            core.log.error( "loadjson(", res.body, ") failed! err:", err)
+            return {status=res.status, err=errmsg}
+        else
+            if body.data then
+                userInfo = body.data.userInfo
+            end
+            errmsg = body.reason
+            return {status=res.status, err=errmsg, userInfo=userInfo}
+        end
+    else
+        return {status=500, err='request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action=action, url = url, clientIP = clientIP}
+
+	local rbac_token, err = fetch_rbac_token()
+	if rbac_token == nil then
+		core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo =parse_rbac_token(rbac_token)
+    core.log.info("token info: ", core.json.delay_encode(tokenInfo))
+    if tokenInfo.err then
+        return 401, {message = 'invalid rbac token: parse failed'}
+    end
+
+
+    local appid = tokenInfo.appid
+    local wolf_token = tokenInfo.wolf_token
+    permItem.appid = appid
+    permItem.wolf_token = wolf_token
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return 401, {message = "Missing related consumer"}
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.error("consumer [", appid, "] not found")
+        return 401, {message = "Invalid appid in rbac token"}
+    end
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+    local server = consumer.auth_conf.server
+
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {appid=appid, action=action, url = url, clientIP = clientIP, wolf_token=wolf_token}
+
+    local res = check_url_permission(server, appid, action, url, clientIP, wolf_token)
+	core.log.info(" check_url_permission(", core.json.delay_encode(permItem), ") res: ",core.json.delay_encode(res))
+
+	local username = nil
+    local nickname = nil
+    if type(res.userInfo) == 'table' then
+        local userInfo = res.userInfo
+        core.response.set_header("X-UserId", userInfo.id)
+        core.response.set_header("X-Username", userInfo.username)
+        core.response.set_header("X-Nickname", ngx.escape_uri(userInfo.nickname) or userInfo.username)
+        ctx.userInfo = userInfo
+		username = userInfo.username
+        nickname = userInfo.nickname
+	end
+
+	if res.status == 200 then
+		---
+	else
+        -- no permission.
+        core.log.error(" check_url_permission(", core.json.delay_encode(permItem), ") failed, res: ",core.json.delay_encode(res))
+        return 401, {message = res.err, username=username, nickname=nickname}
+    end
+    core.log.info("hit wolf-rbac rewrite")
+end
+
+local function get_args()
+    local args, err
+    ngx.req.read_body()
+    if string.find(ngx.req.get_headers()["Content-Type"] or "","application/json", 0) then
+        args, err = json.decode(ngx.req.get_body_data())
+        if err then
+            core.log.error("json.decode(", ngx.req.get_body_data(), ") failed! ", err)
+        end
+    else
+        args = ngx.req.get_post_args()
+    end
+    return args;
+end
+
+local function login()
+    local args = get_args()
+    if not args then
+        return core.response.exit(400, {message = "invalid request"})
+    end
+    if not args.appid then
+        return core.response.exit(400, {message = "appid is missing"})
+    end
+
+    local appid = args.appid
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return core.response.exit(500)
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.info("request appid [", appid, "] not found")
+        return core.response.exit(400, {message = "appid [" .. tostring(appid) .. "] not found"})
+    end
+
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+
+    local uri = consumer.auth_conf.server .. '/wolf/rbac/login.rest'
+    local headers = new_headers()
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local timeout = 1000 * 5
+    local request_debug = core.json.delay_encode({method='POST', uri=uri, body=args, headers=headers,timeout=timeout})
+    core.log.info("login request [", request_debug, "] ....")
+    local res, err = http_post(uri, core.json.encode(args), headers, timeout)
+    if err or not res then
+        core.log.error("login request [", request_debug, "] failed! err: ", err)
+        return core.response.exit(500, {message = "request to wolf-server failed! " .. tostring(err)})
+    end
+    core.log.info("login request [", request_debug, "] status: ", res.status, ", body: ", res.body)
+
+    if res.status ~= 200 then
+        core.log.error("login request [", request_debug, "] failed! status: ", res.status)
+        return core.response.exit(500, {message = "request to wolf-server failed! status:" .. tostring(res.status) })
+    end
+    local body = json.decode(res.body)
+    if not body then
+        core.log.error("login request [", request_debug, "] failed! response body is nil")
+        return core.response.exit(500, {message = "request to wolf-server failed!"})
+    end
+    if not body.ok then
+        core.log.error("user login [", request_debug, "] failed! response body:", core.json.delay_encode(body))
+        return core.response.exit(200, {message = body.reason})
+    end
+    core.log.info("user login [", request_debug, "] success! response body:", core.json.delay_encode(body))
+
+    local userInfo = body.data.userInfo
+    local wolf_token = body.data.token;
 
 Review comment:
   Done

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373767084
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,380 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local cjson = require("cjson")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local ngx_time = ngx.time
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {type = "string"},
+        server = { type = 'string'},
+    }
+}
+
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token) 
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err=err}
+    end
+
+    if res[1] ~= token_version then
+        return { err='invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body=body, ssl_verify=false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode({method=method, uri=uri, body=body, headers=myheaders}), " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    if not conf.appid then
+        conf.appid = 'unset'
+    end
+    if not conf.server then
+        conf.server = 'http://127.0.0.1:10080'
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token()
+    local args = ngx.req.get_uri_args()
+    if args and args.rbac_token then
+        return args.rbac_token
+    end
+
+    local headers = ngx.req.get_headers()
+    if headers.Authorization then
+        return headers.Authorization
+    end
+    if headers['x-rbac-token'] then
+        return headers['x-rbac-token']
+    end
+    local cookie, err = ck:new()
+    if not cookie then
+        return nil, err
+    end
+    local val, err = cookie:get("x-rbac-token")
+    return val, err
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return cjson.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil;
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP=clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(100)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status=500, err="request to wolf-server failed, err:" .. tostring(err)}
+    elseif res.status == 200 or res.status == 401 then
+        local body, err = loadjson(res.body)
+	    if err then
+            errmsg = 'check permission failed! parse response json failed!'
+            core.log.error( "loadjson(", res.body, ") failed! err:", err)
+            return {status=res.status, err=errmsg}
+        else
+            if body.data then
+                userInfo = body.data.userInfo
+            end
+            errmsg = body.reason
+            return {status=res.status, err=errmsg, userInfo=userInfo}
+        end
+    else
+        return {status=500, err='request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action=action, url = url, clientIP = clientIP}
+
+	local rbac_token, err = fetch_rbac_token()
+	if rbac_token == nil then
+		core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo =parse_rbac_token(rbac_token)
 
 Review comment:
   Done

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373753953
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,380 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local cjson = require("cjson")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local ngx_time = ngx.time
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {type = "string"},
+        server = { type = 'string'},
+    }
+}
+
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token) 
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err=err}
+    end
+
+    if res[1] ~= token_version then
+        return { err='invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body=body, ssl_verify=false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode({method=method, uri=uri, body=body, headers=myheaders}), " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    if not conf.appid then
+        conf.appid = 'unset'
+    end
+    if not conf.server then
+        conf.server = 'http://127.0.0.1:10080'
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token()
+    local args = ngx.req.get_uri_args()
+    if args and args.rbac_token then
+        return args.rbac_token
+    end
+
+    local headers = ngx.req.get_headers()
+    if headers.Authorization then
+        return headers.Authorization
+    end
+    if headers['x-rbac-token'] then
+        return headers['x-rbac-token']
+    end
+    local cookie, err = ck:new()
+    if not cookie then
+        return nil, err
+    end
+    local val, err = cookie:get("x-rbac-token")
+    return val, err
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return cjson.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil;
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP=clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(100)
+                end
+            end
+        end
+    end
+
+    if err then
 
 Review comment:
   this is a bad code style, please take a look at this new style:
   
   ```lua
   if err then
       -- ...
   end
   
   if res.status ~= 200 and res.status ~= 401 then
       return {status=500, err='request to wolf-server failed, status:' .. tostring(res.status)}
   end
   
   -- ... other code
   
   ```

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373767129
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,380 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local cjson = require("cjson")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local ngx_time = ngx.time
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {type = "string"},
+        server = { type = 'string'},
+    }
+}
+
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token) 
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err=err}
+    end
+
+    if res[1] ~= token_version then
+        return { err='invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body=body, ssl_verify=false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode({method=method, uri=uri, body=body, headers=myheaders}), " ] failed! res is nil, err:", err)
 
 Review comment:
   Done

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373908367
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,386 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+local core     = require("apisix.core")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local tostring = tostring
+local rawget   = rawget
+local rawset   = rawset
+local setmetatable = setmetatable
+local type     = type
+local string   = string
+
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {
+            type = "string",
+            default = "unset"
+        },
+        server = {
+            type = "string",
+            default = "http://127.0.0.1:10080"
+        },
+    }
+}
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token)
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err = err}
+    end
+
+    if #res ~= 3 or res[1] ~= token_version then
+        return { err = 'invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body = body, ssl_verify = false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode(
+            {method = method, uri = uri, body = body, headers = myheaders}),
+            " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token(ctx)
+    if ctx.var.arg_rbac_token then
+        return ngx.unescape_uri(ctx.var.arg_rbac_token)
+    end
+
+    if ctx.var.http_authorization then
+        return ctx.var.http_authorization
+    end
+
+    if ctx.var.http_x_rbac_token then
+        return ctx.var.http_x_rbac_token
+    end
+
+    return ctx.var['cookie_x-rbac-token']
+end
+
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg
+    local userInfo
+    local res
+    local err
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP = clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status,
+                            ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(0.1)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status = 500, err = "request to wolf-server failed, err:" .. tostring(err)}
+    end
+
+    if res.status ~= 200 and res.status ~= 401 then
+        return {status = 500, err = 'request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+
+    local body, err = json.decode(res.body)
+    if err then
+        errmsg = 'check permission failed! parse response json failed!'
+        core.log.error( "json.decode(", res.body, ") failed! err:", err)
+        return {status = res.status, err = errmsg}
+    else
+        if body.data then
+            userInfo = body.data.userInfo
+        end
+        errmsg = body.reason
+        return {status = res.status, err = errmsg, userInfo = userInfo}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action = action, url = url, clientIP = clientIP}
+    core.log.info("hit wolf-rbac rewrite")
+
+    local rbac_token = fetch_rbac_token(ctx)
+    if rbac_token == nil then
+        core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo = parse_rbac_token(rbac_token)
+    core.log.info("token info: ", core.json.delay_encode(tokenInfo))
+    if tokenInfo.err then
+        return 401, {message = 'invalid rbac token: parse failed'}
+    end
+
+    local appid = tokenInfo.appid
+    local wolf_token = tokenInfo.wolf_token
+    permItem.appid = appid
+    permItem.wolf_token = wolf_token
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return 401, {message = "Missing related consumer"}
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.error("consumer [", appid, "] not found")
+        return 401, {message = "Invalid appid in rbac token"}
+    end
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+    local server = consumer.auth_conf.server
+
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {appid = appid, action = action, url = url, clientIP = clientIP, wolf_token = wolf_token}
+
+    local res = check_url_permission(server, appid, action, url, clientIP, wolf_token)
+    core.log.info(" check_url_permission(", core.json.delay_encode(permItem), ") res: ",core.json.delay_encode(res))
+
+    local username = nil
+    local nickname = nil
+    if type(res.userInfo) == 'table' then
+        local userInfo = res.userInfo
+        core.response.set_header("X-UserId", userInfo.id)
+        core.response.set_header("X-Username", userInfo.username)
+        core.response.set_header("X-Nickname", ngx.escape_uri(userInfo.nickname) or userInfo.username)
+        ctx.userInfo = userInfo
+        username = userInfo.username
+        nickname = userInfo.nickname
+    end
+
+    if res.status ~= 200 then
+        -- no permission.
+        core.log.error(" check_url_permission(", core.json.delay_encode(permItem),
+            ") failed, res: ",core.json.delay_encode(res))
 
 Review comment:
   Done

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373753510
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,380 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local cjson = require("cjson")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local ngx_time = ngx.time
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {type = "string"},
+        server = { type = 'string'},
+    }
+}
+
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token) 
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err=err}
+    end
+
+    if res[1] ~= token_version then
+        return { err='invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body=body, ssl_verify=false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode({method=method, uri=uri, body=body, headers=myheaders}), " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    if not conf.appid then
 
 Review comment:
   We can set the default value by schema.
   
   Here is an example: https://github.com/apache/incubator-apisix/blob/e6804360d1712d456cfee31b9d6abb8b16cfffba/lua/apisix/schema_def.lua#L76

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373776873
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,376 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {
+            type = "string",
+            default = "unset"
+        },
+        server = {
+            type = "string",
+            default = "http://127.0.0.1:10080"
+        },
+    }
+}
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token)
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err = err}
+    end
+
+    if #res ~= 3 or res[1] ~= token_version then
+        return { err = 'invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body = body, ssl_verify = false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode(
+            {method = method, uri = uri, body = body, headers = myheaders}),
+            " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token(ctx)
+    if ctx.var.arg_rbac_token then
+        return ngx.unescape_uri(ctx.var.arg_rbac_token)
+    end
+
+    if ctx.var.http_authorization then
+        return ctx.var.http_authorization
+    end
+
+    if ctx.var.http_x_rbac_token then
+        return ctx.var.http_x_rbac_token
+    end
+
+    return ctx.var['cookie_x-rbac-token']
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return json.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP = clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(0.1)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status = 500, err = "request to wolf-server failed, err:" .. tostring(err)}
+    end
+
+    if res.status ~= 200 and res.status ~= 401 then
+        return {status = 500, err = 'request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+
+    local body, err = loadjson(res.body)
+    if err then
+        errmsg = 'check permission failed! parse response json failed!'
+        core.log.error( "loadjson(", res.body, ") failed! err:", err)
+        return {status = res.status, err = errmsg}
+    else
+        if body.data then
+            userInfo = body.data.userInfo
+        end
+        errmsg = body.reason
+        return {status = res.status, err = errmsg, userInfo = userInfo}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action = action, url = url, clientIP = clientIP}
+
+    local rbac_token = fetch_rbac_token(ctx)
+    if rbac_token == nil then
+        core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo = parse_rbac_token(rbac_token)
+    core.log.info("token info: ", core.json.delay_encode(tokenInfo))
+    if tokenInfo.err then
+        return 401, {message = 'invalid rbac token: parse failed'}
+    end
+
+
+    local appid = tokenInfo.appid
+    local wolf_token = tokenInfo.wolf_token
+    permItem.appid = appid
+    permItem.wolf_token = wolf_token
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return 401, {message = "Missing related consumer"}
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.error("consumer [", appid, "] not found")
+        return 401, {message = "Invalid appid in rbac token"}
+    end
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+    local server = consumer.auth_conf.server
+
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {appid = appid, action = action, url = url, clientIP = clientIP, wolf_token = wolf_token}
+
+    local res = check_url_permission(server, appid, action, url, clientIP, wolf_token)
+    core.log.info(" check_url_permission(", core.json.delay_encode(permItem), ") res: ",core.json.delay_encode(res))
+
+    local username = nil
+    local nickname = nil
+    if type(res.userInfo) == 'table' then
+        local userInfo = res.userInfo
+        core.response.set_header("X-UserId", userInfo.id)
+        core.response.set_header("X-Username", userInfo.username)
+        core.response.set_header("X-Nickname", ngx.escape_uri(userInfo.nickname) or userInfo.username)
+        ctx.userInfo = userInfo
+        username = userInfo.username
+        nickname = userInfo.nickname
+    end
+
+    if res.status == 200 then
+        ---
+    else
+        -- no permission.
+        core.log.error(" check_url_permission(", core.json.delay_encode(permItem), ") failed, res: ",core.json.delay_encode(res))
+        return 401, {message = res.err, username = username, nickname = nickname}
+    end
+    core.log.info("hit wolf-rbac rewrite")
+end
+
+local function get_args()
+    local args, err
+    ngx.req.read_body()
+    if string.find(ngx.req.get_headers()["Content-Type"] or "","application/json", 0) then
 
 Review comment:
   We can turn off the pattern matching feature by using the optional fourth argument plain.
   
   `> = string.find("Hello Lua user", "%su", 1, true) -- turn on plain searches, now not found`
   
   http://lua-users.org/wiki/StringLibraryTutorial

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373776741
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,376 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {
+            type = "string",
+            default = "unset"
+        },
+        server = {
+            type = "string",
+            default = "http://127.0.0.1:10080"
+        },
+    }
+}
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token)
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err = err}
+    end
+
+    if #res ~= 3 or res[1] ~= token_version then
+        return { err = 'invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body = body, ssl_verify = false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode(
+            {method = method, uri = uri, body = body, headers = myheaders}),
+            " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token(ctx)
+    if ctx.var.arg_rbac_token then
+        return ngx.unescape_uri(ctx.var.arg_rbac_token)
+    end
+
+    if ctx.var.http_authorization then
+        return ctx.var.http_authorization
+    end
+
+    if ctx.var.http_x_rbac_token then
+        return ctx.var.http_x_rbac_token
+    end
+
+    return ctx.var['cookie_x-rbac-token']
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return json.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP = clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(0.1)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status = 500, err = "request to wolf-server failed, err:" .. tostring(err)}
+    end
+
+    if res.status ~= 200 and res.status ~= 401 then
+        return {status = 500, err = 'request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+
+    local body, err = loadjson(res.body)
+    if err then
+        errmsg = 'check permission failed! parse response json failed!'
+        core.log.error( "loadjson(", res.body, ") failed! err:", err)
+        return {status = res.status, err = errmsg}
+    else
+        if body.data then
+            userInfo = body.data.userInfo
+        end
+        errmsg = body.reason
+        return {status = res.status, err = errmsg, userInfo = userInfo}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action = action, url = url, clientIP = clientIP}
+
+    local rbac_token = fetch_rbac_token(ctx)
+    if rbac_token == nil then
+        core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo = parse_rbac_token(rbac_token)
+    core.log.info("token info: ", core.json.delay_encode(tokenInfo))
+    if tokenInfo.err then
+        return 401, {message = 'invalid rbac token: parse failed'}
+    end
+
+
+    local appid = tokenInfo.appid
+    local wolf_token = tokenInfo.wolf_token
+    permItem.appid = appid
+    permItem.wolf_token = wolf_token
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return 401, {message = "Missing related consumer"}
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.error("consumer [", appid, "] not found")
+        return 401, {message = "Invalid appid in rbac token"}
+    end
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+    local server = consumer.auth_conf.server
+
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {appid = appid, action = action, url = url, clientIP = clientIP, wolf_token = wolf_token}
+
+    local res = check_url_permission(server, appid, action, url, clientIP, wolf_token)
+    core.log.info(" check_url_permission(", core.json.delay_encode(permItem), ") res: ",core.json.delay_encode(res))
+
+    local username = nil
+    local nickname = nil
+    if type(res.userInfo) == 'table' then
+        local userInfo = res.userInfo
+        core.response.set_header("X-UserId", userInfo.id)
+        core.response.set_header("X-Username", userInfo.username)
+        core.response.set_header("X-Nickname", ngx.escape_uri(userInfo.nickname) or userInfo.username)
+        ctx.userInfo = userInfo
+        username = userInfo.username
+        nickname = userInfo.nickname
+    end
+
+    if res.status == 200 then
+        ---
+    else
+        -- no permission.
+        core.log.error(" check_url_permission(", core.json.delay_encode(permItem), ") failed, res: ",core.json.delay_encode(res))
 
 Review comment:
   this line is too long, need a shorter style

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373908303
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,386 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+local core     = require("apisix.core")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local tostring = tostring
+local rawget   = rawget
+local rawset   = rawset
+local setmetatable = setmetatable
+local type     = type
+local string   = string
+
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {
+            type = "string",
+            default = "unset"
+        },
+        server = {
+            type = "string",
+            default = "http://127.0.0.1:10080"
+        },
+    }
+}
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token)
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err = err}
+    end
+
+    if #res ~= 3 or res[1] ~= token_version then
+        return { err = 'invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body = body, ssl_verify = false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode(
+            {method = method, uri = uri, body = body, headers = myheaders}),
+            " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token(ctx)
+    if ctx.var.arg_rbac_token then
+        return ngx.unescape_uri(ctx.var.arg_rbac_token)
+    end
+
+    if ctx.var.http_authorization then
+        return ctx.var.http_authorization
+    end
+
+    if ctx.var.http_x_rbac_token then
+        return ctx.var.http_x_rbac_token
+    end
+
+    return ctx.var['cookie_x-rbac-token']
+end
+
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg
+    local userInfo
+    local res
+    local err
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP = clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status,
+                            ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(0.1)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status = 500, err = "request to wolf-server failed, err:" .. tostring(err)}
+    end
+
+    if res.status ~= 200 and res.status ~= 401 then
+        return {status = 500, err = 'request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+
+    local body, err = json.decode(res.body)
+    if err then
+        errmsg = 'check permission failed! parse response json failed!'
+        core.log.error( "json.decode(", res.body, ") failed! err:", err)
+        return {status = res.status, err = errmsg}
+    else
+        if body.data then
+            userInfo = body.data.userInfo
+        end
+        errmsg = body.reason
+        return {status = res.status, err = errmsg, userInfo = userInfo}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action = action, url = url, clientIP = clientIP}
+    core.log.info("hit wolf-rbac rewrite")
+
+    local rbac_token = fetch_rbac_token(ctx)
+    if rbac_token == nil then
+        core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo = parse_rbac_token(rbac_token)
+    core.log.info("token info: ", core.json.delay_encode(tokenInfo))
+    if tokenInfo.err then
+        return 401, {message = 'invalid rbac token: parse failed'}
 
 Review comment:
   Done

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] moonming merged pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
moonming merged pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095
 
 
   

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373754045
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,380 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local cjson = require("cjson")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local ngx_time = ngx.time
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {type = "string"},
+        server = { type = 'string'},
+    }
+}
+
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token) 
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err=err}
+    end
+
+    if res[1] ~= token_version then
+        return { err='invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body=body, ssl_verify=false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode({method=method, uri=uri, body=body, headers=myheaders}), " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    if not conf.appid then
+        conf.appid = 'unset'
+    end
+    if not conf.server then
+        conf.server = 'http://127.0.0.1:10080'
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token()
+    local args = ngx.req.get_uri_args()
+    if args and args.rbac_token then
+        return args.rbac_token
+    end
+
+    local headers = ngx.req.get_headers()
+    if headers.Authorization then
+        return headers.Authorization
+    end
+    if headers['x-rbac-token'] then
+        return headers['x-rbac-token']
+    end
+    local cookie, err = ck:new()
+    if not cookie then
+        return nil, err
+    end
+    local val, err = cookie:get("x-rbac-token")
+    return val, err
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return cjson.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil;
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP=clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(100)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status=500, err="request to wolf-server failed, err:" .. tostring(err)}
+    elseif res.status == 200 or res.status == 401 then
+        local body, err = loadjson(res.body)
+	    if err then
+            errmsg = 'check permission failed! parse response json failed!'
+            core.log.error( "loadjson(", res.body, ") failed! err:", err)
+            return {status=res.status, err=errmsg}
+        else
+            if body.data then
+                userInfo = body.data.userInfo
+            end
+            errmsg = body.reason
+            return {status=res.status, err=errmsg, userInfo=userInfo}
+        end
+    else
+        return {status=500, err='request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action=action, url = url, clientIP = clientIP}
+
+	local rbac_token, err = fetch_rbac_token()
+	if rbac_token == nil then
+		core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
 
 Review comment:
   bad indentation

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373816684
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,376 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {
+            type = "string",
+            default = "unset"
+        },
+        server = {
+            type = "string",
+            default = "http://127.0.0.1:10080"
+        },
+    }
+}
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token)
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err = err}
+    end
+
+    if #res ~= 3 or res[1] ~= token_version then
+        return { err = 'invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body = body, ssl_verify = false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode(
+            {method = method, uri = uri, body = body, headers = myheaders}),
+            " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token(ctx)
+    if ctx.var.arg_rbac_token then
+        return ngx.unescape_uri(ctx.var.arg_rbac_token)
+    end
+
+    if ctx.var.http_authorization then
+        return ctx.var.http_authorization
+    end
+
+    if ctx.var.http_x_rbac_token then
+        return ctx.var.http_x_rbac_token
+    end
+
+    return ctx.var['cookie_x-rbac-token']
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return json.decode(str) end)
 
 Review comment:
   Done

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373754452
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,380 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local cjson = require("cjson")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local ngx_time = ngx.time
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {type = "string"},
+        server = { type = 'string'},
+    }
+}
+
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token) 
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err=err}
+    end
+
+    if res[1] ~= token_version then
+        return { err='invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body=body, ssl_verify=false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode({method=method, uri=uri, body=body, headers=myheaders}), " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    if not conf.appid then
+        conf.appid = 'unset'
+    end
+    if not conf.server then
+        conf.server = 'http://127.0.0.1:10080'
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token()
+    local args = ngx.req.get_uri_args()
+    if args and args.rbac_token then
+        return args.rbac_token
+    end
+
+    local headers = ngx.req.get_headers()
+    if headers.Authorization then
+        return headers.Authorization
+    end
+    if headers['x-rbac-token'] then
+        return headers['x-rbac-token']
+    end
+    local cookie, err = ck:new()
+    if not cookie then
+        return nil, err
+    end
+    local val, err = cookie:get("x-rbac-token")
+    return val, err
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return cjson.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil;
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP=clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(100)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status=500, err="request to wolf-server failed, err:" .. tostring(err)}
+    elseif res.status == 200 or res.status == 401 then
+        local body, err = loadjson(res.body)
+	    if err then
+            errmsg = 'check permission failed! parse response json failed!'
+            core.log.error( "loadjson(", res.body, ") failed! err:", err)
+            return {status=res.status, err=errmsg}
+        else
+            if body.data then
+                userInfo = body.data.userInfo
+            end
+            errmsg = body.reason
+            return {status=res.status, err=errmsg, userInfo=userInfo}
+        end
+    else
+        return {status=500, err='request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action=action, url = url, clientIP = clientIP}
+
+	local rbac_token, err = fetch_rbac_token()
+	if rbac_token == nil then
+		core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo =parse_rbac_token(rbac_token)
+    core.log.info("token info: ", core.json.delay_encode(tokenInfo))
+    if tokenInfo.err then
+        return 401, {message = 'invalid rbac token: parse failed'}
+    end
+
+
+    local appid = tokenInfo.appid
+    local wolf_token = tokenInfo.wolf_token
+    permItem.appid = appid
+    permItem.wolf_token = wolf_token
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return 401, {message = "Missing related consumer"}
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.error("consumer [", appid, "] not found")
+        return 401, {message = "Invalid appid in rbac token"}
+    end
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+    local server = consumer.auth_conf.server
+
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {appid=appid, action=action, url = url, clientIP = clientIP, wolf_token=wolf_token}
+
+    local res = check_url_permission(server, appid, action, url, clientIP, wolf_token)
+	core.log.info(" check_url_permission(", core.json.delay_encode(permItem), ") res: ",core.json.delay_encode(res))
+
+	local username = nil
+    local nickname = nil
+    if type(res.userInfo) == 'table' then
+        local userInfo = res.userInfo
+        core.response.set_header("X-UserId", userInfo.id)
+        core.response.set_header("X-Username", userInfo.username)
+        core.response.set_header("X-Nickname", ngx.escape_uri(userInfo.nickname) or userInfo.username)
+        ctx.userInfo = userInfo
+		username = userInfo.username
+        nickname = userInfo.nickname
+	end
+
+	if res.status == 200 then
+		---
+	else
+        -- no permission.
+        core.log.error(" check_url_permission(", core.json.delay_encode(permItem), ") failed, res: ",core.json.delay_encode(res))
+        return 401, {message = res.err, username=username, nickname=nickname}
+    end
+    core.log.info("hit wolf-rbac rewrite")
+end
+
+local function get_args()
+    local args, err
+    ngx.req.read_body()
+    if string.find(ngx.req.get_headers()["Content-Type"] or "","application/json", 0) then
+        args, err = json.decode(ngx.req.get_body_data())
+        if err then
+            core.log.error("json.decode(", ngx.req.get_body_data(), ") failed! ", err)
+        end
+    else
+        args = ngx.req.get_post_args()
+    end
+    return args;
+end
+
+local function login()
+    local args = get_args()
+    if not args then
+        return core.response.exit(400, {message = "invalid request"})
+    end
+    if not args.appid then
+        return core.response.exit(400, {message = "appid is missing"})
+    end
+
+    local appid = args.appid
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return core.response.exit(500)
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.info("request appid [", appid, "] not found")
+        return core.response.exit(400, {message = "appid [" .. tostring(appid) .. "] not found"})
+    end
+
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+
+    local uri = consumer.auth_conf.server .. '/wolf/rbac/login.rest'
+    local headers = new_headers()
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local timeout = 1000 * 5
+    local request_debug = core.json.delay_encode({method='POST', uri=uri, body=args, headers=headers,timeout=timeout})
+    core.log.info("login request [", request_debug, "] ....")
+    local res, err = http_post(uri, core.json.encode(args), headers, timeout)
+    if err or not res then
+        core.log.error("login request [", request_debug, "] failed! err: ", err)
+        return core.response.exit(500, {message = "request to wolf-server failed! " .. tostring(err)})
+    end
+    core.log.info("login request [", request_debug, "] status: ", res.status, ", body: ", res.body)
+
+    if res.status ~= 200 then
+        core.log.error("login request [", request_debug, "] failed! status: ", res.status)
+        return core.response.exit(500, {message = "request to wolf-server failed! status:" .. tostring(res.status) })
+    end
+    local body = json.decode(res.body)
+    if not body then
+        core.log.error("login request [", request_debug, "] failed! response body is nil")
+        return core.response.exit(500, {message = "request to wolf-server failed!"})
+    end
+    if not body.ok then
+        core.log.error("user login [", request_debug, "] failed! response body:", core.json.delay_encode(body))
+        return core.response.exit(200, {message = body.reason})
+    end
+    core.log.info("user login [", request_debug, "] success! response body:", core.json.delay_encode(body))
+
+    local userInfo = body.data.userInfo
+    local wolf_token = body.data.token;
 
 Review comment:
   `;` is uesless

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373776622
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,376 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {
+            type = "string",
+            default = "unset"
+        },
+        server = {
+            type = "string",
+            default = "http://127.0.0.1:10080"
+        },
+    }
+}
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token)
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err = err}
+    end
+
+    if #res ~= 3 or res[1] ~= token_version then
+        return { err = 'invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body = body, ssl_verify = false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode(
+            {method = method, uri = uri, body = body, headers = myheaders}),
+            " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token(ctx)
+    if ctx.var.arg_rbac_token then
+        return ngx.unescape_uri(ctx.var.arg_rbac_token)
+    end
+
+    if ctx.var.http_authorization then
+        return ctx.var.http_authorization
+    end
+
+    if ctx.var.http_x_rbac_token then
+        return ctx.var.http_x_rbac_token
+    end
+
+    return ctx.var['cookie_x-rbac-token']
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return json.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil
 
 Review comment:
   `local errmsg = nil` to `local errmsg`
   
   new code is simpler

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373754218
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,380 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local cjson = require("cjson")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local ngx_time = ngx.time
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {type = "string"},
+        server = { type = 'string'},
+    }
+}
+
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token) 
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err=err}
+    end
+
+    if res[1] ~= token_version then
+        return { err='invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body=body, ssl_verify=false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode({method=method, uri=uri, body=body, headers=myheaders}), " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    if not conf.appid then
+        conf.appid = 'unset'
+    end
+    if not conf.server then
+        conf.server = 'http://127.0.0.1:10080'
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token()
+    local args = ngx.req.get_uri_args()
+    if args and args.rbac_token then
+        return args.rbac_token
+    end
+
+    local headers = ngx.req.get_headers()
+    if headers.Authorization then
+        return headers.Authorization
+    end
+    if headers['x-rbac-token'] then
+        return headers['x-rbac-token']
+    end
+    local cookie, err = ck:new()
+    if not cookie then
+        return nil, err
+    end
+    local val, err = cookie:get("x-rbac-token")
+    return val, err
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return cjson.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil;
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP=clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(100)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status=500, err="request to wolf-server failed, err:" .. tostring(err)}
+    elseif res.status == 200 or res.status == 401 then
+        local body, err = loadjson(res.body)
+	    if err then
+            errmsg = 'check permission failed! parse response json failed!'
+            core.log.error( "loadjson(", res.body, ") failed! err:", err)
+            return {status=res.status, err=errmsg}
+        else
+            if body.data then
+                userInfo = body.data.userInfo
+            end
+            errmsg = body.reason
+            return {status=res.status, err=errmsg, userInfo=userInfo}
+        end
+    else
+        return {status=500, err='request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action=action, url = url, clientIP = clientIP}
+
+	local rbac_token, err = fetch_rbac_token()
+	if rbac_token == nil then
+		core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo =parse_rbac_token(rbac_token)
+    core.log.info("token info: ", core.json.delay_encode(tokenInfo))
+    if tokenInfo.err then
+        return 401, {message = 'invalid rbac token: parse failed'}
+    end
+
+
+    local appid = tokenInfo.appid
+    local wolf_token = tokenInfo.wolf_token
+    permItem.appid = appid
+    permItem.wolf_token = wolf_token
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return 401, {message = "Missing related consumer"}
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.error("consumer [", appid, "] not found")
+        return 401, {message = "Invalid appid in rbac token"}
+    end
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+    local server = consumer.auth_conf.server
+
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {appid=appid, action=action, url = url, clientIP = clientIP, wolf_token=wolf_token}
+
+    local res = check_url_permission(server, appid, action, url, clientIP, wolf_token)
+	core.log.info(" check_url_permission(", core.json.delay_encode(permItem), ") res: ",core.json.delay_encode(res))
+
+	local username = nil
+    local nickname = nil
+    if type(res.userInfo) == 'table' then
+        local userInfo = res.userInfo
+        core.response.set_header("X-UserId", userInfo.id)
+        core.response.set_header("X-Username", userInfo.username)
+        core.response.set_header("X-Nickname", ngx.escape_uri(userInfo.nickname) or userInfo.username)
+        ctx.userInfo = userInfo
+		username = userInfo.username
+        nickname = userInfo.nickname
+	end
+
+	if res.status == 200 then
 
 Review comment:
   I think we should check `res.status` first.

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373767142
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,380 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local cjson = require("cjson")
 
 Review comment:
   Done

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373816692
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,376 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {
+            type = "string",
+            default = "unset"
+        },
+        server = {
+            type = "string",
+            default = "http://127.0.0.1:10080"
+        },
+    }
+}
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token)
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err = err}
+    end
+
+    if #res ~= 3 or res[1] ~= token_version then
+        return { err = 'invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body = body, ssl_verify = false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode(
+            {method = method, uri = uri, body = body, headers = myheaders}),
+            " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token(ctx)
+    if ctx.var.arg_rbac_token then
+        return ngx.unescape_uri(ctx.var.arg_rbac_token)
+    end
+
+    if ctx.var.http_authorization then
+        return ctx.var.http_authorization
+    end
+
+    if ctx.var.http_x_rbac_token then
+        return ctx.var.http_x_rbac_token
+    end
+
+    return ctx.var['cookie_x-rbac-token']
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return json.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil
 
 Review comment:
   Done

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373754186
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,380 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local cjson = require("cjson")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local ngx_time = ngx.time
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {type = "string"},
+        server = { type = 'string'},
+    }
+}
+
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token) 
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err=err}
+    end
+
+    if res[1] ~= token_version then
+        return { err='invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body=body, ssl_verify=false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode({method=method, uri=uri, body=body, headers=myheaders}), " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    if not conf.appid then
+        conf.appid = 'unset'
+    end
+    if not conf.server then
+        conf.server = 'http://127.0.0.1:10080'
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token()
+    local args = ngx.req.get_uri_args()
+    if args and args.rbac_token then
+        return args.rbac_token
+    end
+
+    local headers = ngx.req.get_headers()
+    if headers.Authorization then
+        return headers.Authorization
+    end
+    if headers['x-rbac-token'] then
+        return headers['x-rbac-token']
+    end
+    local cookie, err = ck:new()
+    if not cookie then
+        return nil, err
+    end
+    local val, err = cookie:get("x-rbac-token")
+    return val, err
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return cjson.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil;
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP=clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(100)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status=500, err="request to wolf-server failed, err:" .. tostring(err)}
+    elseif res.status == 200 or res.status == 401 then
+        local body, err = loadjson(res.body)
+	    if err then
+            errmsg = 'check permission failed! parse response json failed!'
+            core.log.error( "loadjson(", res.body, ") failed! err:", err)
+            return {status=res.status, err=errmsg}
+        else
+            if body.data then
+                userInfo = body.data.userInfo
+            end
+            errmsg = body.reason
+            return {status=res.status, err=errmsg, userInfo=userInfo}
+        end
+    else
+        return {status=500, err='request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action=action, url = url, clientIP = clientIP}
+
+	local rbac_token, err = fetch_rbac_token()
+	if rbac_token == nil then
+		core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo =parse_rbac_token(rbac_token)
+    core.log.info("token info: ", core.json.delay_encode(tokenInfo))
+    if tokenInfo.err then
+        return 401, {message = 'invalid rbac token: parse failed'}
+    end
+
+
+    local appid = tokenInfo.appid
+    local wolf_token = tokenInfo.wolf_token
+    permItem.appid = appid
+    permItem.wolf_token = wolf_token
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return 401, {message = "Missing related consumer"}
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.error("consumer [", appid, "] not found")
+        return 401, {message = "Invalid appid in rbac token"}
+    end
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+    local server = consumer.auth_conf.server
+
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {appid=appid, action=action, url = url, clientIP = clientIP, wolf_token=wolf_token}
+
+    local res = check_url_permission(server, appid, action, url, clientIP, wolf_token)
+	core.log.info(" check_url_permission(", core.json.delay_encode(permItem), ") res: ",core.json.delay_encode(res))
 
 Review comment:
   Replace tabs with four spaces.

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373776686
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,376 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {
+            type = "string",
+            default = "unset"
+        },
+        server = {
+            type = "string",
+            default = "http://127.0.0.1:10080"
+        },
+    }
+}
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token)
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err = err}
+    end
+
+    if #res ~= 3 or res[1] ~= token_version then
+        return { err = 'invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body = body, ssl_verify = false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode(
+            {method = method, uri = uri, body = body, headers = myheaders}),
+            " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token(ctx)
+    if ctx.var.arg_rbac_token then
+        return ngx.unescape_uri(ctx.var.arg_rbac_token)
+    end
+
+    if ctx.var.http_authorization then
+        return ctx.var.http_authorization
+    end
+
+    if ctx.var.http_x_rbac_token then
+        return ctx.var.http_x_rbac_token
+    end
+
+    return ctx.var['cookie_x-rbac-token']
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return json.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP = clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(0.1)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status = 500, err = "request to wolf-server failed, err:" .. tostring(err)}
+    end
+
+    if res.status ~= 200 and res.status ~= 401 then
+        return {status = 500, err = 'request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+
+    local body, err = loadjson(res.body)
+    if err then
+        errmsg = 'check permission failed! parse response json failed!'
+        core.log.error( "loadjson(", res.body, ") failed! err:", err)
+        return {status = res.status, err = errmsg}
+    else
+        if body.data then
+            userInfo = body.data.userInfo
+        end
+        errmsg = body.reason
+        return {status = res.status, err = errmsg, userInfo = userInfo}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action = action, url = url, clientIP = clientIP}
+
+    local rbac_token = fetch_rbac_token(ctx)
+    if rbac_token == nil then
+        core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo = parse_rbac_token(rbac_token)
+    core.log.info("token info: ", core.json.delay_encode(tokenInfo))
+    if tokenInfo.err then
+        return 401, {message = 'invalid rbac token: parse failed'}
+    end
+
+
 
 Review comment:
   one blank line here

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373767092
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,380 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local cjson = require("cjson")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local ngx_time = ngx.time
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {type = "string"},
+        server = { type = 'string'},
+    }
+}
+
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token) 
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err=err}
+    end
+
+    if res[1] ~= token_version then
+        return { err='invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body=body, ssl_verify=false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode({method=method, uri=uri, body=body, headers=myheaders}), " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    if not conf.appid then
+        conf.appid = 'unset'
+    end
+    if not conf.server then
+        conf.server = 'http://127.0.0.1:10080'
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token()
+    local args = ngx.req.get_uri_args()
+    if args and args.rbac_token then
+        return args.rbac_token
+    end
+
+    local headers = ngx.req.get_headers()
+    if headers.Authorization then
+        return headers.Authorization
+    end
+    if headers['x-rbac-token'] then
+        return headers['x-rbac-token']
+    end
+    local cookie, err = ck:new()
+    if not cookie then
+        return nil, err
+    end
+    local val, err = cookie:get("x-rbac-token")
+    return val, err
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return cjson.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil;
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP=clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(100)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status=500, err="request to wolf-server failed, err:" .. tostring(err)}
+    elseif res.status == 200 or res.status == 401 then
+        local body, err = loadjson(res.body)
+	    if err then
+            errmsg = 'check permission failed! parse response json failed!'
+            core.log.error( "loadjson(", res.body, ") failed! err:", err)
+            return {status=res.status, err=errmsg}
+        else
+            if body.data then
+                userInfo = body.data.userInfo
+            end
+            errmsg = body.reason
+            return {status=res.status, err=errmsg, userInfo=userInfo}
+        end
+    else
+        return {status=500, err='request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action=action, url = url, clientIP = clientIP}
+
+	local rbac_token, err = fetch_rbac_token()
+	if rbac_token == nil then
+		core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
 
 Review comment:
   Done

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373767068
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,380 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local cjson = require("cjson")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local ngx_time = ngx.time
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {type = "string"},
+        server = { type = 'string'},
+    }
+}
+
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token) 
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err=err}
+    end
+
+    if res[1] ~= token_version then
+        return { err='invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body=body, ssl_verify=false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode({method=method, uri=uri, body=body, headers=myheaders}), " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    if not conf.appid then
+        conf.appid = 'unset'
+    end
+    if not conf.server then
+        conf.server = 'http://127.0.0.1:10080'
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token()
+    local args = ngx.req.get_uri_args()
+    if args and args.rbac_token then
+        return args.rbac_token
+    end
+
+    local headers = ngx.req.get_headers()
+    if headers.Authorization then
+        return headers.Authorization
+    end
+    if headers['x-rbac-token'] then
+        return headers['x-rbac-token']
+    end
+    local cookie, err = ck:new()
+    if not cookie then
+        return nil, err
+    end
+    local val, err = cookie:get("x-rbac-token")
+    return val, err
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return cjson.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil;
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP=clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(100)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status=500, err="request to wolf-server failed, err:" .. tostring(err)}
+    elseif res.status == 200 or res.status == 401 then
+        local body, err = loadjson(res.body)
+	    if err then
+            errmsg = 'check permission failed! parse response json failed!'
+            core.log.error( "loadjson(", res.body, ") failed! err:", err)
+            return {status=res.status, err=errmsg}
+        else
+            if body.data then
+                userInfo = body.data.userInfo
+            end
+            errmsg = body.reason
+            return {status=res.status, err=errmsg, userInfo=userInfo}
+        end
+    else
+        return {status=500, err='request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action=action, url = url, clientIP = clientIP}
+
+	local rbac_token, err = fetch_rbac_token()
+	if rbac_token == nil then
+		core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo =parse_rbac_token(rbac_token)
+    core.log.info("token info: ", core.json.delay_encode(tokenInfo))
+    if tokenInfo.err then
+        return 401, {message = 'invalid rbac token: parse failed'}
+    end
+
+
+    local appid = tokenInfo.appid
+    local wolf_token = tokenInfo.wolf_token
+    permItem.appid = appid
+    permItem.wolf_token = wolf_token
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return 401, {message = "Missing related consumer"}
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.error("consumer [", appid, "] not found")
+        return 401, {message = "Invalid appid in rbac token"}
+    end
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+    local server = consumer.auth_conf.server
+
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {appid=appid, action=action, url = url, clientIP = clientIP, wolf_token=wolf_token}
+
+    local res = check_url_permission(server, appid, action, url, clientIP, wolf_token)
+	core.log.info(" check_url_permission(", core.json.delay_encode(permItem), ") res: ",core.json.delay_encode(res))
+
+	local username = nil
+    local nickname = nil
+    if type(res.userInfo) == 'table' then
+        local userInfo = res.userInfo
+        core.response.set_header("X-UserId", userInfo.id)
+        core.response.set_header("X-Username", userInfo.username)
+        core.response.set_header("X-Nickname", ngx.escape_uri(userInfo.nickname) or userInfo.username)
+        ctx.userInfo = userInfo
+		username = userInfo.username
+        nickname = userInfo.nickname
+	end
+
+	if res.status == 200 then
 
 Review comment:
   res.status check is not necessary, no matter if res.status is 200 or 401,400, res.userInfo may return value

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373908197
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,386 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+local core     = require("apisix.core")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local tostring = tostring
+local rawget   = rawget
+local rawset   = rawset
+local setmetatable = setmetatable
+local type     = type
+local string   = string
+
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {
+            type = "string",
+            default = "unset"
+        },
+        server = {
+            type = "string",
+            default = "http://127.0.0.1:10080"
+        },
+    }
+}
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token)
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err = err}
+    end
+
+    if #res ~= 3 or res[1] ~= token_version then
+        return { err = 'invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body = body, ssl_verify = false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode(
+            {method = method, uri = uri, body = body, headers = myheaders}),
+            " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token(ctx)
+    if ctx.var.arg_rbac_token then
+        return ngx.unescape_uri(ctx.var.arg_rbac_token)
+    end
+
+    if ctx.var.http_authorization then
+        return ctx.var.http_authorization
+    end
+
+    if ctx.var.http_x_rbac_token then
+        return ctx.var.http_x_rbac_token
+    end
+
+    return ctx.var['cookie_x-rbac-token']
+end
+
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg
+    local userInfo
+    local res
+    local err
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP = clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status,
+                            ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(0.1)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status = 500, err = "request to wolf-server failed, err:" .. tostring(err)}
+    end
+
+    if res.status ~= 200 and res.status ~= 401 then
+        return {status = 500, err = 'request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+
+    local body, err = json.decode(res.body)
+    if err then
+        errmsg = 'check permission failed! parse response json failed!'
+        core.log.error( "json.decode(", res.body, ") failed! err:", err)
+        return {status = res.status, err = errmsg}
+    else
+        if body.data then
+            userInfo = body.data.userInfo
+        end
+        errmsg = body.reason
+        return {status = res.status, err = errmsg, userInfo = userInfo}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action = action, url = url, clientIP = clientIP}
+    core.log.info("hit wolf-rbac rewrite")
+
+    local rbac_token = fetch_rbac_token(ctx)
+    if rbac_token == nil then
+        core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo = parse_rbac_token(rbac_token)
 
 Review comment:
   Done

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373816696
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,376 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {
+            type = "string",
+            default = "unset"
+        },
+        server = {
+            type = "string",
+            default = "http://127.0.0.1:10080"
+        },
+    }
+}
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token)
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err = err}
+    end
+
+    if #res ~= 3 or res[1] ~= token_version then
+        return { err = 'invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body = body, ssl_verify = false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode(
+            {method = method, uri = uri, body = body, headers = myheaders}),
+            " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token(ctx)
+    if ctx.var.arg_rbac_token then
+        return ngx.unescape_uri(ctx.var.arg_rbac_token)
+    end
+
+    if ctx.var.http_authorization then
+        return ctx.var.http_authorization
+    end
+
+    if ctx.var.http_x_rbac_token then
+        return ctx.var.http_x_rbac_token
+    end
+
+    return ctx.var['cookie_x-rbac-token']
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return json.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP = clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(0.1)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status = 500, err = "request to wolf-server failed, err:" .. tostring(err)}
+    end
+
+    if res.status ~= 200 and res.status ~= 401 then
+        return {status = 500, err = 'request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+
+    local body, err = loadjson(res.body)
+    if err then
+        errmsg = 'check permission failed! parse response json failed!'
+        core.log.error( "loadjson(", res.body, ") failed! err:", err)
+        return {status = res.status, err = errmsg}
+    else
+        if body.data then
+            userInfo = body.data.userInfo
+        end
+        errmsg = body.reason
+        return {status = res.status, err = errmsg, userInfo = userInfo}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action = action, url = url, clientIP = clientIP}
+
+    local rbac_token = fetch_rbac_token(ctx)
+    if rbac_token == nil then
+        core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo = parse_rbac_token(rbac_token)
+    core.log.info("token info: ", core.json.delay_encode(tokenInfo))
+    if tokenInfo.err then
+        return 401, {message = 'invalid rbac token: parse failed'}
+    end
+
+
 
 Review comment:
   Done

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373908244
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,386 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+local core     = require("apisix.core")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local tostring = tostring
+local rawget   = rawget
+local rawset   = rawset
+local setmetatable = setmetatable
+local type     = type
+local string   = string
+
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {
+            type = "string",
+            default = "unset"
+        },
+        server = {
+            type = "string",
+            default = "http://127.0.0.1:10080"
+        },
+    }
+}
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token)
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err = err}
+    end
+
+    if #res ~= 3 or res[1] ~= token_version then
+        return { err = 'invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body = body, ssl_verify = false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode(
+            {method = method, uri = uri, body = body, headers = myheaders}),
+            " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token(ctx)
+    if ctx.var.arg_rbac_token then
+        return ngx.unescape_uri(ctx.var.arg_rbac_token)
+    end
+
+    if ctx.var.http_authorization then
+        return ctx.var.http_authorization
+    end
+
+    if ctx.var.http_x_rbac_token then
+        return ctx.var.http_x_rbac_token
+    end
+
+    return ctx.var['cookie_x-rbac-token']
+end
+
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg
+    local userInfo
+    local res
+    local err
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP = clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status,
+                            ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(0.1)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status = 500, err = "request to wolf-server failed, err:" .. tostring(err)}
+    end
+
+    if res.status ~= 200 and res.status ~= 401 then
+        return {status = 500, err = 'request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+
+    local body, err = json.decode(res.body)
+    if err then
+        errmsg = 'check permission failed! parse response json failed!'
+        core.log.error( "json.decode(", res.body, ") failed! err:", err)
+        return {status = res.status, err = errmsg}
+    else
+        if body.data then
+            userInfo = body.data.userInfo
+        end
+        errmsg = body.reason
+        return {status = res.status, err = errmsg, userInfo = userInfo}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action = action, url = url, clientIP = clientIP}
+    core.log.info("hit wolf-rbac rewrite")
+
+    local rbac_token = fetch_rbac_token(ctx)
+    if rbac_token == nil then
+        core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo = parse_rbac_token(rbac_token)
 
 Review comment:
   Done

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] moonming commented on issue #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
moonming commented on issue #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#issuecomment-583933112
 
 
   @iGeeky please add this plugin to `README.md` and `doc/README.md`, in order to help to find it.

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373894579
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,380 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local cjson = require("cjson")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local ngx_time = ngx.time
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {type = "string"},
+        server = { type = 'string'},
+    }
+}
+
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token) 
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err=err}
+    end
+
+    if res[1] ~= token_version then
+        return { err='invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body=body, ssl_verify=false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode({method=method, uri=uri, body=body, headers=myheaders}), " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    if not conf.appid then
+        conf.appid = 'unset'
+    end
+    if not conf.server then
+        conf.server = 'http://127.0.0.1:10080'
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token()
+    local args = ngx.req.get_uri_args()
+    if args and args.rbac_token then
+        return args.rbac_token
+    end
+
+    local headers = ngx.req.get_headers()
+    if headers.Authorization then
+        return headers.Authorization
+    end
+    if headers['x-rbac-token'] then
+        return headers['x-rbac-token']
+    end
+    local cookie, err = ck:new()
+    if not cookie then
+        return nil, err
+    end
+    local val, err = cookie:get("x-rbac-token")
+    return val, err
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return cjson.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil;
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP=clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(100)
+                end
+            end
+        end
+    end
+
+    if err then
 
 Review comment:
   Done

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373908509
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,386 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+local core     = require("apisix.core")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local tostring = tostring
+local rawget   = rawget
+local rawset   = rawset
+local setmetatable = setmetatable
+local type     = type
+local string   = string
+
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {
+            type = "string",
+            default = "unset"
+        },
+        server = {
+            type = "string",
+            default = "http://127.0.0.1:10080"
+        },
+    }
+}
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token)
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err = err}
+    end
+
+    if #res ~= 3 or res[1] ~= token_version then
+        return { err = 'invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body = body, ssl_verify = false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode(
+            {method = method, uri = uri, body = body, headers = myheaders}),
+            " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token(ctx)
+    if ctx.var.arg_rbac_token then
+        return ngx.unescape_uri(ctx.var.arg_rbac_token)
+    end
+
+    if ctx.var.http_authorization then
+        return ctx.var.http_authorization
+    end
+
+    if ctx.var.http_x_rbac_token then
+        return ctx.var.http_x_rbac_token
+    end
+
+    return ctx.var['cookie_x-rbac-token']
+end
+
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg
+    local userInfo
+    local res
+    local err
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP = clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status,
+                            ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(0.1)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status = 500, err = "request to wolf-server failed, err:" .. tostring(err)}
+    end
+
+    if res.status ~= 200 and res.status ~= 401 then
+        return {status = 500, err = 'request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+
+    local body, err = json.decode(res.body)
+    if err then
+        errmsg = 'check permission failed! parse response json failed!'
+        core.log.error( "json.decode(", res.body, ") failed! err:", err)
+        return {status = res.status, err = errmsg}
+    else
+        if body.data then
+            userInfo = body.data.userInfo
+        end
+        errmsg = body.reason
+        return {status = res.status, err = errmsg, userInfo = userInfo}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action = action, url = url, clientIP = clientIP}
+    core.log.info("hit wolf-rbac rewrite")
+
+    local rbac_token = fetch_rbac_token(ctx)
+    if rbac_token == nil then
+        core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo = parse_rbac_token(rbac_token)
+    core.log.info("token info: ", core.json.delay_encode(tokenInfo))
+    if tokenInfo.err then
+        return 401, {message = 'invalid rbac token: parse failed'}
+    end
+
+    local appid = tokenInfo.appid
+    local wolf_token = tokenInfo.wolf_token
+    permItem.appid = appid
+    permItem.wolf_token = wolf_token
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return 401, {message = "Missing related consumer"}
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.error("consumer [", appid, "] not found")
+        return 401, {message = "Invalid appid in rbac token"}
+    end
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+    local server = consumer.auth_conf.server
+
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {appid = appid, action = action, url = url, clientIP = clientIP, wolf_token = wolf_token}
+
+    local res = check_url_permission(server, appid, action, url, clientIP, wolf_token)
+    core.log.info(" check_url_permission(", core.json.delay_encode(permItem), ") res: ",core.json.delay_encode(res))
+
+    local username = nil
+    local nickname = nil
+    if type(res.userInfo) == 'table' then
+        local userInfo = res.userInfo
+        core.response.set_header("X-UserId", userInfo.id)
+        core.response.set_header("X-Username", userInfo.username)
+        core.response.set_header("X-Nickname", ngx.escape_uri(userInfo.nickname) or userInfo.username)
+        ctx.userInfo = userInfo
+        username = userInfo.username
+        nickname = userInfo.nickname
+    end
+
+    if res.status ~= 200 then
+        -- no permission.
+        core.log.error(" check_url_permission(", core.json.delay_encode(permItem),
+            ") failed, res: ",core.json.delay_encode(res))
+        return 401, {message = res.err, username = username, nickname = nickname}
+    end
+    core.log.info("wolf-rbac check permission passed")
+end
+
+local function get_args()
+    local ctx = ngx.ctx.api_ctx
+    local args, err
+    ngx.req.read_body()
+    if string.find(ctx.var.http_content_type or "","application/json", 1, true) then
+        args, err = json.decode(ngx.req.get_body_data())
+        if err then
+            core.log.error("json.decode(", ngx.req.get_body_data(), ") failed! ", err)
+        end
+    else
+        args = ngx.req.get_post_args()
+    end
+    return args
+end
+
+local function login()
+    local args = get_args()
+    if not args then
+        return core.response.exit(400, {message = "invalid request"})
+    end
+    if not args.appid then
+        return core.response.exit(400, {message = "appid is missing"})
+    end
+
+    local appid = args.appid
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return core.response.exit(500)
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.info("request appid [", appid, "] not found")
+        return core.response.exit(400, {message = "appid [" .. tostring(appid) .. "] not found"})
+    end
+
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+
+    local uri = consumer.auth_conf.server .. '/wolf/rbac/login.rest'
+    local headers = new_headers()
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local timeout = 1000 * 5
+    local request_debug = core.json.delay_encode(
 
 Review comment:
   Done

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373898548
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,386 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+local core     = require("apisix.core")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local tostring = tostring
+local rawget   = rawget
+local rawset   = rawset
+local setmetatable = setmetatable
+local type     = type
+local string   = string
+
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {
+            type = "string",
+            default = "unset"
+        },
+        server = {
+            type = "string",
+            default = "http://127.0.0.1:10080"
+        },
+    }
+}
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token)
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err = err}
+    end
+
+    if #res ~= 3 or res[1] ~= token_version then
+        return { err = 'invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body = body, ssl_verify = false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode(
+            {method = method, uri = uri, body = body, headers = myheaders}),
+            " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token(ctx)
+    if ctx.var.arg_rbac_token then
+        return ngx.unescape_uri(ctx.var.arg_rbac_token)
+    end
+
+    if ctx.var.http_authorization then
+        return ctx.var.http_authorization
+    end
+
+    if ctx.var.http_x_rbac_token then
+        return ctx.var.http_x_rbac_token
+    end
+
+    return ctx.var['cookie_x-rbac-token']
+end
+
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg
+    local userInfo
+    local res
+    local err
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP = clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status,
+                            ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(0.1)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status = 500, err = "request to wolf-server failed, err:" .. tostring(err)}
+    end
+
+    if res.status ~= 200 and res.status ~= 401 then
+        return {status = 500, err = 'request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+
+    local body, err = json.decode(res.body)
+    if err then
+        errmsg = 'check permission failed! parse response json failed!'
+        core.log.error( "json.decode(", res.body, ") failed! err:", err)
+        return {status = res.status, err = errmsg}
+    else
+        if body.data then
+            userInfo = body.data.userInfo
+        end
+        errmsg = body.reason
+        return {status = res.status, err = errmsg, userInfo = userInfo}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action = action, url = url, clientIP = clientIP}
+    core.log.info("hit wolf-rbac rewrite")
+
+    local rbac_token = fetch_rbac_token(ctx)
+    if rbac_token == nil then
+        core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo = parse_rbac_token(rbac_token)
+    core.log.info("token info: ", core.json.delay_encode(tokenInfo))
+    if tokenInfo.err then
+        return 401, {message = 'invalid rbac token: parse failed'}
+    end
+
+    local appid = tokenInfo.appid
+    local wolf_token = tokenInfo.wolf_token
+    permItem.appid = appid
+    permItem.wolf_token = wolf_token
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return 401, {message = "Missing related consumer"}
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.error("consumer [", appid, "] not found")
+        return 401, {message = "Invalid appid in rbac token"}
+    end
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+    local server = consumer.auth_conf.server
+
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {appid = appid, action = action, url = url, clientIP = clientIP, wolf_token = wolf_token}
+
+    local res = check_url_permission(server, appid, action, url, clientIP, wolf_token)
+    core.log.info(" check_url_permission(", core.json.delay_encode(permItem), ") res: ",core.json.delay_encode(res))
+
+    local username = nil
+    local nickname = nil
+    if type(res.userInfo) == 'table' then
+        local userInfo = res.userInfo
+        core.response.set_header("X-UserId", userInfo.id)
+        core.response.set_header("X-Username", userInfo.username)
+        core.response.set_header("X-Nickname", ngx.escape_uri(userInfo.nickname) or userInfo.username)
+        ctx.userInfo = userInfo
+        username = userInfo.username
+        nickname = userInfo.nickname
+    end
+
+    if res.status ~= 200 then
+        -- no permission.
+        core.log.error(" check_url_permission(", core.json.delay_encode(permItem),
+            ") failed, res: ",core.json.delay_encode(res))
 
 Review comment:
   bad indentation

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373776579
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,376 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {
+            type = "string",
+            default = "unset"
+        },
+        server = {
+            type = "string",
+            default = "http://127.0.0.1:10080"
+        },
+    }
+}
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token)
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err = err}
+    end
+
+    if #res ~= 3 or res[1] ~= token_version then
+        return { err = 'invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body = body, ssl_verify = false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode(
+            {method = method, uri = uri, body = body, headers = myheaders}),
+            " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token(ctx)
+    if ctx.var.arg_rbac_token then
+        return ngx.unescape_uri(ctx.var.arg_rbac_token)
+    end
+
+    if ctx.var.http_authorization then
+        return ctx.var.http_authorization
+    end
+
+    if ctx.var.http_x_rbac_token then
+        return ctx.var.http_x_rbac_token
+    end
+
+    return ctx.var['cookie_x-rbac-token']
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return json.decode(str) end)
 
 Review comment:
   please pay attention to `json` and `json.safe`, it is a little different. https://github.com/apache/incubator-apisix/blob/master/lua/apisix/core/json.lua#L28
   
   `local data, err = require("cjson.safe").decode(str)`
   so we do not need a `pcall` here.

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373776733
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,376 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {
+            type = "string",
+            default = "unset"
+        },
+        server = {
+            type = "string",
+            default = "http://127.0.0.1:10080"
+        },
+    }
+}
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token)
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err = err}
+    end
+
+    if #res ~= 3 or res[1] ~= token_version then
+        return { err = 'invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body = body, ssl_verify = false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode(
+            {method = method, uri = uri, body = body, headers = myheaders}),
+            " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token(ctx)
+    if ctx.var.arg_rbac_token then
+        return ngx.unescape_uri(ctx.var.arg_rbac_token)
+    end
+
+    if ctx.var.http_authorization then
+        return ctx.var.http_authorization
+    end
+
+    if ctx.var.http_x_rbac_token then
+        return ctx.var.http_x_rbac_token
+    end
+
+    return ctx.var['cookie_x-rbac-token']
+end
+
+local function loadjson(str)
+    local ok, jso = pcall(function() return json.decode(str) end)
+    if ok then
+        return jso
+    else
+        return nil, jso
+    end
+end
+
+local function check_url_permission(server, appid, action, resName, clientIP, wolf_token)
+    local retry_max = 3
+    local errmsg = nil
+    local userInfo = nil
+    local res = nil
+    local err = nil
+    local access_check_url = server .. "/wolf/rbac/access_check"
+    local headers = new_headers()
+    headers["x-rbac-token"] = wolf_token
+    headers["Content-Type"] = "application/json; charset=utf-8"
+    local args = { appID = appid, resName = resName, action = action, clientIP = clientIP}
+    local url = access_check_url .. "?" .. ngx.encode_args(args)
+    local timeout = 1000 * 10
+
+    for i = 1, retry_max do
+        -- TODO: read apisix info.
+        res, err = http_get(url, headers, timeout)
+        if err then
+            errmsg = 'check permission failed!' .. tostring(err)
+            break
+        else
+            core.log.info("check permission request:", url, ", status:", res.status, ",body:", core.json.delay_encode(res.body))
+            if res.status < 500 then
+                break
+            else
+                core.log.info("request [curl -v ", url, "] failed! status:", res.status)
+                if i < retry_max then
+                    ngx.sleep(0.1)
+                end
+            end
+        end
+    end
+
+    if err then
+        core.log.error("fail request: ", url, ", err:", err)
+        return {status = 500, err = "request to wolf-server failed, err:" .. tostring(err)}
+    end
+
+    if res.status ~= 200 and res.status ~= 401 then
+        return {status = 500, err = 'request to wolf-server failed, status:' .. tostring(res.status)}
+    end
+
+    local body, err = loadjson(res.body)
+    if err then
+        errmsg = 'check permission failed! parse response json failed!'
+        core.log.error( "loadjson(", res.body, ") failed! err:", err)
+        return {status = res.status, err = errmsg}
+    else
+        if body.data then
+            userInfo = body.data.userInfo
+        end
+        errmsg = body.reason
+        return {status = res.status, err = errmsg, userInfo = userInfo}
+    end
+end
+
+
+function _M.rewrite(conf, ctx)
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {action = action, url = url, clientIP = clientIP}
+
+    local rbac_token = fetch_rbac_token(ctx)
+    if rbac_token == nil then
+        core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!")
+        return 401, {message = "Missing rbac token in request"}
+    end
+
+    local tokenInfo = parse_rbac_token(rbac_token)
+    core.log.info("token info: ", core.json.delay_encode(tokenInfo))
+    if tokenInfo.err then
+        return 401, {message = 'invalid rbac token: parse failed'}
+    end
+
+
+    local appid = tokenInfo.appid
+    local wolf_token = tokenInfo.wolf_token
+    permItem.appid = appid
+    permItem.wolf_token = wolf_token
+
+    local consumer_conf = consumer.plugin(plugin_name)
+    if not consumer_conf then
+        return 401, {message = "Missing related consumer"}
+    end
+
+    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
+            consumer_conf.conf_version,
+            create_consume_cache, consumer_conf)
+
+    core.log.info("------ consumers: ", core.json.delay_encode(consumers))
+    local consumer = consumers[appid]
+    if not consumer then
+        core.log.error("consumer [", appid, "] not found")
+        return 401, {message = "Invalid appid in rbac token"}
+    end
+    core.log.info("consumer: ", core.json.delay_encode(consumer))
+    local server = consumer.auth_conf.server
+
+    local url = ctx.var.uri
+    local action = ctx.var.request_method
+    local clientIP = core.request.get_ip(ctx)
+    local permItem = {appid = appid, action = action, url = url, clientIP = clientIP, wolf_token = wolf_token}
+
+    local res = check_url_permission(server, appid, action, url, clientIP, wolf_token)
+    core.log.info(" check_url_permission(", core.json.delay_encode(permItem), ") res: ",core.json.delay_encode(res))
+
+    local username = nil
+    local nickname = nil
+    if type(res.userInfo) == 'table' then
+        local userInfo = res.userInfo
+        core.response.set_header("X-UserId", userInfo.id)
+        core.response.set_header("X-Username", userInfo.username)
+        core.response.set_header("X-Nickname", ngx.escape_uri(userInfo.nickname) or userInfo.username)
+        ctx.userInfo = userInfo
+        username = userInfo.username
+        nickname = userInfo.nickname
+    end
+
+    if res.status == 200 then
+        ---
+    else
+        -- no permission.
+        core.log.error(" check_url_permission(", core.json.delay_encode(permItem), ") failed, res: ",core.json.delay_encode(res))
+        return 401, {message = res.err, username = username, nickname = nickname}
+    end
+    core.log.info("hit wolf-rbac rewrite")
 
 Review comment:
   move this line before https://github.com/apache/incubator-apisix/pull/1095/files#diff-0d1c836712de65dc51f6498601f35938R216 is better.

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin

Posted by GitBox <gi...@apache.org>.
iGeeky commented on a change in pull request #1095: feature: Add wolf rbac plugin
URL: https://github.com/apache/incubator-apisix/pull/1095#discussion_r373767094
 
 

 ##########
 File path: lua/apisix/plugins/wolf-rbac.lua
 ##########
 @@ -0,0 +1,380 @@
+
+local core     = require("apisix.core")
+local ck       = require("resty.cookie")
+local consumer = require("apisix.consumer")
+local json     = require("apisix.core.json")
+local ngx_re = require("ngx.re")
+local cjson = require("cjson")
+local http     = require("resty.http")
+local ipairs   = ipairs
+local ngx      = ngx
+local ngx_time = ngx.time
+local plugin_name = "wolf-rbac"
+
+
+local schema = {
+    type = "object",
+    properties = {
+        appid = {type = "string"},
+        server = { type = 'string'},
+    }
+}
+
+
+local _M = {
+    version = 0.1,
+    priority = 2555,
+    type = 'auth',
+    name = plugin_name,
+    schema = schema,
+}
+
+
+local create_consume_cache
+do
+    local consumer_ids = {}
+
+    function create_consume_cache(consumers)
+        core.table.clear(consumer_ids)
+
+        for _, consumer in ipairs(consumers.nodes) do
+            core.log.info("consumer node: ", core.json.delay_encode(consumer))
+            consumer_ids[consumer.auth_conf.appid] = consumer
+        end
+
+        return consumer_ids
+    end
+
+end -- do
+
+local token_version = 'V1'
+local function create_rbac_token(appid, wolf_token)
+    return token_version .. "#" .. appid .. "#" .. wolf_token
+end
+
+local function parse_rbac_token(rbac_token) 
+    local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3)
+    if not res then
+        return { err=err}
+    end
+
+    if res[1] ~= token_version then
+        return { err='invalid rbac token: version'}
+    end
+    local appid = res[2]
+    local wolf_token = res[3]
+
+    return {appid = appid, wolf_token = wolf_token}
+end
+
+local function new_headers()
+    local t = {}
+    local lt = {}
+    local _mt = {
+        __index = function(t, k)
+            return rawget(lt, string.lower(k))
+        end,
+        __newindex = function(t, k, v)
+            rawset(t, k, v)
+            rawset(lt, string.lower(k), v)
+        end,
+     }
+    return setmetatable(t, _mt)
+end
+
+-- timeout in ms
+local function http_req(method, uri, body, myheaders, timeout)
+    if myheaders == nil then myheaders = new_headers() end
+
+    local httpc = http.new()
+    if timeout then
+        httpc:set_timeout(timeout)
+    end
+
+    local params = {method = method, headers = myheaders, body=body, ssl_verify=false}
+    local res, err = httpc:request_uri(uri, params)
+    if err then
+        core.log.error("FAIL REQUEST [ ",core.json.delay_encode({method=method, uri=uri, body=body, headers=myheaders}), " ] failed! res is nil, err:", err)
+        return nil, err
+    end
+
+    return res
+end
+
+local function http_get(uri, myheaders, timeout)
+    return http_req("GET", uri, nil, myheaders, timeout)
+end
+
+local function http_post(uri, body, myheaders, timeout)
+    return http_req("POST", uri, body, myheaders, timeout)
+end
+
+local function http_put(uri,  body, myheaders, timeout)
+    return http_req("PUT", uri, body, myheaders, timeout)
+end
+
+function _M.check_schema(conf)
+    core.log.info("input conf: ", core.json.delay_encode(conf))
+
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+
+    if not conf.appid then
+        conf.appid = 'unset'
+    end
+    if not conf.server then
+        conf.server = 'http://127.0.0.1:10080'
+    end
+
+    return true
+end
+
+
+local function fetch_rbac_token()
+    local args = ngx.req.get_uri_args()
 
 Review comment:
   Done

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services