Skip to content

Commit

Permalink
Merge pull request #6 from infonova/migrate-3.x
Browse files Browse the repository at this point in the history
Migrates the plugin according plugin development documentation
  • Loading branch information
prabagodelrio authored Feb 29, 2024
2 parents db9db57 + 41b7b1b commit 160b1cc
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 143 deletions.
127 changes: 62 additions & 65 deletions handler.lua
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
local constants = require "kong.constants"
local jwt_decoder = require "kong.plugins.jwt.jwt_parser"
local responses = kong.response

local ngx_error = ngx.ERR
local ngx_debug = ngx.DEBUG
local ngx_log = ngx.log

local policy_ALL = 'all'
local policy_ANY = 'any'
Expand Down Expand Up @@ -63,7 +58,6 @@ end
-- @param roles_to_check (array) an array of role names.
-- @param claimed_roles (table) list of roles claimed in JWT
-- @return (boolean) whether a claimed role is part of any of the given roles.

local function role_in_roles_claim(roles_to_check, claimed_roles)
local result = false
for _, role_to_check in ipairs(roles_to_check) do
Expand Down Expand Up @@ -98,89 +92,92 @@ local function split(str, sep)
return ret
end

function JWTAuthHandler:access(conf)
JWTAuthHandler.super.access(self)

-- get the JWT from the Nginx context
local token = ngx.ctx.authenticated_jwt_token
local function do_authorization(conf)
-- get the JWT from the shared context
local token = kong.ctx.shared.authenticated_jwt_token or kong.ctx.shared.jwt_keycloak_token
if not token then
ngx_log(ngx_error, "[jwt-auth plugin] Cannot get JWT token, add the ",
"JWT plugin to be able to use the JWT-Auth plugin")
return kong.response.exit(403, {
message = "You cannot consume this service"
})
-- return responses.send_HTTP_FORBIDDEN("You cannot consume this service")
kong.log.err("The JWT token cannot be found, make sure that a JWT plugin is enabled")
return false, { status = 403, message = "You cannot consume this service" }
end

-- decode token to get roles claim
local jwt, err = jwt_decoder:new(token)
if err then
-- return false, {status = 401, message = "Bad token; " .. tostring(err)}
return kong.response.exit(401, {
message = "Bad token; " .. tostring(err)
})

local jwt, err = {}
if token then
if type(token) == "table" then
jwt = token
-- check if configured roles claim exists
if not jwt.claims[conf.roles_claim_name] then
return false, { status = 403, message = conf.msg_error_not_roles_claimed }
end
else
-- decode token to get roles claim
jwt, err = jwt_decoder:new(token)
if err then
return false, { status = 401, message = "Bad token; " .. tostring(err) }
end
end
end

local msg_error_all = conf.msg_error_all
local roles = jwt.claims[conf.roles_claim_name]
local roles_cfg = conf.roles

local msg_error_any = conf.msg_error_any
local msg_error_not_roles_claimed = conf.msg_error_not_roles_claimed
local roles_cfg = conf.roles
local claims = jwt.claims
local roles = claims[conf.roles_claim_name]
local roles_table = {}

-- check if no roles claimed..
if not roles then
-- return responses.send_HTTP_FORBIDDEN("You cannot consume this service")
return kong.response.exit(403, {
-- message = "You cannot consume this service"
message = msg_error_not_roles_claimed
})
end

-- if the claim is a string (single role), make it a table
if type(roles) == "string" then
if string.find(roles, ",") then
roles_table = split(roles, ",")

else
table.insert(roles_table, roles)

end
roles = roles_table
end
if type(conf.roles) == "table" then

-- if roles in the config is a string (single role), make it a table
if type(roles_cfg) == "table" then
-- in declarative db-less setup the roles can be separated by a space
if string.find(conf.roles[1], " ") then
conf_roles_table = split(conf.roles[1], " ")
if string.find(roles_cfg[1], " ") then
conf_roles_table = split(roles_cfg[1], " ")
end
if string.find(conf.roles[1], ",") then
conf_roles_table = split(conf.roles[1], ",")
if string.find(roles_cfg[1], ",") then
conf_roles_table = split(roles_cfg[1], ",")
end
if conf_roles_table then
roles_cfg = conf_roles_table
end
conf.roles = conf_roles_table
end
if conf.policy == policy_ANY and not role_in_roles_claim(conf.roles, roles) then
-- return responses.send_HTTP_FORBIDDEN("You cannot consume this service")
return kong.response.exit(403, {
-- message = "You can't use these service"
detail = "The permitted role for this invocation is [" .. table.concat(roles_cfg, ", ") ..
"] and yours role are [" .. table.concat(roles, ", ") .. "]",
message = msg_error_any

})

local err_detail_fmt = "The permitted role for this invocation is [%s] and yours role are [%s]"
if conf.policy == policy_ANY and not role_in_roles_claim(roles_cfg, roles) then
return false, {
status = 403,
message = conf.msg_error_any,
detail = string.format(err_detail_fmt, table.concat(roles_cfg, ", "), table.concat(roles, ", "))
}
end

if conf.policy == policy_ALL and not all_roles_in_roles_claim(conf.roles, roles) then
-- return responses.send_HTTP_FORBIDDEN("You cannot consume this service")
return kong.response.exit(403, {
-- message = "You can't use these service"
detail = "The permitted role for this invocation is [" .. table.concat(roles_cfg, ", ") ..
"] and yours role are [" .. table.concat(roles, ", ") .. "]",
message = msg_error_all
})
if conf.policy == policy_ALL and not all_roles_in_roles_claim(roles_cfg, roles) then
return false, {
status = 403,
message = conf.msg_error_all,
detail = string.format(err_detail_fmt, table.concat(roles_cfg, ", "), table.concat(roles, ", "))
}
end

kong.log.debug("The request was authorized using the JWT claim [" .. conf.roles_claim_name .. "]")
return true
end

function JWTAuthHandler:access(conf)
local ok, err = do_authorization(conf)
if not ok then
if err then
if err.detail then
kong.log.err(err.detail)
end
return kong.response.exit(err.status, err.errors or { message = err.message })
end
return kong.response.exit(500, { message = "An unexpected error occurred during authorization" })
end
end

return JWTAuthHandler
27 changes: 0 additions & 27 deletions kong-plugin-jwt-auth-rbac-0.1.0-1.rockspec

This file was deleted.

Binary file removed kong-plugin-jwt-auth-rbac-0.1.0-1.src.rock
Binary file not shown.
35 changes: 35 additions & 0 deletions kong-plugin-jwt-auth-rbac-0.4.0-1.rockspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
local plugin_name = "jwt-auth-rbac"
local package_name = "kong-plugin-" .. plugin_name
local package_version = "0.4.0"
local rockspec_revision = "1"

local github_account_name = "prabago"
local github_repo_name = package_name
local git_checkout = package_version == "dev" and "master" or package_version

package = package_name
version = package_version .. "-" .. rockspec_revision
supported_platforms = {"linux", "macosx"}

source = {
url = "git+https://github.com/"..github_account_name.."/"..github_repo_name..".git",
branch = git_checkout,
}

description = {
summary = "A Kong plugin to authorize access based on a roles claim",
homepage = "https://"..github_account_name..".github.io/"..github_repo_name,
license = "MIT",
}

dependencies = {
"lua ~> 5",
}

build = {
type = "builtin",
modules = {
["kong.plugins.jwt-auth-rbac.handler"] = "handler.lua",
["kong.plugins.jwt-auth-rbac.schema"] = "schema.lua",
},
}
98 changes: 47 additions & 51 deletions schema.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,52 @@ local typedefs = require "kong.db.schema.typedefs"

return {
name = "jwt-auth-rbac",
fields = {
{
-- this plugin will only be applied to services or routes
consumer = typedefs.no_consumer
},
{
-- this plugin will only run within nginx http module
protocols = typedefs.protocols_http
},
{
config = {
type = "record",
fields = {{
roles = {
type = "array",
elements = {
type = "string"
}
fields = {{
-- this plugin will only be applied to services or routes
consumer = typedefs.no_consumer
}, {
-- this plugin will only run within nginx http module
protocols = typedefs.protocols_http
}, {
config = {
type = "record",
fields = {{
roles = {
type = "array",
elements = {
type = "string"
}
}, {
roles_claim_name = {
type = "string",
default = "roles"
}
}, {
msg_error_any = {
type = "string",
default = "To be able to use this service you must have at least one of the roles configured"
}
}, {
msg_error_all = {
type = "string",
default = "In order to use this service you must match all the roles configured with the associated ones in the JWT token"
}
}, {
msg_error_not_roles_claimed = {
type = "string",
default = "The claim roles are not informed in the JWT token"
}
}, {
policy = {
type = "string",
default = "any",
one_of = {"any", "all"}
}
}}
}
},
entity_checks = {{
at_least_one_of = {"config.roles"}
}}
}
}
}, {
roles_claim_name = {
type = "string",
default = "roles"
}
}, {
msg_error_any = {
type = "string",
default = "To be able to use this service you must have at least one of the roles configured"
}
}, {
msg_error_all = {
type = "string",
default = "In order to use this service you must match all the roles configured with the associated ones in the JWT token"
}
}, {
msg_error_not_roles_claimed = {
type = "string",
default = "The claim roles are not informed in the JWT token"
}
}, {
policy = {
type = "string",
default = "any",
one_of = {"any", "all"}
}
}}
}
}},
entity_checks = {{
at_least_one_of = {"config.roles"}
}}
}

0 comments on commit 160b1cc

Please sign in to comment.