Skip to content

Commit

Permalink
refactor(basic-auth) remove kong.tools.* dependency from basic-auth p…
Browse files Browse the repository at this point in the history
…lugin
  • Loading branch information
bungle committed Oct 19, 2018
1 parent d18e1a5 commit 561245c
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 54 deletions.
110 changes: 70 additions & 40 deletions kong/plugins/basic-auth/access.lua
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
local crypto = require "kong.plugins.basic-auth.crypto"
local constants = require "kong.constants"
local responses = require "kong.tools.responses"

local ngx_set_header = ngx.req.set_header
local ngx_get_headers = ngx.req.get_headers
local ngx_re_match = ngx.re.match

local decode_base64 = ngx.decode_base64
local re_gmatch = ngx.re.gmatch
local re_match = ngx.re.match
local kong = kong


local realm = 'Basic realm="' .. _KONG._NAME .. '"'


local _M = {}


Expand All @@ -19,35 +22,34 @@ local _M = {}
-- @param {table} conf Plugin config
-- @return {string} public_key
-- @return {string} private_key
local function retrieve_credentials(request, header_name, conf)
local function retrieve_credentials(header_name, conf)
local username, password
local authorization_header = request.get_headers()[header_name]
local authorization_header = kong.request.get_header(header_name)

if authorization_header then
local iterator, iter_err = ngx.re.gmatch(authorization_header, "\\s*[Bb]asic\\s*(.+)")
local iterator, iter_err = re_gmatch(authorization_header, "\\s*[Bb]asic\\s*(.+)")
if not iterator then
ngx.log(ngx.ERR, iter_err)
kong.log.err(iter_err)
return
end

local m, err = iterator()
if err then
ngx.log(ngx.ERR, err)
kong.log.err(err)
return
end

if m and m[1] then
local decoded_basic = ngx.decode_base64(m[1])
local decoded_basic = decode_base64(m[1])
if decoded_basic then
local basic_parts, err = ngx_re_match(decoded_basic,
"([^:]+):(.*)", "oj")
local basic_parts, err = re_match(decoded_basic, "([^:]+):(.*)", "oj")
if err then
ngx.log(ngx.ERR, err)
kong.log.err(err)
return
end

if not basic_parts then
ngx.log(ngx.ERR, "[basic-auth] header has unrecognized format")
kong.log.err("header has unrecognized format")
return
end

Expand All @@ -58,7 +60,7 @@ local function retrieve_credentials(request, header_name, conf)
end

if conf.hide_credentials then
request.clear_header(header_name)
kong.service.request.clear_header(header_name)
end

return username, password
Expand All @@ -71,8 +73,9 @@ end
local function validate_credentials(credential, given_password)
local digest, err = crypto.encrypt(credential.consumer.id, given_password)
if err then
ngx.log(ngx.ERR, "[basic-auth] " .. err)
kong.log.err(err)
end

return credential.password == digest
end

Expand All @@ -94,8 +97,10 @@ local function load_credential_from_db(username)
load_credential_into_memory,
username)
if err then
return responses.send_HTTP_INTERNAL_SERVER_ERROR(err)
kong.log.err(err)
return kong.response.exit(500, { message = "An unexpected error occurred" })
end

return credential
end

Expand All @@ -111,42 +116,54 @@ local function load_consumer_into_memory(consumer_id, anonymous)
end

local function set_consumer(consumer, credential)
ngx_set_header(constants.HEADERS.CONSUMER_ID, consumer.id)
ngx_set_header(constants.HEADERS.CONSUMER_CUSTOM_ID, consumer.custom_id)
ngx_set_header(constants.HEADERS.CONSUMER_USERNAME, consumer.username)
ngx.ctx.authenticated_consumer = consumer
kong.service.request.set_header(constants.HEADERS.CONSUMER_ID, consumer.id)
kong.service.request.set_header(constants.HEADERS.CONSUMER_CUSTOM_ID, consumer.custom_id)
kong.service.request.set_header(constants.HEADERS.CONSUMER_USERNAME, consumer.username)

local shared_ctx = kong.ctx.shared
local ngx_ctx = ngx.ctx -- TODO: for bc only

shared_ctx.authenticated_consumer = consumer
ngx_ctx.authenticated_consumer = consumer

if credential then
ngx_set_header(constants.HEADERS.CREDENTIAL_USERNAME, credential.username)
ngx.ctx.authenticated_credential = credential
ngx_set_header(constants.HEADERS.ANONYMOUS, nil) -- in case of auth plugins concatenation
shared_ctx.authenticated_credential = credential
ngx_ctx.authenticated_credential = credential

kong.service.request.set_header(constants.HEADERS.CREDENTIAL_USERNAME, credential.username)
kong.service.request.clear_header(constants.HEADERS.ANONYMOUS)

else
ngx_set_header(constants.HEADERS.ANONYMOUS, true)
kong.service.request.set_header(constants.HEADERS.ANONYMOUS, true)
end

end

local function do_authentication(conf)
-- If both headers are missing, return 401
local headers = ngx_get_headers()
if not (headers["authorization"] or headers["proxy-authorization"]) then
ngx.header["WWW-Authenticate"] = realm
return false, {status = 401}
if not (kong.request.get_header("authorization") or kong.request.get_header("proxy-authorization")) then
return false, {
status = 401,
message = "Unauthorized",
headers = {
["WWW-Authenticate"] = realm
}
}
end

local credential
local given_username, given_password = retrieve_credentials(ngx.req, "proxy-authorization", conf)
local given_username, given_password = retrieve_credentials("proxy-authorization", conf)
if given_username then
credential = load_credential_from_db(given_username)
end

-- Try with the authorization header
if not credential then
given_username, given_password = retrieve_credentials(ngx.req, "authorization", conf)
given_username, given_password = retrieve_credentials("authorization", conf)
credential = load_credential_from_db(given_username)
end

if not credential or not validate_credentials(credential, given_password) then
return false, {status = 403, message = "Invalid authentication credentials"}
return false, { status = 403, message = "Invalid authentication credentials" }
end

-- Retrieve consumer
Expand All @@ -155,7 +172,8 @@ local function do_authentication(conf)
load_consumer_into_memory,
credential.consumer.id)
if err then
return responses.send_HTTP_INTERNAL_SERVER_ERROR(err)
kong.log.err(err)
return kong.response.exit(500, { message = "An unexpected error occurred" })
end

set_consumer(consumer, credential)
Expand All @@ -165,11 +183,20 @@ end


function _M.execute(conf)
if conf.anonymous then
local shared_ctx = kong.ctx.shared
if shared_ctx.authenticated_credential then
-- we're already authenticated, and we're configured for using anonymous,
-- hence we're in a logical OR between auth methods and we're already done.
return
end

if ngx.ctx.authenticated_credential and conf.anonymous then
-- we're already authenticated, and we're configured for using anonymous,
-- hence we're in a logical OR between auth methods and we're already done.
return
local ngx_ctx = ngx.ctx -- TODO: for bc only
if ngx_ctx.authenticated_credential then
-- we're already authenticated, and we're configured for using anonymous,
-- hence we're in a logical OR between auth methods and we're already done.
return
end
end

local ok, err = do_authentication(conf)
Expand All @@ -181,11 +208,14 @@ function _M.execute(conf)
load_consumer_into_memory,
conf.anonymous, true)
if err then
return responses.send_HTTP_INTERNAL_SERVER_ERROR(err)
kong.log.err(err)
return kong.response.exit(500, { message = "An unexpected error occurred" })
end

set_consumer(consumer, nil)

else
return responses.send(err.status, err.message)
return kong.response.exit(err.status, { message = err.message }, err.headers)
end
end
end
Expand Down
14 changes: 8 additions & 6 deletions kong/plugins/basic-auth/api.lua
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
local endpoints = require "kong.api.endpoints"
local responses = require "kong.tools.responses"


local kong = kong
local credentials_schema = kong.db.basicauth_credentials.schema
local consumers_schema = kong.db.consumers.schema


return {
["/consumers/:consumers/basic-auth"] = {
schema = credentials_schema,
Expand All @@ -19,13 +20,13 @@ return {
["/consumers/:consumers/basic-auth/:basicauth_credentials"] = {
schema = credentials_schema,
methods = {
before = function(self, db, helpers)
before = function(self, db)
local consumer, _, err_t = endpoints.select_entity(self, db, consumers_schema)
if err_t then
return endpoints.handle_error(err_t)
end
if not consumer then
return responses.send_HTTP_NOT_FOUND()
return kong.response.exit(404, { message = "Not found" })
end

self.consumer = consumer
Expand All @@ -37,17 +38,18 @@ return {

if self.req.cmd_mth ~= "PUT" then
if not cred or cred.consumer.id ~= consumer.id then
return responses.send_HTTP_NOT_FOUND()
return kong.response.exit(404, { message = "Not found" })
end

self.basicauth_credential = cred
self.params.basicauth_credentials = cred.id
end
end,

GET = endpoints.get_entity_endpoint(credentials_schema),
PUT = function(self, db, helpers)
PUT = function(self, ...)
self.args.post.consumer = { id = self.consumer.id }
return endpoints.put_entity_endpoint(credentials_schema)(self, db, helpers)
return endpoints.put_entity_endpoint(credentials_schema)(self, ...)
end,
PATCH = endpoints.patch_entity_endpoint(credentials_schema),
DELETE = endpoints.delete_entity_endpoint(credentials_schema),
Expand Down
2 changes: 1 addition & 1 deletion kong/plugins/basic-auth/basicauth_credentials.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
local crypto = require "kong.plugins.basic-auth.crypto"
local utils = require "kong.tools.utils"
local utils = require "kong.tools.utils"


local encrypt_password = function(self, cred_id_or_username, cred)
Expand Down
12 changes: 7 additions & 5 deletions kong/plugins/basic-auth/crypto.lua
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
-- Module to encrypt the basic-auth credentials password field

local resty_sha1 = require "resty.sha1"
local sha1 = require "resty.sha1"
local to_hex = require "resty.string".to_hex
local format = string.format
local assert = assert


--- Salt the password
-- Password is salted with the credential's consumer_id (long enough, unique)
Expand All @@ -11,16 +11,18 @@ local function salt_password(consumer_id, password)
if password == nil or password == ngx.null then
password = ""
end
return format("%s%s", password, consumer_id)

return password .. consumer_id
end


return {
--- Encrypt the password field credential table
-- @param credential The basic auth credential table
-- @return hash of the salted credential's password
encrypt = function(consumer_id, password)
local salted = salt_password(consumer_id, password)
local digest = resty_sha1:new()
local digest = sha1:new()
assert(digest:update(salted))
return to_hex(digest:final())
end
Expand Down
1 change: 1 addition & 0 deletions kong/plugins/basic-auth/daos.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
local typedefs = require "kong.db.schema.typedefs"


return {
basicauth_credentials = {
dao = "kong.plugins.basic-auth.basicauth_credentials",
Expand Down
8 changes: 6 additions & 2 deletions kong/plugins/basic-auth/handler.lua
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
-- Copyright (C) Kong Inc.

local BasePlugin = require "kong.plugins.base_plugin"
local access = require "kong.plugins.basic-auth.access"


local BasicAuthHandler = BasePlugin:extend()


function BasicAuthHandler:new()
BasicAuthHandler.super.new(self, "basic-auth")
end


function BasicAuthHandler:access(conf)
BasicAuthHandler.super.access(self)
access.execute(conf)
end


BasicAuthHandler.PRIORITY = 1001
BasicAuthHandler.VERSION = "0.1.0"
BasicAuthHandler.VERSION = "0.2.0"


return BasicAuthHandler
1 change: 1 addition & 0 deletions kong/plugins/basic-auth/schema.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
local typedefs = require "kong.db.schema.typedefs"


return {
name = "basic-auth",
fields = {
Expand Down

0 comments on commit 561245c

Please sign in to comment.