Updated subscription support and added Rest intfc
diff --git a/api-gateway-config/conf.d/management_apis.conf b/api-gateway-config/conf.d/management_apis.conf
index 783575a..ce3feda 100644
--- a/api-gateway-config/conf.d/management_apis.conf
+++ b/api-gateway-config/conf.d/management_apis.conf
@@ -49,6 +49,22 @@
}
}
+ location /subscriptions {
+ access_by_lua_block {
+ mgmt = require("management")
+ requestMethod = ngx.req.get_method()
+ if requestMethod == "PUT" then
+ mgmt.addSubscription()
+ elseif requestMethod == "DELETE" then
+ mgmt.deleteSubscription()
+ else
+ ngx.status = 400
+ ngx.say("Invalid verb")
+ end
+
+ }
+ }
+
location /subscribe {
access_by_lua_block {
mgmt = require("management")
diff --git a/api-gateway-config/scripts/lua/lib/redis.lua b/api-gateway-config/scripts/lua/lib/redis.lua
index 1d826c8..425a3dc 100644
--- a/api-gateway-config/scripts/lua/lib/redis.lua
+++ b/api-gateway-config/scripts/lua/lib/redis.lua
@@ -191,6 +191,32 @@
end
end
+--- Create/update subscription/apikey in redis
+-- @param red
+-- @param key
+-- @param ngx
+function _M.createSubscription(red, key, ngx)
+ -- Add/update a subscription key to redis
+ local ok, err = red:set (key, "")
+ if not ok then
+ ngx.status = 500
+ ngx.say(utils.concatStrings({"Failed adding subscription to redis: ", err}))
+ ngx.exit(ngx.status)
+ end
+end
+
+--- Delete subscription/apikey int redis
+-- @param red
+-- @param key
+-- @param ngx
+function _M.deleteSubscription(red, key, ngx)
+ local ok, err = red:del(key, "subscriptions")
+ if not ok then
+ ngx.status = 500
+ ngx.say("Error deleting subscription: ", err)
+ ngx.exit(ngx.status)
+ end
+end
--- Subscribe to redis
-- @param redisSubClient the redis client that is listening for the redis key changes
diff --git a/api-gateway-config/scripts/lua/management.lua b/api-gateway-config/scripts/lua/management.lua
index 52a862f..c35561a 100644
--- a/api-gateway-config/scripts/lua/management.lua
+++ b/api-gateway-config/scripts/lua/management.lua
@@ -86,7 +86,10 @@
local backendMethod = decoded and decoded.backendMethod or gatewayMethod
local requestURI = string.gsub(ngx.var.request_uri, "?.*", "")
- local redisKey, namespace, gatewayPath = parseRequestURI(requestURI)
+ local list = parseRequestURI(requestURI)
+ local namespace = list[2]
+ local gatewayPath = list[3]
+ local redisKey = utils.concatStrings({list[1], ":", namespace, ":", ngx.unescape_uri(gatewayPath)})
-- Open connection to redis or use one from connection pool
local red = redis.init(REDIS_HOST, REDIS_PORT, REDIS_PASS, 1000, ngx)
@@ -118,7 +121,10 @@
--
function _M.getRoute()
local requestURI = string.gsub(ngx.var.request_uri, "?.*", "")
- local redisKey, namespace, gatewayPath = parseRequestURI(requestURI)
+ local list = parseRequestURI(requestURI)
+ local namespace = list[2]
+ local gatewayPath = list[3]
+ local redisKey = utils.concatStrings({list[1], ":", namespace, ":", ngx.unescape_uri(gatewayPath)})
-- Initialize and connect to redis
local red = redis.init(REDIS_HOST, REDIS_PORT, REDIS_PASS, 1000, ngx)
@@ -150,7 +156,10 @@
--
function _M.deleteRoute()
local requestURI = string.gsub(ngx.var.request_uri, "?.*", "")
- local redisKey, namespace, gatewayPath = parseRequestURI(requestURI)
+ local list = parseRequestURI(requestURI)
+ local namespace = list[2]
+ local gatewayPath = list[3]
+ local redisKey = utils.concatStrings({list[1], ":", namespace, ":", ngx.unescape_uri(gatewayPath)})
-- Initialize and connect to redis
local red = redis.init(REDIS_HOST, REDIS_PORT, REDIS_PASS, 1000, ngx)
@@ -198,36 +207,82 @@
ngx.exit(ngx.status)
end
+--- Add an apikey/subscription to redis
+-- PUT http://0.0.0.0:9000/subscriptions/<namespace>/<url-encoded-route>/<key>
+-- where list[1] = prefix, list[2] = namespace, list[3] = gatewayPath, list[4] = key
+------ or
+-- PUT http://0.0.0.0:9000/subscriptions/<namespace>/<key>
+-- where list[1] = prefix, list[2] = namespace, list[3] = key
+function _M.addSubscription()
+ local requestURI = string.gsub(ngx.var.request_uri, "?.*", "")
+ local list = parseRequestURI(requestURI)
+ local redisKey
+ if list[4] then
+ redisKey = utils.concatStrings({list[1], ":", list[2], ":", ngx.unescape_uri(list[3]), ":", list[4]})
+ else
+ redisKey = utils.concatStrings({list[1], ":", list[2], ":", list[3]})
+ end
+
+ -- Open connection to redis or use one from connection pool
+ local red = redis.init(REDIS_HOST, REDIS_PORT, REDIS_PASS, 1000, ngx)
+
+ redis.createSubscription(red, redisKey, ngx)
+
+ -- Add current redis connection in the ngx_lua cosocket connection pool
+ redis.close(red, ngx)
+
+ ngx.status = 200
+ ngx.say("Subscription created.")
+ ngx.exit(ngx.status)
+end
+
+--- Delete apikey/subscription from redis
+-- DELETE http://0.0.0.0:9000/subscriptions/<namespace>/<url-encoded-route>/<key>
+-- where list[1] = prefix, list[2] = namespace, list[3] = gatewayPath, list[4] = key
+------ or
+-- DELETE http://0.0.0.0:9000/subscriptions/<namespace>/<key>
+-- where list[1] = prefix, list[2] = namespace, list[3] = key
+function _M.deleteSubscription()
+ local requestURI = string.gsub(ngx.var.request_uri, "?.*", "")
+ local list = parseRequestURI(requestURI)
+ local redisKey
+ if list[4] then
+ redisKey = utils.concatStrings({list[1], ":", list[2], ":", ngx.unescape_uri(list[3]), ":", list[4]})
+ else
+ redisKey = utils.concatStrings({list[1], ":", list[2], ":", list[3]})
+ end
+
+ -- Initialize and connect to redis
+ local red = redis.init(REDIS_HOST, REDIS_PORT, REDIS_PASS, 1000, ngx)
+
+ -- Return if subscription doesn't exist
+ redis.deleteSubscription(red, redisKey, ngx)
+
+ -- Add current redis connection in the ngx_lua cosocket connection pool
+ redis.close(red, ngx)
+
+ ngx.status = 200
+ ngx.say("Subscription deleted.")
+ ngx.exit(ngx.status)
+end
+
--- Parse the request uri to get the redisKey, namespace, and gatewayPath
-- @param requestURI
-- @return redisKey, namespace, gatewayPath
function parseRequestURI(requestURI)
- local index = 0
- local prefix = nil
- local namespace = nil
- local gatewayPath = nil
- for word in string.gmatch(requestURI, '([^/]+)') do
- -- word is "routes"
- if index == 0 then
- prefix = word
- -- word is the namespace
- elseif index == 1 then
- namespace = word
- -- the rest is the path
- elseif index == 2 then
- gatewayPath = word
- end
- index = index + 1
+ local list = {}
+ for i in string.gmatch(requestURI, '([^/]+)') do
+ list[#list + 1] = i
end
- if not namespace or not gatewayPath or index > 3 then
+ if not list[1] or not list[2] then
ngx.status = 400
ngx.say("Error: Request path should be \"/routes/<namespace>/<url-encoded-route>\"")
ngx.exit(ngx.status)
end
- local redisKey = utils.concatStrings({prefix, ":", namespace, ":", ngx.unescape_uri(gatewayPath)})
- return redisKey, namespace, gatewayPath
+
+ return list --prefix, namespace, gatewayPath, apiKey
end
--- Convert JSON body to Lua table using the cjson module
diff --git a/api-gateway-config/scripts/lua/policies/security.lua b/api-gateway-config/scripts/lua/policies/security.lua
index 68bd183..38f4a2c 100644
--- a/api-gateway-config/scripts/lua/policies/security.lua
+++ b/api-gateway-config/scripts/lua/policies/security.lua
@@ -32,30 +32,34 @@
local _M = {}
-function validateAPIKey(namespace ,apiKey)
+function validateAPIKey(namespace, gatewayPath, apiKey)
-- Open connection to redis or use one from connection pool
local red = redis.init(REDIS_HOST, REDIS_PORT, REDIS_PASS, 1000, ngx)
- local k = utils.concatStrings({'subscriptions:', tostring(namespace), ':', tostring(apiKey)})
+ local k = utils.concatStrings({'subscriptions:', tostring(namespace), ':', tostring(gatewayPath), ':', tostring(apiKey)})
local exists, err = red:exists(k)
-
+ if exists == 0 then
+ k = utils.concatStrings({'subscriptions:', tostring(namespace), ':', tostring(apiKey)})
+ exists, err = red:exists(k)
+ end
return exists == 1
end
function processAPIKey(h)
local namespace = ngx.var.namespace
+ local gatewayPath = ngx.var.gatewayPath
local apiKey = ngx.var[h]
if not apiKey then
- logger.err('No x-api-key passed. Sending 401')
+ logger.err('No api-key passed. Sending 401')
ngx.exit(401)
end
- local ok = validateAPIKey(namespace, apiKey)
+ local ok = validateAPIKey(namespace, gatewayPath, apiKey)
if not ok then
- logger.err('x-api-key does not match. Sending 401')
+ logger.err('api-key does not match. Sending 401')
ngx.exit(401)
end
end
_M.processAPIKey = processAPIKey
-return _M
\ No newline at end of file
+return _M