You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwhisk.apache.org by mh...@apache.org on 2020/08/03 15:28:31 UTC

[openwhisk-apigateway] branch scope-fixes created (now e83218c)

This is an automated email from the ASF dual-hosted git repository.

mhamann pushed a change to branch scope-fixes
in repository https://gitbox.apache.org/repos/asf/openwhisk-apigateway.git.


      at e83218c  fix(core): upstream openresty fixes; lua global scope pollution

This branch includes the following new commits:

     new e83218c  fix(core): upstream openresty fixes; lua global scope pollution

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[openwhisk-apigateway] 01/01: fix(core): upstream openresty fixes; lua global scope pollution

Posted by mh...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mhamann pushed a commit to branch scope-fixes
in repository https://gitbox.apache.org/repos/asf/openwhisk-apigateway.git

commit e83218ce6d63837bdf1cd5655610e830535814bc
Author: Matt Hamann <mh...@us.ibm.com>
AuthorDate: Mon Aug 3 11:28:14 2020 -0400

    fix(core): upstream openresty fixes; lua global scope pollution
---
 .dockerignore                                   |   1 +
 Dockerfile                                      |   4 +-
 scripts/lua/lib/dataStore.lua                   |   4 +-
 scripts/lua/lib/redis.lua                       | 330 ++++++++++++------------
 scripts/lua/lib/request.lua                     |   4 +-
 scripts/lua/lib/utils.lua                       |   2 +-
 scripts/lua/management/lib/apis.lua             |  54 ++--
 scripts/lua/management/lib/swagger.lua          | 212 +++++++--------
 scripts/lua/management/lib/tenants.lua          | 103 ++++----
 scripts/lua/management/lib/validation.lua       | 154 +++++------
 scripts/lua/management/routes/apis.lua          |  54 ++--
 scripts/lua/management/routes/subscriptions.lua | 164 ++++++------
 scripts/lua/management/routes/tenants.lua       |  62 ++---
 scripts/lua/oauth/facebook.lua                  |  37 +--
 scripts/lua/oauth/google.lua                    |   2 +-
 scripts/lua/policies/backendRouting.lua         |  16 +-
 scripts/lua/policies/mapping.lua                | 176 ++++++-------
 scripts/lua/policies/rateLimit.lua              |   2 +-
 scripts/lua/policies/security.lua               |   2 +-
 scripts/lua/policies/security/apiKey.lua        |  30 +--
 scripts/lua/policies/security/clientSecret.lua  |  99 ++++---
 scripts/lua/policies/security/oauth2.lua        |  53 ++--
 scripts/lua/routing.lua                         |  83 +++---
 tools/lua-releng                                | 104 ++++++++
 24 files changed, 919 insertions(+), 833 deletions(-)

diff --git a/.dockerignore b/.dockerignore
index 1b5d582..b6643df 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -5,3 +5,4 @@ CONTRIBUTING.md
 Dockerfile
 Makefile
 README.md
+tools/
diff --git a/Dockerfile b/Dockerfile
index 30a35ce..ce8d088 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -17,7 +17,7 @@
 
 # apigateway
 #
-# VERSION               1.15.8.3
+# VERSION               1.17.8.2
 #
 # From https://hub.docker.com/_/alpine/
 #
@@ -37,7 +37,7 @@ RUN apk update && \
     && rm -rf /var/cache/apk/*
 
 # openresty build
-ENV OPENRESTY_VERSION=1.15.8.3 \
+ENV OPENRESTY_VERSION=1.17.8.2 \
     PCRE_VERSION=8.37 \
     TEST_NGINX_VERSION=0.24 \
     OPM_VERSION=0.0.5 \
diff --git a/scripts/lua/lib/dataStore.lua b/scripts/lua/lib/dataStore.lua
index 57a86cc..453576a 100644
--- a/scripts/lua/lib/dataStore.lua
+++ b/scripts/lua/lib/dataStore.lua
@@ -34,7 +34,7 @@ end
 
 function DataStore:setSnapshotId(tenant)
   self.snapshotId = self.impl.getSnapshotId(self.ds, tenant)
-  self:lockSnapshot(snapshotId)
+  self:lockSnapshot(self.snapshotId)
   if self.snapshotId == ngx.null then
     self.snapshotId = nil
   end
@@ -159,7 +159,7 @@ end
 
 function DataStore:getSubscriptions(artifactId, tenantId)
   self:singleInit()
-  return self.impl.deleteSubscription(self.ds, key, self.snapshotId)
+  return self.impl.getSubscriptions(self.ds, artifactId, tenantId, self.snapshotId)
 end
 
 function DataStore:healthCheck()
diff --git a/scripts/lua/lib/redis.lua b/scripts/lua/lib/redis.lua
index bd6701f..5c4da83 100644
--- a/scripts/lua/lib/redis.lua
+++ b/scripts/lua/lib/redis.lua
@@ -102,6 +102,169 @@ function _M.close(red)
   end
 end
 
+-- LRU Caching methods
+
+--- Call function with retry logic
+-- @param func function to call
+-- @param args arguments to pass in to function
+local function call(func, args)
+  local res, err = func(unpack(args))
+  local retryCount = REDIS_RETRY_COUNT
+  while not res and retryCount > 0 do
+    res, err = func(unpack(args))
+    retryCount = retryCount - 1
+  end
+  return res, err
+end
+
+local function exists(red, key, snapshotId)
+  if snapshotId ~= nil then
+    key = utils.concatStrings({'snapshots:', snapshotId, ':', key})
+  end
+  if CACHING_ENABLED then
+    local cached = c:get(key)
+    if cached ~= nil then
+      return 1
+    end
+  -- if it isn't in the cache, try and load it in there
+    if red == nil then
+      red = _M.init()
+    end
+    local result = red:get(key)
+    if result ~= ngx.null then
+      c:set(key, result, CACHE_TTL)
+      return 1, red
+    end
+    return 0
+  else
+    if red == nil then
+      red = _M.init()
+    end
+    return call(red.exists, {red, key}), red
+  end
+end
+
+local function get(red, key)
+  if CACHING_ENABLED then
+    local cached, stale = c:get(key)
+    if cached ~= nil then
+      return cached
+    else
+      if red == nil then
+        red = _M.init()
+      end
+      local result = red:get(key)
+      c:set(key, result, CACHE_TTL)
+      return result, red
+    end
+  else
+    if red == nil then
+      red = _M.init()
+    end
+    return call(red.get, {red, key})
+  end
+end
+
+local function hget(red, key, id)
+  if CACHING_ENABLED then
+    local cachedmap, stale = c:get(key)
+    if cachedmap ~= nil then
+      local cached = cachedmap:get(id)
+      if cached ~= nil then
+         return cached
+      else
+        if red == nil then
+          red = _M.init()
+        end
+        local result = red:hget(key, id)
+        cachedmap:set(id, result, CACHE_TTL)
+        c:set(key, cachedmap, CACHE_TTL)
+        return result, red
+      end
+    else
+      if red == nil then
+        red = _M.init()
+      end
+      local result = red:hget(key, id)
+      local newcache = lrucache.new(CACHE_SIZE)
+      newcache:set(id, result, CACHE_TTL)
+      c:set(key, newcache, CACHE_TTL)
+      return result, red
+    end
+  else
+    if red == nil then
+      red = _M.init()
+    end
+    return call(red.hget, {red, key, id}), red
+  end
+end
+
+local function hgetall(red, key)
+  return call(red.hgetall, {red, key})
+end
+
+local function hset(red, key, id, value)
+  if CACHING_ENABLED then
+    local cachedmap = c:get(key)
+    if cachedmap ~= nil then
+      cachedmap:set(id, value, CACHE_TTL)
+      c:set(key, cachedmap, CACHE_TTL)
+      return red:hset(key, id, value)
+    else
+      local val = lrucache.new(CACHE_SIZE)
+      val:set(id, value, CACHE_TTL)
+      c:set(key, val, CACHE_TTL)
+    end
+  end
+  return call(red.hset, {red, key, id, value})
+end
+
+local function expire(red, key, ttl)
+  if CACHING_ENABLED then
+    local cached = c:get(key)
+    local value = ''
+    if cached ~= nil then -- just put it back in the cache with a ttl
+      value = cached
+    end
+    c:set(key, value, ttl)
+  end
+  return call(red.expire, {red, ttl})
+end
+
+local function del(red, key)
+  if CACHING_ENABLED then
+    c:delete(key)
+  end
+  return call(red.del, {red, key})
+end
+
+local function hdel(red, key, id)
+  if CACHING_ENABLED then
+    local cachecontents = c:get(key)
+    if cachecontents ~= nil then
+      cachecontents:del(id)
+      c:set(key, cachecontents, CACHE_TTL)
+    end
+  end
+  return call(red.hdel, {red, key, id})
+end
+
+local function set(red, key, value)
+  return call(red.set, {red, key, value})
+end
+
+local function smembers(red, key)
+  return call(red.smembers, {red, key})
+end
+
+local function srem(red, key, id)
+  return call(red.srem, {red, key, id})
+end
+
+local function sadd(red, key, id)
+  return call(red.sadd, {red, key, id})
+end
+
 ---------------------------
 ----------- APIs ----------
 ---------------------------
@@ -597,8 +760,8 @@ function _M.optimizeLookup(red, tenant, resourceKey, pathStr)
   if get(red, startingString) == nil then
     set(red, startingString, '')
   end
-  path = {}
-  key = {}
+  local path = {}
+  local key = {}
   for p in string.gmatch(pathStr, '[^/]*') do
     if p ~= '' then
       table.insert(path, p)
@@ -632,169 +795,6 @@ function _M.lockSnapshot(red, snapshotId)
   red:expire(utils.concatStrings({'lock:snapshots:', snapshotId}), 60)
 end
 
--- LRU Caching methods
-
-function exists(red, key, snapshotId)
-  if snapshotId ~= nil then
-    key = utils.concatStrings({'snapshots:', snapshotId, ':', key})
-  end
-  if CACHING_ENABLED then
-    local cached = c:get(key)
-    if cached ~= nil then
-      return 1
-    end
-  -- if it isn't in the cache, try and load it in there
-    if red == nil then
-      red = _M.init()
-    end
-    local result = red:get(key)
-    if result ~= ngx.null then
-      c:set(key, result, CACHE_TTL)
-      return 1, red
-    end
-    return 0
-  else
-    if red == nil then
-      red = _M.init()
-    end
-    return call(red.exists, {red, key}), red
-  end
-end
-
-function get(red, key)
-  if CACHING_ENABLED then
-    local cached, stale = c:get(key)
-    if cached ~= nil then
-      return cached
-    else
-      if red == nil then
-        red = _M.init()
-      end
-      local result = red:get(key)
-      c:set(key, result, CACHE_TTL)
-      return result, red
-    end
-  else
-    if red == nil then
-      red = _M.init()
-    end
-    return call(red.get, {red, key})
-  end
-end
-
-function hget(red, key, id)
-  if CACHING_ENABLED then
-    local cachedmap, stale = c:get(key)
-    if cachedmap ~= nil then
-      local cached = cachedmap:get(id)
-      if cached ~= nil then
-         return cached
-      else
-        if red == nil then
-          red = _M.init()
-        end
-        local result = red:hget(key, id)
-        cachedmap:set(id, result, CACHE_TTL)
-        c:set(key, cachedmap, CACHE_TTL)
-        return result, red
-      end
-    else
-      if red == nil then
-        red = _M.init()
-      end
-      local result = red:hget(key, id)
-      local newcache = lrucache.new(CACHE_SIZE)
-      newcache:set(id, result, CACHE_TTL)
-      c:set(key, newcache, CACHE_TTL)
-      return result, red
-    end
-  else
-    if red == nil then
-      red = _M.init()
-    end
-    return call(red.hget, {red, key, id}), red
-  end
-end
-
-function hgetall(red, key)
-  return call(red.hgetall, {red, key})
-end
-
-function hset(red, key, id, value)
-  if CACHING_ENABLED then
-    local cachedmap = c:get(key)
-    if cachedmap ~= nil then
-      cachedmap:set(id, value, CACHE_TTL)
-      c:set(key, cachedmap, CACHE_TTL)
-      return red:hset(key, id, value)
-    else
-      local val = lrucache.new(CACHE_SIZE)
-      val:set(id, value, CACHE_TTL)
-      c:set(key, val, CACHE_TTL)
-    end
-  end
-  return call(red.hset, {red, key, id, value})
-end
-
-function expire(red, key, ttl)
-  if CACHING_ENABLED then
-    local cached = c:get(key)
-    local value = ''
-    if cached ~= nil then -- just put it back in the cache with a ttl
-      value = cached
-    end
-    c:set(key, value, ttl)
-  end
-  return call(red.expire, {red, ttl})
-end
-
-function del(red, key)
-  if CACHING_ENABLED then
-    c:delete(key)
-  end
-  return call(red.del, {red, key})
-end
-
-function hdel(red, key, id)
-  if CACHING_ENABLED then
-    local cachecontents = c:get(key)
-    if cachecontents ~= nil then
-      cachecontents:del(id)
-      c:set(key, cachecontents, CACHE_TTL)
-    end
-  end
-  return call(red.hdel, {red, key, id})
-end
-
-function set(red, key, value)
-  return call(red.set, {red, key, value})
-end
-
-function smembers(red, key)
-  return call(red.smembers, {red, key})
-end
-
-function srem(red, key, id)
-  return call(red.srem, {red, key, id})
-end
-
-function sadd(red, key, id)
-  return call(red.sadd, {red, key, id})
-end
-
---- Call function with retry logic
--- @param func function to call
--- @param args arguments to pass in to function
-function call(func, args)
-  local res, err = func(unpack(args))
-  local retryCount = REDIS_RETRY_COUNT
-  while not res and retryCount > 0 do
-    res, err = func(unpack(args))
-    retryCount = retryCount - 1
-  end
-  return res, err
-end
-
 _M.get = get
 _M.set = set
 _M.exists = exists
diff --git a/scripts/lua/lib/request.lua b/scripts/lua/lib/request.lua
index faa2caa..38f6eab 100644
--- a/scripts/lua/lib/request.lua
+++ b/scripts/lua/lib/request.lua
@@ -27,7 +27,7 @@ local _Request = {}
 --- Error function to call when request is malformed
 -- @param code error code
 -- @param msg error message
-function err(code, msg)
+local function err(code, msg)
   ngx.header.content_type = "application/json; charset=utf-8"
   ngx.status = code
   local errObj = cjson.encode({
@@ -41,7 +41,7 @@ end
 --- Function to call when request is successful
 -- @param code status code
 -- @param obj JSON encoded object to return
-function success(code, obj)
+local function success(code, obj)
   ngx.status = code
   if obj ~= nil then
     ngx.say(obj)
diff --git a/scripts/lua/lib/utils.lua b/scripts/lua/lib/utils.lua
index e9c2977..4c58f83 100644
--- a/scripts/lua/lib/utils.lua
+++ b/scripts/lua/lib/utils.lua
@@ -67,7 +67,7 @@ end
 -- @return concatenated string of (?<path_pathParam>(\\w+))
 function _Utils.convertTemplatedPathParam(m)
   local x = m:gsub("{", ""):gsub("}", "")
-  return concatStrings({"(?<path_" , x , ">([a-zA-Z0-9\\-\\s\\_\\%]*))"})
+  return _Utils.concatStrings({"(?<path_" , x , ">([a-zA-Z0-9\\-\\s\\_\\%]*))"})
 end
 
 --- Generate random uuid
diff --git a/scripts/lua/management/lib/apis.lua b/scripts/lua/management/lib/apis.lua
index 04161f2..b2efbd3 100644
--- a/scripts/lua/management/lib/apis.lua
+++ b/scripts/lua/management/lib/apis.lua
@@ -32,6 +32,33 @@ GATEWAY_URL = (GATEWAY_URL ~= nil and GATEWAY_URL ~= '') and GATEWAY_URL or util
 
 local _M = {}
 
+--- Filter APIs based on query parameters
+-- @param apis list of apis
+-- @param queryParams query parameters to filter tenants
+local function filterAPIs(apis, queryParams)
+  local basePath = queryParams['filter[where][basePath]']
+  basePath = basePath == nil and queryParams['basePath'] or basePath
+  local name = queryParams['filter[where][name]']
+  name = name == nil and queryParams['title'] or name
+  -- missing or invalid query parameters
+  if (basePath == nil and name == nil) then
+    return nil
+  end
+  -- filter tenants
+  local apiList = {}
+  for k, v in pairs(apis) do
+    if k%2 == 0 then
+      local api = cjson.decode(v)
+      if (basePath ~= nil and name == nil and api.basePath == basePath) or
+          (name ~= nil and basePath == nil and api.name == name) or
+          (basePath ~= nil and name ~= nil and api.basePath == basePath and api.name == name) then
+        apiList[#apiList+1] = api
+      end
+    end
+  end
+  return apiList
+end
+
 --- Get all APIs in redis
 -- @param ds dataStore.client
 -- @param queryParams object containing optional query parameters
@@ -137,31 +164,4 @@ function _M.deleteAPI(dataStore, id)
   return {}
 end
 
---- Filter APIs based on query parameters
--- @param apis list of apis
--- @param queryParams query parameters to filter tenants
-function filterAPIs(apis, queryParams)
-  local basePath = queryParams['filter[where][basePath]']
-  basePath = basePath == nil and queryParams['basePath'] or basePath
-  local name = queryParams['filter[where][name]']
-  name = name == nil and queryParams['title'] or name
-  -- missing or invalid query parameters
-  if (basePath == nil and name == nil) then
-    return nil
-  end
-  -- filter tenants
-  local apiList = {}
-  for k, v in pairs(apis) do
-    if k%2 == 0 then
-      local api = cjson.decode(v)
-      if (basePath ~= nil and name == nil and api.basePath == basePath) or
-          (name ~= nil and basePath == nil and api.name == name) or
-          (basePath ~= nil and name ~= nil and api.basePath == basePath and api.name == name) then
-        apiList[#apiList+1] = api
-      end
-    end
-  end
-  return apiList
-end
-
 return _M
diff --git a/scripts/lua/management/lib/swagger.lua b/scripts/lua/management/lib/swagger.lua
index d70c08c..b02397e 100644
--- a/scripts/lua/management/lib/swagger.lua
+++ b/scripts/lua/management/lib/swagger.lua
@@ -18,63 +18,51 @@
 --- @module swagger
 -- Module for parsing swagger file
 
-local _M = {}
 local utils = require "lib/utils"
 
--- Convert passed-in swagger body to valid lua table
--- @param swagger swagger file to parse
-function _M.parseSwagger(swagger)
-  local backends = parseBackends(swagger)
-  local policies = parseSwaggerPolicies(swagger)
-  local security = parseSecurity(swagger)
-  local corsObj = parseCors(swagger)
-  local decoded = {
-    name = swagger.info.title,
-    basePath = swagger.basePath,
-    resources = {}
-  }
-  for path, verbObj in pairs(swagger.paths) do
-    decoded.resources[path] = { operations = {} }
-    decoded.resources[path].cors = corsObj
-    for verb, value in pairs(verbObj) do
-      decoded.resources[path].operations[verb] = {}
-      local verbObj = decoded.resources[path].operations[verb]
-      verbObj.policies = utils.deepCloneTable(policies) or {}
-      verbObj.security = security
-      if backends ~= nil then
-        local backend = (backends["all"] ~= nil) and backends["all"] or backends[value.operationId]
-        verbObj.backendUrl = backend.backendUrl
-        verbObj.backendMethod = (backend.backendMethod == 'keep') and verb or backend.backendMethod
-        if backend.policy ~= nil then
-          local globalReqMappingPolicy = nil;
-          for _, policy in pairs(verbObj.policies) do
-            if policy.type == 'reqMapping' then
-              globalReqMappingPolicy = policy;
-            end
-          end
-          if globalReqMappingPolicy ~= nil then
-            for _, v in pairs(backend.policy.value) do
-              globalReqMappingPolicy.value[#globalReqMappingPolicy.value+1] = v
-            end
-          else
-            verbObj.policies[#verbObj.policies+1] = {
-              type = 'reqMapping',
-              value = backend.policy.value
+local _M = {}
+
+--- Parse request mapping
+local function parseRequestMapping(configObj)
+  local valueList = {}
+  if configObj ~= nil then
+    for _, obj in pairs(configObj.execute) do
+      for policy, v in pairs(obj) do
+        if policy == "set-variable" then
+          for _, actionObj in pairs(v.actions) do
+            local fromValue = actionObj.value
+            local toParsedArray = {string.match(actionObj.set, "([^.]+).([^.]+).([^.]+)") }
+            local toName = toParsedArray[3]
+            local toLocation = toParsedArray[2]
+            toLocation = toLocation == "headers" and "header" or toLocation
+            valueList[#valueList+1] = {
+              action = "insert",
+              from = {
+                value = fromValue
+              },
+              to = {
+                name = toName,
+                location = toLocation
+              }
             }
           end
         end
-      else
-        verbObj.backendUrl = ''
-        verbObj.backendMethod = verb
       end
     end
   end
-  return decoded
+  if next(valueList) ~= nil then
+    return {
+      type = "reqMapping",
+      value = valueList
+    }
+  else
+    return nil
+  end
 end
 
 --- Parse backendUrl and backendMethod
 -- @param swagger swagger file to parse
-function parseBackends(swagger)
+local function parseBackends(swagger)
   local configObj = swagger["x-gateway-configuration"]
   configObj = (configObj == nil) and swagger["x-ibm-configuration"] or configObj
   if configObj ~= nil then
@@ -113,32 +101,10 @@ function parseBackends(swagger)
   end
 end
 
---- Parse policies in swagger
--- @param swagger swagger file to parse
-function parseSwaggerPolicies(swagger)
-  local policies = {}
-  -- parse rate limit
-  local rlObj = swagger["x-gateway-rate-limit"]
-  rlObj = (rlObj == nil) and swagger["x-ibm-rate-limit"] or rlObj
-  local rateLimitPolicy = parseRateLimit(rlObj)
-  if rateLimitPolicy ~= nil then
-    policies[#policies+1] = rateLimitPolicy
-  end
-  -- parse set-variable
-  local configObj = swagger["x-gateway-configuration"]
-  configObj = (configObj == nil) and swagger["x-ibm-configuration"] or configObj
-  if configObj ~= nil then
-    local reqMappingPolicy = parseRequestMapping(configObj.assembly)
-    if reqMappingPolicy ~= nil then
-      policies[#policies+1] = reqMappingPolicy
-    end
-  end
-  return policies
-end
-
 --- Parse rate limit
-function parseRateLimit(rlObj)
+local function parseRateLimit(rlObj)
   if rlObj ~= nil and rlObj[1] ~= nil then
+    local unit
     rlObj = rlObj[1]
     if rlObj.unit == "second" then
       unit = 1
@@ -164,52 +130,37 @@ function parseRateLimit(rlObj)
   return nil
 end
 
---- Parse request mapping
-function parseRequestMapping(configObj)
-  local valueList = {}
+--- Parse policies in swagger
+-- @param swagger swagger file to parse
+local function parsePolicies(swagger)
+  local policies = {}
+  -- parse rate limit
+  local rlObj = swagger["x-gateway-rate-limit"]
+  rlObj = (rlObj == nil) and swagger["x-ibm-rate-limit"] or rlObj
+  local rateLimitPolicy = parseRateLimit(rlObj)
+  if rateLimitPolicy ~= nil then
+    policies[#policies+1] = rateLimitPolicy
+  end
+  -- parse set-variable
+  local configObj = swagger["x-gateway-configuration"]
+  configObj = (configObj == nil) and swagger["x-ibm-configuration"] or configObj
   if configObj ~= nil then
-    for _, obj in pairs(configObj.execute) do
-      for policy, v in pairs(obj) do
-        if policy == "set-variable" then
-          for _, actionObj in pairs(v.actions) do
-            local fromValue = actionObj.value
-            local toParsedArray = {string.match(actionObj.set, "([^.]+).([^.]+).([^.]+)") }
-            local toName = toParsedArray[3]
-            local toLocation = toParsedArray[2]
-            toLocation = toLocation == "headers" and "header" or toLocation
-            valueList[#valueList+1] = {
-              action = "insert",
-              from = {
-                value = fromValue
-              },
-              to = {
-                name = toName,
-                location = toLocation
-              }
-            }
-          end
-        end
-      end
+    local reqMappingPolicy = parseRequestMapping(configObj.assembly)
+    if reqMappingPolicy ~= nil then
+      policies[#policies+1] = reqMappingPolicy
     end
   end
-  if next(valueList) ~= nil then
-    return {
-      type = "reqMapping",
-      value = valueList
-    }
-  else
-    return nil
-  end
+  return policies
 end
 
 --- Parse security in swagger
 -- @param swagger swagger file to parse
-function parseSecurity(swagger)
+local function parseSecurity(swagger)
   local security = {}
   if swagger["securityDefinitions"] ~= nil then
     local secObject = swagger["securityDefinitions"]
     if utils.tableLength(secObject) == 2 then
-      secObj = {
+      local secObj = {
         type = 'clientSecret',
         scope = 'api'
       }
@@ -242,7 +193,7 @@ function parseSecurity(swagger)
   return security
 end
 
-function parseCors(swagger)
+local function parseCors(swagger)
   local cors = { origin = nil, methods = nil }
   local configObj = swagger["x-gateway-configuration"]
   configObj = (configObj == nil) and swagger["x-ibm-configuration"] or configObj
@@ -257,4 +208,55 @@ function parseCors(swagger)
   return nil
 end
 
+-- Convert passed-in swagger body to valid lua table
+-- @param swagger swagger file to parse
+function _M.parseSwagger(swagger)
+  local backends = parseBackends(swagger)
+  local policies = parsePolicies(swagger)
+  local security = parseSecurity(swagger)
+  local corsObj = parseCors(swagger)
+  local decoded = {
+    name = swagger.info.title,
+    basePath = swagger.basePath,
+    resources = {}
+  }
+  for path, verbObj in pairs(swagger.paths) do
+    decoded.resources[path] = { operations = {} }
+    decoded.resources[path].cors = corsObj
+    for verb, value in pairs(verbObj) do
+      decoded.resources[path].operations[verb] = {}
+      local verbObj = decoded.resources[path].operations[verb]
+      verbObj.policies = utils.deepCloneTable(policies) or {}
+      verbObj.security = security
+      if backends ~= nil then
+        local backend = (backends["all"] ~= nil) and backends["all"] or backends[value.operationId]
+        verbObj.backendUrl = backend.backendUrl
+        verbObj.backendMethod = (backend.backendMethod == 'keep') and verb or backend.backendMethod
+        if backend.policy ~= nil then
+          local globalReqMappingPolicy = nil;
+          for _, policy in pairs(verbObj.policies) do
+            if policy.type == 'reqMapping' then
+              globalReqMappingPolicy = policy;
+            end
+          end
+          if globalReqMappingPolicy ~= nil then
+            for _, v in pairs(backend.policy.value) do
+              globalReqMappingPolicy.value[#globalReqMappingPolicy.value+1] = v
+            end
+          else
+            verbObj.policies[#verbObj.policies+1] = {
+              type = 'reqMapping',
+              value = backend.policy.value
+            }
+          end
+        end
+      else
+        verbObj.backendUrl = ''
+        verbObj.backendMethod = verb
+      end
+    end
+  end
+  return decoded
+end
+
 return _M
diff --git a/scripts/lua/management/lib/tenants.lua b/scripts/lua/management/lib/tenants.lua
index a83c773..4fb7a8a 100644
--- a/scripts/lua/management/lib/tenants.lua
+++ b/scripts/lua/management/lib/tenants.lua
@@ -19,7 +19,6 @@
 -- Management interface for tenants for the gateway
 
 local cjson = require "cjson"
-local redis = require "lib/redis"
 local utils = require "lib/utils"
 local request = require "lib/request"
 local apis = require "management/lib/apis"
@@ -38,30 +37,10 @@ function _M.addTenant(dataStore, decoded, existingTenant)
   return cjson.decode(tenantObj)
 end
 
---- Get all tenants in redis
--- @param ds redis client
--- @param queryParams object containing optional query parameters
-function _M.getAllTenants(dataStore, queryParams)
-  local tenants = dataStore:getAllTenants()
-  local tenantList
-  if next(queryParams) ~= nil then
-    tenantList = filterTenants(tenants, queryParams);
-  end
-  if tenantList == nil then
-    tenantList = {}
-    for k, v in pairs(tenants) do
-      if k%2 == 0 then
-        tenantList[#tenantList+1] = cjson.decode(v)
-      end
-    end
-  end
-  return tenantList
-end
-
 --- Filter tenants based on query parameters
 -- @param tenants list of tenants
 -- @param queryParams query parameters to filter tenants
-function filterTenants(tenants, queryParams)
+local function filterTenants(tenants, queryParams)
   local namespace = queryParams['filter[where][namespace]']
   local instance = queryParams['filter[where][instance]']
   -- missing or invalid query parameters
@@ -82,49 +61,41 @@ function filterTenants(tenants, queryParams)
   return tenantList
 end
 
---- Get tenant by its id
--- @param ds redis client
--- @param id tenant id
-function _M.getTenant(dataStore, id)
-  local tenant = dataStore:getTenant(id)
-  if tenant == nil then
-    request.err(404, utils.concatStrings({"Unknown tenant id ", id }))
-  end
-  return tenant
-end
-
---- Get APIs associated with tenant
+--- Get all tenants in redis
 -- @param ds redis client
--- @param id tenant id
 -- @param queryParams object containing optional query parameters
-function _M.getTenantAPIs(dataStore, id, queryParams)
-  local apis = dataStore:getAllAPIs()
-  local apiList
+function _M.getAllTenants(dataStore, queryParams)
+  local tenants = dataStore:getAllTenants()
+  local tenantList
   if next(queryParams) ~= nil then
-    apiList = filterTenantAPIs(id, apis, queryParams);
+    tenantList = filterTenants(tenants, queryParams);
   end
-  if apiList == nil then
-    apiList = {}
-    for k, v in pairs(apis) do
+  if tenantList == nil then
+    tenantList = {}
+    for k, v in pairs(tenants) do
       if k%2 == 0 then
-        local decoded = cjson.decode(v)
-        if decoded.tenantId == id then
-          apiList[#apiList+1] = decoded
-        end
+        tenantList[#tenantList+1] = cjson.decode(v)
       end
     end
   end
-  if (((queryParams['skip'] == nil or queryParams['skip'] == 'undefined') and (queryParams['limit'] == nil or queryParams['limit'] == 'undefined')) or table.getn(apiList) == 0) then
-    return apiList
-  else
-    return applyPagingToAPIs(apiList, queryParams)
+  return tenantList
+end
+
+--- Get tenant by its id
+-- @param ds redis client
+-- @param id tenant id
+function _M.getTenant(dataStore, id)
+  local tenant = dataStore:getTenant(id)
+  if tenant == nil then
+    request.err(404, utils.concatStrings({"Unknown tenant id ", id }))
   end
+  return tenant
 end
 
 -- Apply paging on apis
 -- @param apis the list of apis
 -- @param queryparams object containing optional query parameters
-function applyPagingToAPIs(apiList, queryParams)
+local function applyPagingToAPIs(apiList, queryParams)
   local skip  = queryParams['skip']  == nil and 1 or queryParams['skip']
   local limit = queryParams['limit'] == nil and table.getn(apiList) or queryParams['limit']
 
@@ -155,7 +126,7 @@ end
 
 --- Filter apis based on query paramters
 -- @param queryParams query parameters to filter apis
-function filterTenantAPIs(id, apis, queryParams)
+local function filterTenantAPIs(id, apis, queryParams)
   local basePath = queryParams['filter[where][basePath]']
   basePath = basePath == nil and queryParams['basePath'] or basePath
   local name = queryParams['filter[where][name]']
@@ -180,6 +151,34 @@ function filterTenantAPIs(id, apis, queryParams)
   return apiList
 end
 
+--- Get APIs associated with tenant
+-- @param ds redis client
+-- @param id tenant id
+-- @param queryParams object containing optional query parameters
+function _M.getTenantAPIs(dataStore, id, queryParams)
+  local apis = dataStore:getAllAPIs()
+  local apiList
+  if next(queryParams) ~= nil then
+    apiList = filterTenantAPIs(id, apis, queryParams);
+  end
+  if apiList == nil then
+    apiList = {}
+    for k, v in pairs(apis) do
+      if k%2 == 0 then
+        local decoded = cjson.decode(v)
+        if decoded.tenantId == id then
+          apiList[#apiList+1] = decoded
+        end
+      end
+    end
+  end
+  if (((queryParams['skip'] == nil or queryParams['skip'] == 'undefined') and (queryParams['limit'] == nil or queryParams['limit'] == 'undefined')) or table.getn(apiList) == 0) then
+    return apiList
+  else
+    return applyPagingToAPIs(apiList, queryParams)
+  end
+end
+
 --- Delete tenant from gateway
 -- @param ds redis client
 -- @param id id of tenant to delete
diff --git a/scripts/lua/management/lib/validation.lua b/scripts/lua/management/lib/validation.lua
index 4c8ed58..8eef460 100644
--- a/scripts/lua/management/lib/validation.lua
+++ b/scripts/lua/management/lib/validation.lua
@@ -23,53 +23,67 @@ local utils = require "lib/utils"
 
 local _M = {}
 
-function _M.validate(dataStore, decoded)
-  local fields = {"name", "basePath", "tenantId", "resources"}
-  for _, v in pairs(fields) do
-    local res, err = isValid(dataStore, v, decoded[v])
-    if res == false then
-      return err
+--- Error checking for policies and security
+-- @param policies policies object
+-- @param security security object
+local function checkOptionalPolicies(policies, security)
+  if policies then
+    for _, v in pairs(policies) do
+      local validTypes = {"reqMapping", "rateLimit", "backendRouting"}
+      if (v.type == nil or v.value == nil) then
+        return false, { statusCode = 400, message = "Missing field in policy object. Need \"type\" and \"value\"." }
+      elseif utils.tableContains(validTypes, v.type) == false then
+        return false, { statusCode = 400, message = "Invalid type in policy object. Valid: " .. cjson.encode(validTypes) }
+      end
+    end
+  end
+  if security then
+    for _, sec in ipairs(security) do
+      local validScopes = {"tenant", "api", "resource"}
+      if (sec.type == nil or sec.scope == nil) then
+        return false, { statusCode = 400, message = "Missing field in security object. Need \"type\" and \"scope\"." }
+      elseif utils.tableContains(validScopes, sec.scope) == false then
+        return false, { statusCode = 400, message = "Invalid scope in security object. Valid: " .. cjson.encode(validScopes) }
+      end
     end
   end
-  return nil
 end
 
---- Check JSON body fields for errors
--- @param ds edis client instance
--- @param field name of field
--- @param object field object
-function isValid(dataStore, field, object)
-  -- Check that field exists in body
-  if not object then
-    return false, { statusCode = 400, message = utils.concatStrings({"Missing field '", field, "' in request body."}) }
+--- Error checking for operations
+-- @param operations operations object
+local function checkOperations(operations)
+  if not operations or next(operations) == nil then
+    return false, { statusCode = 400, message = "Missing or empty field 'operations' or in resource path object." }
   end
-  -- Additional check for basePath
-  if field == "basePath" then
-    local basePath = object
-    if string.match(basePath, "'") then
-      return false, { statusCode = 400, message = "basePath contains illegal character \"'\"." }
+  local allowedVerbs = {GET=true, POST=true, PUT=true, DELETE=true, PATCH=true, HEAD=true, OPTIONS=true}
+  for verb, verbObj in pairs(operations) do
+    if allowedVerbs[verb:upper()] == nil then
+      return false, { statusCode = 400, message = utils.concatStrings({"Resource verb '", verb, "' not supported."}) }
     end
-  end
-  -- Additional check for tenantId
-  if field == "tenantId" then
-    local tenant = dataStore:getTenant(object)
-    if tenant == nil then
-      return false, { statusCode = 404, message = utils.concatStrings({"Unknown tenant id ", object }) }
+    -- Check required fields
+    local requiredFields = {"backendMethod", "backendUrl"}
+    for k, v in pairs(requiredFields) do
+      if verbObj[v] == nil then
+        return false, { statusCode = 400, message = utils.concatStrings({"Missing field '", v, "' for '", verb, "' operation."}) }
+      end
+      if v == "backendMethod" then
+        local backendMethod = verbObj[v]
+        if allowedVerbs[backendMethod:upper()] == nil then
+          return false, { statusCode = 400, message = utils.concatStrings({"backendMethod '", backendMethod, "' not supported."}) }
+        end
+      end
     end
-  end
-  if field == "resources" then
-    local res, err = checkResources(object)
+    -- Check optional fields
+    local res, err = checkOptionalPolicies(verbObj.policies, verbObj.security)
     if res ~= nil and res == false then
       return res, err
     end
   end
-  -- All error checks passed
-  return true
 end
 
 --- Error checking for resources
 -- @param resources resources object
-function checkResources(resources)
+local function checkResources(resources)
   if next(resources) == nil then
     return false, { statusCode = 400, message = "Empty resources object." }
   end
@@ -90,62 +104,48 @@ function checkResources(resources)
   end
 end
 
---- Error checking for operations
--- @param operations operations object
-function checkOperations(operations)
-  if not operations or next(operations) == nil then
-    return false, { statusCode = 400, message = "Missing or empty field 'operations' or in resource path object." }
+--- Check JSON body fields for errors
+-- @param ds edis client instance
+-- @param field name of field
+-- @param object field object
+local function isValid(dataStore, field, object)
+  -- Check that field exists in body
+  if not object then
+    return false, { statusCode = 400, message = utils.concatStrings({"Missing field '", field, "' in request body."}) }
   end
-  local allowedVerbs = {GET=true, POST=true, PUT=true, DELETE=true, PATCH=true, HEAD=true, OPTIONS=true}
-  for verb, verbObj in pairs(operations) do
-    if allowedVerbs[verb:upper()] == nil then
-      return false, { statusCode = 400, message = utils.concatStrings({"Resource verb '", verb, "' not supported."}) }
+  -- Additional check for basePath
+  if field == "basePath" then
+    local basePath = object
+    if string.match(basePath, "'") then
+      return false, { statusCode = 400, message = "basePath contains illegal character \"'\"." }
     end
-    -- Check required fields
-    local requiredFields = {"backendMethod", "backendUrl"}
-    for k, v in pairs(requiredFields) do
-      if verbObj[v] == nil then
-        return false, { statusCode = 400, message = utils.concatStrings({"Missing field '", v, "' for '", verb, "' operation."}) }
-      end
-      if v == "backendMethod" then
-        local backendMethod = verbObj[v]
-        if allowedVerbs[backendMethod:upper()] == nil then
-          return false, { statusCode = 400, message = utils.concatStrings({"backendMethod '", backendMethod, "' not supported."}) }
-        end
-      end
+  end
+  -- Additional check for tenantId
+  if field == "tenantId" then
+    local tenant = dataStore:getTenant(object)
+    if tenant == nil then
+      return false, { statusCode = 404, message = utils.concatStrings({"Unknown tenant id ", object }) }
     end
-    -- Check optional fields
-    local res, err = checkOptionalPolicies(verbObj.policies, verbObj.security)
+  end
+  if field == "resources" then
+    local res, err = checkResources(object)
     if res ~= nil and res == false then
       return res, err
     end
   end
+  -- All error checks passed
+  return true
 end
 
---- Error checking for policies and security
--- @param policies policies object
--- @param security security object
-function checkOptionalPolicies(policies, security)
-  if policies then
-    for _, v in pairs(policies) do
-      local validTypes = {"reqMapping", "rateLimit", "backendRouting"}
-      if (v.type == nil or v.value == nil) then
-        return false, { statusCode = 400, message = "Missing field in policy object. Need \"type\" and \"value\"." }
-      elseif utils.tableContains(validTypes, v.type) == false then
-        return false, { statusCode = 400, message = "Invalid type in policy object. Valid: " .. cjson.encode(validTypes) }
-      end
-    end
-  end
-  if security then
-    for _, sec in ipairs(security) do
-      local validScopes = {"tenant", "api", "resource"}
-      if (sec.type == nil or sec.scope == nil) then
-        return false, { statusCode = 400, message = "Missing field in security object. Need \"type\" and \"scope\"." }
-      elseif utils.tableContains(validScopes, sec.scope) == false then
-        return false, { statusCode = 400, message = "Invalid scope in security object. Valid: " .. cjson.encode(validScopes) }
-      end
+function _M.validate(dataStore, decoded)
+  local fields = {"name", "basePath", "tenantId", "resources"}
+  for _, v in pairs(fields) do
+    local res, err = isValid(dataStore, v, decoded[v])
+    if res == false then
+      return err
     end
   end
+  return nil
 end
 
 return _M
diff --git a/scripts/lua/management/routes/apis.lua b/scripts/lua/management/routes/apis.lua
index 73b0904..45086c1 100644
--- a/scripts/lua/management/routes/apis.lua
+++ b/scripts/lua/management/routes/apis.lua
@@ -33,22 +33,22 @@ local REDIS_PASS = os.getenv("REDIS_PASS")
 
 local _M = {}
 
---- Request handler for routing API calls appropriately
-function _M.requestHandler(dataStore)
-  local requestMethod = ngx.req.get_method()
-  ngx.header.content_type = "application/json; charset=utf-8"
-  if requestMethod == "GET" then
-    getAPIs(dataStore)
-  elseif requestMethod == 'POST' or requestMethod == 'PUT' then
-    addAPI(dataStore)
-  elseif requestMethod == "DELETE" then
-    deleteAPI(dataStore)
-  else
-    request.err(400, "Invalid verb.")
+--- Check for api id from uri and use existing API if it already exists in redis
+-- @param red Redis client instance
+-- @param id API id to check
+local function checkForExistingAPI(dataStore, id)
+  local existing
+  if id ~= nil and id ~= '' then
+    existing = dataStore:getAPI(id)
+    if existing == nil then
+      dataStore:close()
+      request.err(404, utils.concatStrings({"Unknown API id ", id}))
+    end
   end
+  return existing
 end
 
-function getAPIs(dataStore)
+local function getAPIs(dataStore)
   local queryParams = ngx.req.get_uri_args()
   local id = ngx.var.api_id
   local version = ngx.var.version
@@ -103,7 +103,7 @@ function getAPIs(dataStore)
   end
 end
 
-function addAPI(dataStore)
+local function addAPI(dataStore)
   local id = ngx.var.api_id
   local existingAPI = checkForExistingAPI(dataStore, id)
   ngx.req.read_body()
@@ -159,7 +159,7 @@ function addAPI(dataStore)
   end
 end
 
-function deleteAPI(dataStore)
+local function deleteAPI(dataStore)
   local id = ngx.var.api_id
   if id == nil or id == '' then
     dataStore:close()
@@ -177,19 +177,19 @@ function deleteAPI(dataStore)
   end
 end
 
---- Check for api id from uri and use existing API if it already exists in redis
--- @param red Redis client instance
--- @param id API id to check
-function checkForExistingAPI(dataStore, id)
-  local existing
-  if id ~= nil and id ~= '' then
-    existing = dataStore:getAPI(id)
-    if existing == nil then
-      dataStore:close()
-      request.err(404, utils.concatStrings({"Unknown API id ", id}))
-    end
+--- Request handler for routing API calls appropriately
+function _M.requestHandler(dataStore)
+  local requestMethod = ngx.req.get_method()
+  ngx.header.content_type = "application/json; charset=utf-8"
+  if requestMethod == "GET" then
+    getAPIs(dataStore)
+  elseif requestMethod == 'POST' or requestMethod == 'PUT' then
+    addAPI(dataStore)
+  elseif requestMethod == "DELETE" then
+    deleteAPI(dataStore)
+  else
+    request.err(400, "Invalid verb.")
   end
-  return existing
 end
 
 return _M;
diff --git a/scripts/lua/management/routes/subscriptions.lua b/scripts/lua/management/routes/subscriptions.lua
index 6993f56..6d9406a 100644
--- a/scripts/lua/management/routes/subscriptions.lua
+++ b/scripts/lua/management/routes/subscriptions.lua
@@ -30,35 +30,69 @@ local REDIS_PASS = os.getenv("REDIS_PASS")
 
 local _M = {}
 
-function _M.requestHandler(dataStore)
-  local version = ngx.var.version
-  if version == "v2" then
-    v2(dataStore)
-  elseif version == "v1" then
-    v1(dataStore)
+local function validateSubscriptionBody(dataStore)
+  -- Read in the PUT JSON Body
+  ngx.req.read_body()
+  local args = ngx.req.get_body_data()
+  if not args then
+    dataStore:close()
+    request.err(400, "Missing request body.")
+  end
+  -- Convert json into Lua table
+  local decoded = cjson.decode(args)
+  -- Check required fields
+  local res, err = utils.tableContainsAll(decoded, {"key", "scope", "tenantId"})
+  if res == false then
+    dataStore:close()
+    request.err(err.statusCode, err.message)
+  end
+  -- Check if we're using tenant or resource or api
+  local resource = decoded.resource
+  local apiId = decoded.apiId
+  local redisKey
+  dataStore:setSnapshotId(decoded.tenantId)
+  local prefix = utils.concatStrings({"subscriptions:tenant:", decoded.tenantId})
+  if decoded.scope == "tenant" then
+    redisKey = prefix
+  elseif decoded.scope == "resource" then
+    if resource ~= nil then
+      redisKey = utils.concatStrings({prefix, ":resource:", resource})
+    else
+      dataStore:close()
+      request.err(400, "\"resource\" missing from request body.")
+    end
+  elseif decoded.scope == "api" then
+    if apiId ~= nil then
+      redisKey = utils.concatStrings({prefix, ":api:", apiId})
+    else
+      dataStore:close()
+      request.err(400, "\"apiId\" missing from request body.")
+    end
   else
-    request.err(404, "404 Not found")
+    dataStore:close()
+    request.err(400, "Invalid scope")
   end
+  redisKey = utils.concatStrings({redisKey, ":key:", decoded.key})
+  return redisKey
 end
 
+local function addSubscription(dataStore)
+  local redisKey = validateSubscriptionBody(dataStore)
+  dataStore:createSubscription(redisKey)
+  dataStore:close()
+  request.success(200, "Subscription created.")
+end
 
--- v2 --
-
-function v2(dataStore)
-  local requestMethod = ngx.req.get_method()
-  if requestMethod == "POST" or requestMethod == "PUT" then
-    v2AddSubscription(dataStore)
-  elseif requestMethod == "GET" then
-    v2GetSubscriptions(dataStore)
-  elseif requestMethod == "DELETE" then
-    v2DeleteSubscription(dataStore)
-  else
-    dataStore:close()
-    request.err(400, "Invalid verb")
-  end
+local function deleteSubscription(dataStore)
+  local redisKey = validateSubscriptionBody(dataStore)
+  dataStore:deleteSubscription(redisKey)
+  dataStore:close()
+  request.success(200, "Subscription deleted.")
 end
 
-function v2AddSubscription(dataStore)
+-- v2 --
+
+local function v2AddSubscription(dataStore)
   ngx.req.read_body()
   local args = ngx.req.get_body_data()
   if not args then
@@ -83,19 +117,19 @@ function v2AddSubscription(dataStore)
   request.success(200, cjson.encode(result))
 end
 
-function v2GetSubscriptions(dataStore)
+local function v2GetSubscriptions(dataStore)
   local tenantId = ngx.var.tenant_id
   local artifactId = ngx.req.get_uri_args()["artifact_id"]
   if artifactId == nil or artifactId == "" then
     request.err(400, "Missing artifact_id")
   end
   local subscriptionList = subscriptions.getSubscriptions(dataStore, artifactId, tenantId)
-  redis.close(red)
+  dataStore:close()
   ngx.header.content_type = "application/json; charset=utf-8"
   request.success(200, cjson.encode(subscriptionList))
 end
 
-function v2DeleteSubscription(dataStore)
+local function v2DeleteSubscription(dataStore)
   local clientId = ngx.var.client_id
   local tenantId = ngx.var.tenant_id
   local artifactId = ngx.req.get_uri_args()["artifact_id"]
@@ -109,14 +143,27 @@ function v2DeleteSubscription(dataStore)
   if res == false then
     request.err(404, "Subscription doesn't exist")
   end
-  redis.close(red)
+  dataStore:close()
   request.success(204)
 end
 
+local function v2(dataStore)
+  local requestMethod = ngx.req.get_method()
+  if requestMethod == "POST" or requestMethod == "PUT" then
+    v2AddSubscription(dataStore)
+  elseif requestMethod == "GET" then
+    v2GetSubscriptions(dataStore)
+  elseif requestMethod == "DELETE" then
+    v2DeleteSubscription(dataStore)
+  else
+    dataStore:close()
+    request.err(400, "Invalid verb")
+  end
+end
 
 -- v1 --
 
-function v1(dataStore)
+local function v1(dataStore)
   local requestMethod = ngx.req.get_method()
   if requestMethod == "POST" or requestMethod == "PUT" then
     addSubscription(dataStore)
@@ -128,64 +175,15 @@ function v1(dataStore)
   end
 end
 
-function addSubscription(dataStore)
-  local redisKey = validateSubscriptionBody(dataStore)
-  dataStore:createSubscription(redisKey)
-  dataStore:close()
-  request.success(200, "Subscription created.")
-end
-
-function deleteSubscription(dataStore)
-  local redisKey = validateSubscriptionBody(dataStore)
-  dataStore:deleteSubscription(redisKey)
-  dataStore:close()
-  request.success(200, "Subscription deleted.")
-end
-
-function validateSubscriptionBody(dataStore)
-  -- Read in the PUT JSON Body
-  ngx.req.read_body()
-  local args = ngx.req.get_body_data()
-  if not args then
-    dataStore:close()
-    request.err(400, "Missing request body.")
-  end
-  -- Convert json into Lua table
-  local decoded = cjson.decode(args)
-  -- Check required fields
-  local res, err = utils.tableContainsAll(decoded, {"key", "scope", "tenantId"})
-  if res == false then
-    dataStore:close()
-    request.err(err.statusCode, err.message)
-  end
-  -- Check if we're using tenant or resource or api
-  local resource = decoded.resource
-  local apiId = decoded.apiId
-  local redisKey
-  dataStore:setSnapshotId(decoded.tenantId)
-  local prefix = utils.concatStrings({"subscriptions:tenant:", decoded.tenantId})
-  if decoded.scope == "tenant" then
-    redisKey = prefix
-  elseif decoded.scope == "resource" then
-    if resource ~= nil then
-      redisKey = utils.concatStrings({prefix, ":resource:", resource})
-    else
-      dataStore:close()
-      request.err(400, "\"resource\" missing from request body.")
-    end
-  elseif decoded.scope == "api" then
-    if apiId ~= nil then
-      redisKey = utils.concatStrings({prefix, ":api:", apiId})
-    else
-      dataStore:close()
-      request.err(400, "\"apiId\" missing from request body.")
-    end
+function _M.requestHandler(dataStore)
+  local version = ngx.var.version
+  if version == "v2" then
+    v2(dataStore)
+  elseif version == "v1" then
+    v1(dataStore)
   else
-    dataStore:close()
-    request.err(400, "Invalid scope")
+    request.err(404, "404 Not found")
   end
-  redisKey = utils.concatStrings({redisKey, ":key:", decoded.key})
-  return redisKey
 end
 
 return _M
diff --git a/scripts/lua/management/routes/tenants.lua b/scripts/lua/management/routes/tenants.lua
index 9e26020..4b92bdd 100644
--- a/scripts/lua/management/routes/tenants.lua
+++ b/scripts/lua/management/routes/tenants.lua
@@ -29,22 +29,23 @@ local REDIS_PASS = os.getenv("REDIS_PASS")
 
 local _M = {};
 
---- Request handler for routing tenant calls appropriately
-function _M.requestHandler(dataStore)
-  local requestMethod = ngx.req.get_method()
-  ngx.header.content_type = "application/json; charset=utf-8"
-  if requestMethod == "GET" then
-    getTenants(dataStore)
-  elseif requestMethod == "PUT" or requestMethod == "POST" then
-    addTenant(dataStore)
-  elseif requestMethod == "DELETE" then
-    deleteTenant(dataStore)
-  else
-    request.err(400, "Invalid verb.")
+--- Check for tenant id from uri and use existing tenant if it already exists in redis
+-- @param red Redis client instance
+local function checkForExistingTenant(dataStore)
+  local id = ngx.var.tenant_id
+  local existing
+  -- Get object from redis
+  if id ~= nil and id ~= '' then
+    existing = dataStore:getTenant(id)
+    if existing == nil then
+      dataStore:close()
+      request.err(404, utils.concatStrings({"Unknown Tenant id ", id}))
+    end
   end
+  return existing
 end
 
-function addTenant(dataStore)
+local function addTenant(dataStore)
   -- Open connection to redis or use one from connection pool
   -- Check for tenant id and use existingTenant if it already exists in redis
   local existingTenant = checkForExistingTenant(dataStore)
@@ -76,25 +77,9 @@ function addTenant(dataStore)
   request.success(200, tenantObj)
 end
 
---- Check for tenant id from uri and use existing tenant if it already exists in redis
--- @param red Redis client instance
-function checkForExistingTenant(dataStore)
-  local id = ngx.var.tenant_id
-  local existing
-  -- Get object from redis
-  if id ~= nil and id ~= '' then
-    existing = dataStore:getTenant(id)
-    if existing == nil then
-      dataStore:close()
-      request.err(404, utils.concatStrings({"Unknown Tenant id ", id}))
-    end
-  end
-  return existing
-end
-
 --- Get one or all tenants from the gateway
 -- GET /v1/tenants
-function getTenants(dataStore)
+local function getTenants(dataStore)
   local queryParams = ngx.req.get_uri_args()
   local id = ngx.var.tenant_id
   if id == '' then
@@ -125,7 +110,7 @@ end
 
 --- Delete tenant from gateway
 -- DELETE /v1/tenants/<id>
-function deleteTenant(dataStore)
+local function deleteTenant(dataStore)
   local id = ngx.var.tenant_id
   if id == nil or id == '' then
     request.err(400, "No id specified.")
@@ -139,4 +124,19 @@ function deleteTenant(dataStore)
   request.success(200, cjson.encode({}))
 end
 
+--- Request handler for routing tenant calls appropriately
+function _M.requestHandler(dataStore)
+  local requestMethod = ngx.req.get_method()
+  ngx.header.content_type = "application/json; charset=utf-8"
+  if requestMethod == "GET" then
+    getTenants(dataStore)
+  elseif requestMethod == "PUT" or requestMethod == "POST" then
+    addTenant(dataStore)
+  elseif requestMethod == "DELETE" then
+    deleteTenant(dataStore)
+  else
+    request.err(400, "Invalid verb.")
+  end
+end
+
 return _M
diff --git a/scripts/lua/oauth/facebook.lua b/scripts/lua/oauth/facebook.lua
index a27b295..08b1f5b 100644
--- a/scripts/lua/oauth/facebook.lua
+++ b/scripts/lua/oauth/facebook.lua
@@ -20,25 +20,8 @@ local cjson = require 'cjson'
 local utils = require "lib/utils"
 
 local _M = {}
-function _M.process(dataStore, token)
-
-  local headerName = utils.concatStrings({'http_', 'x-facebook-app-token'}):gsub("-", "_")
-
-  local facebookAppToken = ngx.var[headerName]
-  if facebookAppToken == nil then
-    request.err(401, 'Facebook requires you provide an app token to validate user tokens. Provide a X-Facebook-App-Token header')
-    return nil
-  end
 
-  local result = dataStore:getOAuthToken('facebook', utils.concatStrings({token, facebookAppToken}))
-  if result ~= ngx.null then
-    return cjson.decode(result)
-  end
-
-   return exchangeOAuthToken(dataStore, token, facebookAppToken)
-end
-
-function exchangeOAuthToken(dataStore, token, facebookAppToken)
+local function exchangeOAuthToken(dataStore, token, facebookAppToken)
   local http = require 'resty.http'
   local request = require "lib/request"
   local httpc = http.new()
@@ -73,4 +56,22 @@ function exchangeOAuthToken(dataStore, token, facebookAppToken)
   return json_resp
 end
 
+function _M.process(dataStore, token)
+
+  local headerName = utils.concatStrings({'http_', 'x-facebook-app-token'}):gsub("-", "_")
+
+  local facebookAppToken = ngx.var[headerName]
+  if facebookAppToken == nil then
+    request.err(401, 'Facebook requires you provide an app token to validate user tokens. Provide a X-Facebook-App-Token header')
+    return nil
+  end
+
+  local result = dataStore:getOAuthToken('facebook', utils.concatStrings({token, facebookAppToken}))
+  if result ~= ngx.null then
+    return cjson.decode(result)
+  end
+
+   return exchangeOAuthToken(dataStore, token, facebookAppToken)
+end
+
 return _M
diff --git a/scripts/lua/oauth/google.lua b/scripts/lua/oauth/google.lua
index bd8e11b..efdbf28 100644
--- a/scripts/lua/oauth/google.lua
+++ b/scripts/lua/oauth/google.lua
@@ -29,7 +29,7 @@ function _M.process (dataStore, token)
 
   local httpc = http.new()
   if result ~= ngx.null then
-    json_resp = cjson.decode(result)
+    local json_resp = cjson.decode(result)
     ngx.header['X-OIDC-Sub'] = json_resp['sub']
     ngx.header['X-OIDC-Email'] = json_resp['email']
     ngx.header['X-OIDC-Scope'] = json_resp['scope']
diff --git a/scripts/lua/policies/backendRouting.lua b/scripts/lua/policies/backendRouting.lua
index 646de94..e426e53 100644
--- a/scripts/lua/policies/backendRouting.lua
+++ b/scripts/lua/policies/backendRouting.lua
@@ -26,6 +26,14 @@ local backendOverride = os.getenv("BACKEND_HOST")
 
 local _M = {}
 
+local function setUpstream(u)
+  local upstream = utils.concatStrings({u.scheme, '://', u.host})
+  if u.port ~= nil and u.port ~= '' then
+    upstream = utils.concatStrings({upstream, ':', u.port})
+  end
+  ngx.var.upstream = upstream
+end
+
 --- Set upstream based on the backendUrl
 function _M.setRoute(backendUrl, gatewayPath)
   _M.setRouteWithOverride(backendUrl, gatewayPath, backendOverride)
@@ -109,12 +117,4 @@ function _M.getUriPath(backendPath)
   end
 end
 
-function setUpstream(u)
-  local upstream = utils.concatStrings({u.scheme, '://', u.host})
-  if u.port ~= nil and u.port ~= '' then
-    upstream = utils.concatStrings({upstream, ':', u.port})
-  end
-  ngx.var.upstream = upstream
-end
-
 return _M
diff --git a/scripts/lua/policies/mapping.lua b/scripts/lua/policies/mapping.lua
index 63ba789..3ed6385 100644
--- a/scripts/lua/policies/mapping.lua
+++ b/scripts/lua/policies/mapping.lua
@@ -30,33 +30,58 @@ local query
 local headers
 local path
 
---- Implementation for the mapping policy.
--- @param map The mapping object that contains details about request tranformations
-function processMap(map)
-  getRequestParams()
-  for k, v in pairs(map) do
-    if v.action == "insert" then
-      insertParam(v)
-    elseif v.action == "remove" then
-      removeParam(v)
-    elseif v.action == "transform" then
-      transformParam(v)
-    elseif v.action == "default" then
-      checkDefault(v)
-    else
-      logger.err(utils.concatStrings({'Map action not recognized. Skipping... ', v.action}))
-    end
+local function insertHeader(k, v)
+  ngx.req.set_header(k, v)
+  headers[k] = v
+end
+
+local function insertQuery(k, v)
+  query[k] = v
+end
+
+local function insertBody(k, v)
+  body[k] = v
+end
+
+local function insertPath(k, v)
+  v = ngx.unescape_uri(v)
+  path = path:gsub(utils.concatStrings({"%{", k ,"%}"}), v)
+  ngx.req.set_uri(path)
+end
+
+local function removeHeader(k)
+  ngx.req.clear_header(k)
+end
+
+local function removeQuery(k)
+  query[k] = nil
+end
+
+local function removeBody(k)
+  body[k] = nil
+end
+
+local function decodeQuery(param)
+  local decoded = param:gsub('+', ' '):gsub('%%(%x%x)',
+    function(hex) return string.char(tonumber(hex, 16)) end)
+  return decoded
+end
+
+local function parseUrl(url)
+  local map = {}
+  for k,v in url:gmatch('([^&=?]+)=([^&=?]+)') do
+    map[ k ] = decodeQuery(v)
   end
-  finalize()
+  return map
 end
 
 --- Get request body, params, and headers from incoming requests
-function getRequestParams()
+local function getRequestParams()
   ngx.req.read_body()
   body = ngx.req.get_body_data()
   if body ~= nil then
     -- decode body if json
-    decoded, err = cjson.decode(body)
+    local decoded, err = cjson.decode(body)
     if err == nil then
       body = decoded
     end
@@ -74,7 +99,7 @@ end
 
 --- Insert parameter value to header, body, or query params into request
 -- @param m Parameter value to add to request
-function insertParam(m)
+local function insertParam(m)
   local v
   local k = m.to.name
   if m.from.value ~= nil then
@@ -102,7 +127,7 @@ end
 
 --- Remove parameter value to header, body, or query params from request
 -- @param m Parameter value to remove from request
-function removeParam(m)
+local function removeParam(m)
   if m.from.location == "header" then
     removeHeader(m.from.name)
   elseif m.from.location == "query" then
@@ -112,35 +137,12 @@ function removeParam(m)
   end
 end
 
---- Move parameter value from one location to another in the request
--- @param m Parameter value to move within request
-function transformParam(m)
-  if m.from.name == '*' then
-    transformAllParams(m.from.location, m.to.location)
-  else
-    insertParam(m)
-    removeParam(m)
-  end
-end
-
---- Checks if the header has been set, and sets the header to a value if found to be null.
--- @param m Header name and value to be set, if header is null.
-function checkDefault(m)
-  if m.to.location == "header" and headers[m.to.name] == nil then
-    insertHeader(m.to.name, m.from.value)
-  elseif m.to.location == "query" and query[m.to.name] == nil then
-    insertQuery(m.to.name, m.from.value)
-  elseif m.to.location == "body" and body[m.to.name] == nil then
-    insertBody(m.to.name, m.from.value)
-  end
-end
-
 --- Function to handle wildcarding in the transform process.
 -- If the value in the from object is '*', this function will pull all values from the incoming request
 -- and move them to the location provided in the to object
 -- @param s The source object from which we pull all parameters
 -- @param d The destination object that we will move all found parameters to.
-function transformAllParams(s, d)
+local function transformAllParams(s, d)
   if s == 'query' then
     for k, v in pairs(query) do
       local t = {}
@@ -192,57 +194,55 @@ function transformAllParams(s, d)
   end
 end
 
-function finalize()
-  if type(body) == 'table' and next(body) ~= nil then
-    local bodyJson = cjson.encode(body)
-    ngx.req.set_body_data(bodyJson)
+--- Move parameter value from one location to another in the request
+-- @param m Parameter value to move within request
+local function transformParam(m)
+  if m.from.name == '*' then
+    transformAllParams(m.from.location, m.to.location)
+  else
+    insertParam(m)
+    removeParam(m)
   end
-  ngx.req.set_uri_args(query)
-end
-
-function insertHeader(k, v)
-  ngx.req.set_header(k, v)
-  headers[k] = v
-end
-
-function insertQuery(k, v)
-  query[k] = v
 end
 
-function insertBody(k, v)
-  body[k] = v
-end
-
-function insertPath(k, v)
-  v = ngx.unescape_uri(v)
-  path = path:gsub(utils.concatStrings({"%{", k ,"%}"}), v)
-  ngx.req.set_uri(path)
-end
-
-function removeHeader(k)
-  ngx.req.clear_header(k)
-end
-
-function removeQuery(k)
-  query[k] = nil
-end
-
-function removeBody(k)
-  body[k] = nil
+--- Checks if the header has been set, and sets the header to a value if found to be null.
+-- @param m Header name and value to be set, if header is null.
+local function checkDefault(m)
+  if m.to.location == "header" and headers[m.to.name] == nil then
+    insertHeader(m.to.name, m.from.value)
+  elseif m.to.location == "query" and query[m.to.name] == nil then
+    insertQuery(m.to.name, m.from.value)
+  elseif m.to.location == "body" and body[m.to.name] == nil then
+    insertBody(m.to.name, m.from.value)
+  end
 end
 
-function parseUrl(url)
-  local map = {}
-  for k,v in url:gmatch('([^&=?]+)=([^&=?]+)') do
-    map[ k ] = decodeQuery(v)
+local function finalize()
+  if type(body) == 'table' and next(body) ~= nil then
+    local bodyJson = cjson.encode(body)
+    ngx.req.set_body_data(bodyJson)
   end
-  return map
+  ngx.req.set_uri_args(query)
 end
 
-function decodeQuery(param)
-  local decoded = param:gsub('+', ' '):gsub('%%(%x%x)',
-    function(hex) return string.char(tonumber(hex, 16)) end)
-  return decoded
+--- Implementation for the mapping policy.
+-- @param map The mapping object that contains details about request tranformations
+local function processMap(map)
+  getRequestParams()
+  for k, v in pairs(map) do
+    if v.action == "insert" then
+      insertParam(v)
+    elseif v.action == "remove" then
+      removeParam(v)
+    elseif v.action == "transform" then
+      transformParam(v)
+    elseif v.action == "default" then
+      checkDefault(v)
+    else
+      logger.err(utils.concatStrings({'Map action not recognized. Skipping... ', v.action}))
+    end
+  end
+  finalize()
 end
 
 _M.processMap = processMap
diff --git a/scripts/lua/policies/rateLimit.lua b/scripts/lua/policies/rateLimit.lua
index 5f2ca98..468852f 100644
--- a/scripts/lua/policies/rateLimit.lua
+++ b/scripts/lua/policies/rateLimit.lua
@@ -26,7 +26,7 @@ local _M = {}
 -- @param dataStore the datastore object
 -- @param obj rateLimit object containing interval, rate, scope, subscription fields
 -- @param apiKey optional api key to use if subscription is set to true
-function limit(dataStore, obj, apiKey)
+local function limit(dataStore, obj, apiKey)
   local rate = obj.interval / obj.rate
   local tenantId = ngx.var.tenant
   local gatewayPath = ngx.var.gatewayPath
diff --git a/scripts/lua/policies/security.lua b/scripts/lua/policies/security.lua
index 2bcdeb0..4afe76c 100644
--- a/scripts/lua/policies/security.lua
+++ b/scripts/lua/policies/security.lua
@@ -24,7 +24,7 @@ local utils = require "lib/utils"
 --- Allow or block a request by calling a loaded security policy
 -- @param dataStore the datastore object
 -- @param securityObj an object out of the security array in a given tenant / api / resource
-function process(dataStore, securityObj)
+local function process(dataStore, securityObj)
   local ok, result = pcall(require, utils.concatStrings({'policies/security/', securityObj.type}))
   if not ok then
     ngx.log(ngx.ERR, 'An unexpected error ocurred while processing the security policy: ' .. securityObj.type)
diff --git a/scripts/lua/policies/security/apiKey.lua b/scripts/lua/policies/security/apiKey.lua
index 409d6d9..7abee5b 100644
--- a/scripts/lua/policies/security/apiKey.lua
+++ b/scripts/lua/policies/security/apiKey.lua
@@ -18,13 +18,9 @@
 --- @module apiKey
 -- Check a subscription with an API Key
 
-local dataStore = require "lib/dataStore"
 local utils = require "lib/utils"
 local request = require "lib/request"
-
-local REDIS_HOST = os.getenv("REDIS_HOST")
-local REDIS_PORT = os.getenv("REDIS_PORT")
-local REDIS_PASS = os.getenv("REDIS_PASS")
+local logger = require "lib/logger"
 
 local _M = {}
 
@@ -36,7 +32,7 @@ local _M = {}
 -- @param scope scope of the subscription
 -- @param apiKey the subscription api key
 -- @param return boolean value indicating if the subscription exists in redis
-function validate(dataStore, tenant, gatewayPath, apiId, scope, apiKey)
+local function validate(dataStore, tenant, gatewayPath, apiId, scope, apiKey)
   -- Open connection to redis or use one from connection pool
   local k
   if scope == 'tenant' then
@@ -54,27 +50,24 @@ function validate(dataStore, tenant, gatewayPath, apiId, scope, apiKey)
   end
 end
 
-function process(dataStore, securityObj)
-  return processWithHashFunction(dataStore, securityObj, sha256)
-end
-
 --- Process the security object
 -- @param dataStore the datastore object
 -- @param securityObj security object from nginx conf file
 -- @param hashFunction a function that will be called to hash the string
 -- @return apiKey api key for the subscription
-function processWithHashFunction(dataStore, securityObj, hashFunction)
+local function processWithHashFunction(dataStore, securityObj, hashFunction)
   local tenant = ngx.var.tenant
   local gatewayPath = ngx.var.gatewayPath
   local apiId = dataStore:resourceToApi(utils.concatStrings({'resources:', tenant, ':', gatewayPath}))
   local scope = securityObj.scope
-  local name = (securityObj.name == nil) and ((securityObj.header == nil) and 'x-api-key' or securityObj.header) or securityObj.name
   local queryString = ngx.req.get_uri_args()
   local location = (securityObj.location == nil) and 'header' or securityObj.location
 -- backwards compatible with "header" argument for name value. "name" argument takes precedent if both provided
   local name = (securityObj.name == nil and securityObj.header == nil) and 'x-api-key' or (securityObj.name or securityObj.header)
   local apiKey = nil
 
+  ngx.log(ngx.DEBUG, "Processing API_KEY security policy")
+
   if location == "header" then
     apiKey = ngx.var[utils.concatStrings({'http_', name}):gsub("-", "_")]
   end
@@ -97,17 +90,10 @@ function processWithHashFunction(dataStore, securityObj, hashFunction)
   return apiKey
 end
 
---- Calculate the sha256 hash of a string
--- @param str the string you want to hash
--- @return a hashed version of the string
-function sha256(str)
-  local resty_sha256 = require "resty.sha256"
-  local resty_str = require "resty.string"
-  local sha = resty_sha256:new()
-  sha:update(str)
-  local digest = sha:final()
-  return resty_str.to_hex(digest)
+local function process(dataStore, securityObj)
+  return processWithHashFunction(dataStore, securityObj, utils.sha256)
 end
+
 _M.processWithHashFunction = processWithHashFunction
 _M.process = process
 
diff --git a/scripts/lua/policies/security/clientSecret.lua b/scripts/lua/policies/security/clientSecret.lua
index 79f2b82..132c58a 100644
--- a/scripts/lua/policies/security/clientSecret.lua
+++ b/scripts/lua/policies/security/clientSecret.lua
@@ -19,21 +19,35 @@
 -- Check a subscription with a client id and a hashed secret
 local _M = {}
 
-local dataStore = require "lib/dataStore"
 local utils = require "lib/utils"
 local request = require "lib/request"
+local logger = require "lib/logger"
 
-local REDIS_HOST = os.getenv("REDIS_HOST")
-local REDIS_PORT = os.getenv("REDIS_PORT")
-local REDIS_PASS = os.getenv("REDIS_PASS")
-
---- Process function main entry point for the security block.
---  Takes 2 headers and decides if the request should be allowed based on a hashed secret key
---@param dataStore the datastore object
---@param securityObj the security object loaded from nginx.conf
---@return a string representation of what this looks like in redis :clientsecret:clientid:hashed secret
-function process(dataStore, securityObj)
-  local result = processWithHashFunction(dataStore, securityObj, utils.hash)
+--- Validate that the subscription exists in the dataStore
+-- @param dataStore the datastore object
+-- @param tenant the tenantId we are checking for
+-- @param gatewayPath the possible resource we are checking for
+-- @param apiId if we are checking for an api
+-- @param scope which values should we be using to find the location of the secret
+-- @param clientId the subscribed client id
+-- @param clientSecret the hashed client secret
+local function validate(dataStore, tenant, gatewayPath, apiId, scope, clientId, clientSecret)
+  -- Open connection to redis or use one from connection pool
+  local k
+  if scope == "tenant" then
+    k = utils.concatStrings({"subscriptions:tenant:", tenant})
+  elseif scope == "resource" then
+    k = utils.concatStrings({"subscriptions:tenant:", tenant, ":resource:", gatewayPath})
+  elseif scope == "api" then
+    k = utils.concatStrings({"subscriptions:tenant:", tenant, ":api:", apiId})
+  end
+  -- using the same key location in redis, just using :clientsecret: instead of :key:
+  k = utils.concatStrings({k, ":clientsecret:", clientId, ":", clientSecret})
+  if dataStore:exists(k) == 1 then
+    return k
+  else
+    return nil
+  end
 end
 
 --- In order to properly test this functionallity, I use this function to do all of the business logic with injected dependencies
@@ -41,47 +55,49 @@ end
 -- @param dataStore the datastore object
 -- @param securityObj the security configuration for the tenant/resource/api we are verifying
 -- @param hashFunction the function used to perform the hash of the api secret
-function processWithHashFunction(dataStore, securityObj, hashFunction)
+local function processWithHashFunction(dataStore, securityObj, hashFunction)
   -- pull the configuration from nginx
   local tenant = ngx.var.tenant
   local gatewayPath = ngx.var.gatewayPath
   local apiId = ngx.var.apiId
   local scope = securityObj.scope
   local queryString = ngx.req.get_uri_args()
-  local location = (securityObj.location == nil) and 'header' or securityObj.location
+  local location = (securityObj.location == nil) and "header" or securityObj.location
   local clientId = nil
   local clientSecret = nil
 
+  ngx.log(ngx.DEBUG, "Processing CLIENT_SECRET security policy")
+
   -- allow support for custom names in query or header
-  local clientIdName = (securityObj.idFieldName == nil) and 'X-Client-ID' or securityObj.idFieldName
+  local clientIdName = (securityObj.idFieldName == nil) and "X-Client-ID" or securityObj.idFieldName
   if location == "header" then
-    clientId = ngx.var[utils.concatStrings({'http_', clientIdName}):gsub("-", "_")]
+    clientId = ngx.var[utils.concatStrings({"http_", clientIdName}):gsub("-", "_")]
   end
   if location == "query" then
     clientId = queryString[clientIdName]
   end
--- if they didn't supply whatever name this is configured to require, error out
-  if clientId == nil or clientId == '' then
+  -- if they didn't supply whatever name this is configured to require, error out
+  if clientId == nil or clientId == "" then
     request.err(401, clientIdName .. " required")
     return false
   end
 
--- allow support for custom names in query or header
-  local clientSecretName = (securityObj.secretFieldName == nil) and 'X-Client-Secret' or securityObj.secretFieldName
-  _G.clientSecretName = clientSecretName:lower()
+  -- allow support for custom names in query or header
+  local clientSecretName = (securityObj.secretFieldName == nil) and "X-Client-Secret" or securityObj.secretFieldName
+  ngx.ctx.clientSecretName = clientSecretName:lower()
   if location == "header" then
-    clientSecret = ngx.var[utils.concatStrings({'http_', clientSecretName}):gsub("-","_")]
+    clientSecret = ngx.var[utils.concatStrings({"http_", clientSecretName}):gsub("-", "_")]
   end
   if location == "query" then
     clientSecret = queryString[clientSecretName]
   end
--- if they didn't supply whatever name this is configured to require, error out
-  if clientSecret == nil or clientSecret == '' then
+  -- if they didn't supply whatever name this is configured to require, error out
+  if clientSecret == nil or clientSecret == "" then
     request.err(401, clientSecretName .. " required")
     return false
   end
 
--- hash the secret
+  -- hash the secret
   local result = validate(dataStore, tenant, gatewayPath, apiId, scope, clientId, hashFunction(clientSecret))
   if result == nil then
     request.err(401, "Secret mismatch or not subscribed to this api.")
@@ -90,32 +106,15 @@ function processWithHashFunction(dataStore, securityObj, hashFunction)
   return result
 end
 
---- Validate that the subscription exists in the dataStore
--- @param dataStore the datastore object
--- @param tenant the tenantId we are checking for
--- @param gatewayPath the possible resource we are checking for
--- @param apiId if we are checking for an api
--- @param scope which values should we be using to find the location of the secret
--- @param clientId the subscribed client id
--- @param clientSecret the hashed client secret
-function validate(dataStore, tenant, gatewayPath, apiId, scope, clientId, clientSecret)
--- Open connection to redis or use one from connection pool
-  local k
-  if scope == 'tenant' then
-    k = utils.concatStrings({'subscriptions:tenant:', tenant})
-  elseif scope == 'resource' then
-    k = utils.concatStrings({'subscriptions:tenant:', tenant, ':resource:', gatewayPath})
-  elseif scope == 'api' then
-    k = utils.concatStrings({'subscriptions:tenant:', tenant, ':api:', apiId})
-  end
-  -- using the same key location in redis, just using :clientsecret: instead of :key:
-  k = utils.concatStrings({k, ':clientsecret:', clientId, ':', clientSecret})
-  if dataStore:exists(k) == 1 then
-    return k
-  else
-    return nil
-  end
+--- Process function main entry point for the security block.
+--  Takes 2 headers and decides if the request should be allowed based on a hashed secret key
+--@param dataStore the datastore object
+--@param securityObj the security object loaded from nginx.conf
+--@return a string representation of what this looks like in redis :clientsecret:clientid:hashed secret
+local function process(dataStore, securityObj)
+  return processWithHashFunction(dataStore, securityObj, utils.hash)
 end
+
 _M.processWithHashFunction = processWithHashFunction
 _M.process = process
 return _M
diff --git a/scripts/lua/policies/security/oauth2.lua b/scripts/lua/policies/security/oauth2.lua
index 6b58bf9..c1492e5 100644
--- a/scripts/lua/policies/security/oauth2.lua
+++ b/scripts/lua/policies/security/oauth2.lua
@@ -20,20 +20,37 @@
 
 local utils = require "lib/utils"
 local request = require "lib/request"
-local dataStore = require "lib/dataStore"
-local cjson = require "cjson"
-
-local REDIS_HOST = os.getenv("REDIS_HOST")
-local REDIS_PORT = os.getenv("REDIS_PORT")
-local REDIS_PASS = os.getenv("REDIS_PASS")
 
 local _M = {}
 
+--- Exchange tokens with an oauth provider. Loads a provider based on configuration in the nginx.conf
+-- @param dataStore the datastore object
+-- @param token the accessToken passed in the authorization header of the routing request
+-- @param provider the name of the provider we will load from a file. Currently supported google/github/facebook
+-- @return the json object recieved from exchanging tokens with the provider
+local function exchange(dataStore, token, provider, securityObj)
+  -- exchange tokens with the provider
+  local loaded, impl = pcall(require, utils.concatStrings({'oauth/', provider}))
+  if not loaded then
+    request.err(500, 'Error loading OAuth provider authentication module')
+    print("error loading provider:", impl)
+    return nil
+  end
+
+  local result = impl.process(dataStore, token, securityObj)
+  if result == nil then
+    request.err('401', 'OAuth token didn\'t work or provider doesn\'t support OpenID connect')
+  end
+  -- cache the token
+  return result
+end
 
 -- Process the security object
 -- @param securityObj security object from nginx conf file
 -- @return oauthId oauth identification
-function process(dataStore, securityObj)
+local function process(dataStore, securityObj)
+  ngx.log(ngx.DEBUG, "Processing OAUTH2 security policy")
+
   local accessToken = ngx.var['http_Authorization']
   if accessToken == nil then
     request.err(401, "No Authorization header provided")
@@ -56,27 +73,5 @@ function process(dataStore, securityObj)
   return token
 end
 
---- Exchange tokens with an oauth provider. Loads a provider based on configuration in the nginx.conf
--- @param dataStore the datastore object
--- @param token the accessToken passed in the authorization header of the routing request
--- @param provider the name of the provider we will load from a file. Currently supported google/github/facebook
--- @return the json object recieved from exchanging tokens with the provider
-function exchange(dataStore, token, provider, securityObj)
-    -- exchange tokens with the provider
-    local loaded, impl = pcall(require, utils.concatStrings({'oauth/', provider}))
-    if not loaded then
-      request.err(500, 'Error loading OAuth provider authentication module')
-      print("error loading provider:", impl)
-      return nil
-    end
-
-    local result = impl.process(dataStore, token, securityObj)
-    if result == nil then
-      request.err('401', 'OAuth token didn\'t work or provider doesn\'t support OpenID connect')
-    end
-    -- cache the token
-    return result
-end
-
 _M.process = process
 return _M
diff --git a/scripts/lua/routing.lua b/scripts/lua/routing.lua
index f4d1845..080fca6 100644
--- a/scripts/lua/routing.lua
+++ b/scripts/lua/routing.lua
@@ -44,6 +44,46 @@ local SNAPSHOTTING = os.getenv('SNAPSHOTTING')
 
 local _M = {}
 
+local function setRequestLogs()
+  local requestHeaders = ngx.req.get_headers()
+  for k, v in pairs(requestHeaders) do
+    if k == 'authorization' or k == ngx.ctx.clientSecretName then
+      requestHeaders[k] = '[redacted]'
+    end
+  end
+  ngx.var.requestHeaders = cjson.encode(requestHeaders)
+  ngx.req.read_body()
+  ngx.var.requestBody = ngx.req.get_body_data()
+end
+
+--- Function to read the list of policies and send implementation to the correct backend
+-- @param red redis client instance
+-- @param obj List of policies containing a type and value field. This function reads the type field and routes it appropriately.
+-- @param apiKey optional subscription api key
+local function parsePolicies(dataStore, obj, apiKey)
+  for k, v in pairs (obj) do
+    if v.type == 'reqMapping' then
+      mapping.processMap(v.value)
+    elseif v.type == 'rateLimit' then
+      rateLimit.limit(dataStore, v.value, apiKey)
+    elseif v.type == 'backendRouting' then
+      backendRouting.setDynamicRoute(v.value)
+    end
+  end
+end
+
+--- Given a verb, transforms the backend request to use that method
+-- @param v Verb to set on the backend request
+local function setVerb(v)
+  local allowedVerbs = {'GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'}
+  local verb = string.upper(v)
+  if utils.tableContains(allowedVerbs, verb) then
+    ngx.req.set_method(ngx[utils.concatStrings({"HTTP_", verb})])
+  else
+    ngx.req.set_method(ngx.HTTP_GET)
+  end
+end
+
 --- Main function that handles parsing of invocation details and carries out implementation
 function _M.processCall(dataStore)
   -- Get request headers
@@ -154,7 +194,7 @@ function _M.findResource(dataStore, tenant, path)
   end
 
   local resourceKeys = dataStore:getAllResources(tenant)
-  local result = _M.slowLookup(resourceKeys, tenant, path, redisKey, cfRedisKey)
+  result = _M.slowLookup(resourceKeys, tenant, path, redisKey, cfRedisKey)
 
   if OPTIMIZE > 0 and result ~= nil then
     dataStore:optimizeLookup(tenant, result, path)
@@ -177,6 +217,7 @@ function _M.slowLookup(resourceKeys, tenant, path, redisKey, cfRedisKey)
       return key
     end
   end
+  local cfUrl = ngx.req.get_headers()["x-cf-forwarded-url"]
   if cfUrl ~= nil and cfUrl ~= "" then
     return nil
   end
@@ -242,46 +283,6 @@ function _M.pathParamMatch(key, resourceKey)
   return false
 end
 
---- Function to read the list of policies and send implementation to the correct backend
--- @param red redis client instance
--- @param obj List of policies containing a type and value field. This function reads the type field and routes it appropriately.
--- @param apiKey optional subscription api key
-function parsePolicies(dataStore, obj, apiKey)
-  for k, v in pairs (obj) do
-    if v.type == 'reqMapping' then
-      mapping.processMap(v.value)
-    elseif v.type == 'rateLimit' then
-      rateLimit.limit(dataStore, v.value, apiKey)
-    elseif v.type == 'backendRouting' then
-      backendRouting.setDynamicRoute(v.value)
-    end
-  end
-end
-
---- Given a verb, transforms the backend request to use that method
--- @param v Verb to set on the backend request
-function setVerb(v)
-  local allowedVerbs = {'GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'}
-  local verb = string.upper(v)
-  if utils.tableContains(allowedVerbs, verb) then
-    ngx.req.set_method(ngx[utils.concatStrings({"HTTP_", verb})])
-  else
-    ngx.req.set_method(ngx.HTTP_GET)
-  end
-end
-
-function setRequestLogs()
-  local requestHeaders = ngx.req.get_headers()
-  for k, v in pairs(requestHeaders) do
-    if k == 'authorization' or k == _G.clientSecretName then
-      requestHeaders[k] = '[redacted]'
-    end
-  end
-  ngx.var.requestHeaders = cjson.encode(requestHeaders)
-  ngx.req.read_body()
-  ngx.var.requestBody = ngx.req.get_body_data()
-end
-
 function _M.setResponseLogs()
   ngx.var.responseHeaders = cjson.encode(ngx.resp.get_headers())
   local resp_body = ngx.arg[1]
diff --git a/tools/lua-releng b/tools/lua-releng
new file mode 100755
index 0000000..7560316
--- /dev/null
+++ b/tools/lua-releng
@@ -0,0 +1,104 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+
+use Getopt::Std;
+
+my (@luas, @tests);
+
+my %opts;
+getopts('Lse', \%opts) or die "Usage: lua-releng [-L] [-s] [-e] [files]\n";
+
+my $silent = $opts{s};
+my $stop_on_error = $opts{e};
+my $no_long_line_check = $opts{L};
+
+my $check_lua_ver = "luac -v | awk '{print\$2}'| grep 5.1";
+my $output = `$check_lua_ver`;
+if ($output eq '') {
+    die "ERROR: lua-releng ONLY supports Lua 5.1!\n";
+}
+
+if ($#ARGV != -1) {
+    @luas = @ARGV;
+
+} else {
+    @luas = map glob, qw{ *.lua lib/*.lua lib/*/*.lua lib/*/*/*.lua lib/*/*/*/*.lua lib/*/*/*/*/*.lua };
+    if (-d 't') {
+        @tests = map glob, qw{ t/*.t t/*/*.t t/*/*/*.t };
+    }
+}
+
+for my $f (sort @luas) {
+    process_file($f);
+}
+
+for my $t (@tests) {
+    blank(qq{grep -H -n --color -E '\\--- ?(ONLY|LAST)' $t});
+}
+# p: prints a string to STDOUT appending \n
+# w: prints a string to STDERR appending \n
+# Both respect the $silent value
+sub p { print "$_[0]\n" if (!$silent) }
+sub w { warn  "$_[0]\n" if (!$silent) }
+
+# blank: runs a command and looks at the output. If the output is not
+# blank it is printed (and the program dies if stop_on_error is 1)
+sub blank {
+    my ($command) = @_;
+    if ($stop_on_error) {
+        my $output = `$command`;
+        if ($output ne '') {
+            die $output;
+        }
+    } else {
+        system($command);
+    }
+}
+
+my $version;
+sub process_file {
+    my $file = shift;
+    # Check the sanity of each .lua file
+    open my $in, $file or
+        die "ERROR: Can't open $file for reading: $!\n";
+    my $found_ver;
+    while (<$in>) {
+        my ($ver, $skipping);
+        if (/(?x) (?:_VERSION|version) \s* = .*? ([\d\.]*\d+) (.*? SKIP)?/) {
+            my $orig_ver = $ver = $1;
+            $found_ver = 1;
+            $skipping = $2;
+            $ver =~ s{^(\d+)\.(\d{3})(\d{3})$}{join '.', int($1), int($2), int($3)}e;
+            w("$file: $orig_ver ($ver)");
+            last;
+
+        } elsif (/(?x) (?:_VERSION|version) \s* = \s* ([a-zA-Z_]\S*)/) {
+            w("$file: $1");
+            $found_ver = 1;
+            last;
+        }
+
+        if ($ver and $version and !$skipping) {
+            if ($version ne $ver) {
+                die "$file: $ver != $version\n";
+            }
+        } elsif ($ver and !$version) {
+            $version = $ver;
+        }
+    }
+    if (!$found_ver) {
+        w("WARNING: No \"_VERSION\" or \"version\" field found in `$file`.");
+    }
+    close $in;
+
+    p("Checking use of Lua global variables in file $file...");
+    p("\top no.\tline\tinstruction\targs\t; code");
+    blank("luac -p -l $file | grep -E '[GS]ETGLOBAL' | grep -vE '\\<(require|type|tostring|error|ngx|ndk|jit|setmetatable|getmetatable|string|table|io|os|print|tonumber|math|pcall|xpcall|unpack|pairs|ipairs|assert|module|package|coroutine|[gs]etfenv|next|rawget|rawset|rawlen|select)\\>'");
+    unless ($no_long_line_check) {
+        p("Checking line length exceeding 80...");
+        blank("grep -H -n -E --color '.{81}' $file");
+    }
+}
+ 
\ No newline at end of file