diff --git a/config/default.yml b/config/default.yml index 3964a7ec5..a1b7a5352 100644 --- a/config/default.yml +++ b/config/default.yml @@ -58,9 +58,7 @@ gatekeeper: - header - getParam - basicAuthUsername - api_key_cache: false - pep_host: 127.0.0.1 # ip or hostname of Pep Proxy host - pep_port: 8090 # listen port of Pep Proxy + api_key_cache: true trafficserver: host: 127.0.0.1 port: 14009 @@ -284,12 +282,12 @@ apiSettings: message: The requested URL was not found on this server. api_key_missing: status_code: 403 - code: API_KEY_OR_TOKEN_MISSING - message: No api_key or token was supplied. Get one at {{signup_url}} + code: API_KEY_MISSING + message: No api_key was supplied. Get one at {{signup_url}} api_key_invalid: status_code: 403 - code: API_KEY_OR_TOKEN_INVALID - message: An invalid api_key or token was supplied. Get one at {{signup_url}} + code: API_KEY_INVALID + message: An invalid api_key was supplied. Get one at {{signup_url}} api_key_disabled: status_code: 403 code: API_KEY_DISABLED @@ -300,8 +298,8 @@ apiSettings: message: The api_key supplied has not been verified yet. Please check your e-mail to verify the API key. Contact us at {{contact_url}} for assistance api_key_unauthorized: status_code: 403 - code: API_KEY_OR_TOKEN_UNAUTHORIZED - message: The api_key or token supplied is not authorized to access the given service. Contact us at {{contact_url}} for assistance + code: API_KEY_UNAUTHORIZED + message: The api_key supplied is not authorized to access the given service. Contact us at {{contact_url}} for assistance over_rate_limit: status_code: 429 code: OVER_RATE_LIMIT @@ -370,4 +368,4 @@ ban: message: "Please contact us for assistance." ember_server: port: 14050 -live_reload_port: 14051 \ No newline at end of file + live_reload_port: 14051 diff --git a/src/api-umbrella/proxy/hooks/rewrite.lua b/src/api-umbrella/proxy/hooks/rewrite.lua index d238ea134..af0a2268f 100644 --- a/src/api-umbrella/proxy/hooks/rewrite.lua +++ b/src/api-umbrella/proxy/hooks/rewrite.lua @@ -17,7 +17,6 @@ wait_for_setup() -- ngx.var lookups are apparently somewhat expensive. ngx.ctx.args = ngx_var.args ngx.ctx.arg_api_key = ngx_var.arg_api_key -ngx.ctx.arg_token = ngx_var.arg_token if(config["router"]["match_x_forwarded_host"]) then ngx.ctx.host = ngx_var.http_x_forwarded_host or ngx_var.http_host or ngx_var.host else @@ -25,7 +24,6 @@ else end ngx.ctx.host_normalized = host_normalize(ngx.ctx.host) ngx.ctx.http_x_api_key = ngx_var.http_x_api_key -ngx.ctx.http_x_auth_token = ngx_var.http_x_auth_token ngx.ctx.port = ngx_var.real_port ngx.ctx.protocol = ngx_var.real_scheme ngx.ctx.remote_addr = ngx_var.remote_addr @@ -71,4 +69,4 @@ else else error_handler(api_err) end -end \ No newline at end of file +end diff --git a/src/api-umbrella/proxy/middleware/api_key_validator.lua b/src/api-umbrella/proxy/middleware/api_key_validator.lua index 5c6e691b1..ab1447b32 100644 --- a/src/api-umbrella/proxy/middleware/api_key_validator.lua +++ b/src/api-umbrella/proxy/middleware/api_key_validator.lua @@ -6,47 +6,32 @@ local is_empty = types.is_empty local function resolve_api_key() local api_key_methods = config["gatekeeper"]["api_key_methods"] - local key = {key_value="", key_type="" } + local api_key - -- The api_key variable is a dictionary compose by two elements, the key_value which stores - -- the api_key value or the user token value and the key_type field in where is stored - -- the type of key that was provided by the user, it value could be an api_key or a token. - -- The validation process is made for all the api_key_methods (except basicAuthUsername) - -- declared in the configuration file checking if the user sends an api_key or token - -- Only the header and get_param methods are supported by the token validation. for _, method in ipairs(api_key_methods) do - if method == "header" and ngx.ctx.http_x_api_key then - key.key_value = ngx.ctx.http_x_api_key - key.key_type = "api_key" - elseif ngx.ctx.http_x_auth_token then - key.key_value = ngx.ctx.http_x_auth_token - key.key_type = "token" - elseif method == "getParam" and ngx.ctx.arg_api_key then - key.key_value = ngx.ctx.arg_api_key - key.key_type = "api_key" - elseif ngx.ctx.arg_token then - key.key_value = ngx.ctx.arg_token - key.key_type = "token" - elseif method == "basicAuthUsername" and ngx.ctx.remote_user then - key.key_value = ngx.ctx.remote_user - key.key_type = "api_key" + if method == "header" then + api_key = ngx.ctx.http_x_api_key + elseif method == "getParam" then + api_key = ngx.ctx.arg_api_key + elseif method == "basicAuthUsername" then + api_key = ngx.ctx.remote_user end - if not is_empty(key["key_value"]) then + if not is_empty(api_key) then break end end -- Store the api key for logging. - ngx.ctx.api_key = key["key_value"] + ngx.ctx.api_key = api_key - return key + return api_key end return function(settings) -- Find the API key in the header, query string, or HTTP auth. local api_key = resolve_api_key() - if is_empty(api_key["key_value"]) then + if is_empty(api_key) then if settings and settings["disable_api_key"] then return nil else @@ -62,7 +47,7 @@ return function(settings) -- Store the api key on the user object for easier access (the user object -- doesn't contain it directly, to save memory storage in the lookup table). - user["api_key"] = api_key["key_value"] + user["api_key"] = api_key -- Store user details for logging. ngx.ctx.user_id = user["id"] @@ -91,4 +76,4 @@ return function(settings) end return user -end \ No newline at end of file +end diff --git a/src/api-umbrella/proxy/user_store.lua b/src/api-umbrella/proxy/user_store.lua index 6b943af71..6ca87e4e2 100644 --- a/src/api-umbrella/proxy/user_store.lua +++ b/src/api-umbrella/proxy/user_store.lua @@ -8,33 +8,19 @@ local mongo = require "api-umbrella.utils.mongo" local shcache = require "shcache" local types = require "pl.types" local utils = require "api-umbrella.proxy.utils" -local pep = require "api-umbrella.utils.pep" local cache_computed_settings = utils.cache_computed_settings local is_empty = types.is_empty local function lookup_user(api_key) - local raw_user - local db_err - local pep_err - - -- Checking the field of api_key ["key_type"], if the key_type is api_key - -- the api_key value is checked in the database and retrieve the user information - -- else if the key_type is token, the token is checked using PEP Proxy and - -- the user information is retrieved - if not api_key["key_type"] or api_key["key_type"] == "api_key" then - raw_user, db_err = mongo.first("api_users", { - query = { - api_key = api_key["key_value"], - }, - }) - elseif api_key["key_type"] == "token" then - raw_user, pep_err = pep.first(config["gatekeeper"]["pep_host"],config["gatekeeper"]["pep_port"],api_key["key_value"]) - end - if pep_err then - ngx.log(ngx.ERR, "failed to autenticate , status code:", pep_err) - elseif db_err then - ngx.log(ngx.ERR, "failed to fetch user from mongodb", db_err) + local raw_user, err = mongo.first("api_users", { + query = { + api_key = api_key, + }, + }) + + if err then + ngx.log(ngx.ERR, "failed to fetch user from mongodb: ", err) elseif raw_user then local user = utils.pick_where_present(raw_user, { "created_at", @@ -50,31 +36,15 @@ local function lookup_user(api_key) -- Ensure IDs get stored as strings, even if Mongo ObjectIds are in use. if raw_user["_id"] and raw_user["_id"]["$oid"] then user["id"] = raw_user["_id"]["$oid"] - elseif raw_user.Nick_Name then - user["id"] = raw_user.Nick_Name - if not raw_user.Email then - user["email"] = raw_user.Nick_Name - else - user["email"] = raw_user.Email - end else - user["id"] = raw_user["_id"] - end - -- If the validation was made using a token, the Nick_Name associate to the token - -- is assigned to the id attribute of the user - if raw_user.Nick_Name then - user["id"] = raw_user.Nick_Name + user["id"] = raw_user["_id"] end -- Invert the array of roles into a hashy table for more optimized -- lookups (so we can just check if the key exists, rather than -- looping over each value). - -- Moreover, in case that the user information have been retrieved using a token validation, - -- the roles associated with the token are stored in user ["roles"] if user["roles"] then user["roles"] = invert_table(user["roles"]) - elseif raw_user.Roles then - user["roles"] = invert_table(raw_user.Roles) end if user["created_at"] and user["created_at"]["$date"] then @@ -133,14 +103,14 @@ function _M.get(api_key) return nil end - user = shared_cache:load(api_key["key_value"]) + user = shared_cache:load(api_key) if user then - local_cache:set(api_key["key_value"], user, 2) + local_cache:set(api_key, user, 2) else - local_cache:set(api_key["key_value"], EMPTY_DATA, 2) + local_cache:set(api_key, EMPTY_DATA, 2) end return user end -return _M \ No newline at end of file +return _M diff --git a/src/api-umbrella/utils/invert_table.lua b/src/api-umbrella/utils/invert_table.lua index 126b8f38e..5d0000f22 100644 --- a/src/api-umbrella/utils/invert_table.lua +++ b/src/api-umbrella/utils/invert_table.lua @@ -1,18 +1,8 @@ return function(table) - local numItems = 0 local inverted = {} for key, value in pairs(table) do - if type(value)=="string" then - inverted[value] = key - else - for k,v in pairs(value) do - numItems = numItems + 1 - end - if numItems > 1 then - value = value["name"] - end - inverted[value] = key - end + inverted[value] = key end + return inverted -end \ No newline at end of file +end diff --git a/src/api-umbrella/utils/pep.lua b/src/api-umbrella/utils/pep.lua deleted file mode 100644 index 33e7119d1..000000000 --- a/src/api-umbrella/utils/pep.lua +++ /dev/null @@ -1,27 +0,0 @@ -local http = require "resty.http" -local cjson = require "cjson" -local _M = {} --- Function to connect with the Pep Proxy service for checking if the token is valid and retrieve --- the user properties. The function takes the PEP Proxy host and port as parameters --- and sends a request with the header X-Auth-Token with the value of the token provided --- by the user. If the token is valid, PEP proxy sends a response with the user information --- asociated to the token, otherwise, it sends a message indicating the result of the --- validation process with his status, 404 , 402, etc. -function _M.first(host, port, token) - local result - local httpc = http.new() - httpc:set_timeout(45000) - httpc:connect(host,port) - local res, err = httpc:request({headers = {["X-Auth-Token"] = token}}) - if res and res.status == 200 then - local body, body_err = res:read_body() - if not body then - return nil, body_err - end - result = cjson.decode(body) - end - - return result, err -end - -return _M \ No newline at end of file