Skip to content

Commit

Permalink
fix(core): do not accept invalid regex pattern when validating the `r…
Browse files Browse the repository at this point in the history
…oute` entity

Fix FTI-5403

---------

Co-authored-by: Guilherme Salazar <[email protected]>
Co-authored-by: Qi <[email protected]>
  • Loading branch information
3 people authored Jun 20, 2024
1 parent 116f017 commit b5f2fd2
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
message: Fixed an issue where the `route` entity would accept an invalid regex pattern if the `router_flavor` is `traditional` or `traditional_compatible`. Now, the invalid regex pattern for matching the value of request headers will not be accepted when creating the `route` entity.
type: bugfix
scope: Core
4 changes: 4 additions & 0 deletions kong/db/schema/entities/routes.lua
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,10 @@ local routes = {
},
},
},
values = {
type = "array",
elements = typedefs.regex_or_plain_pattern,
}
} },

{ regex_priority = { description = "A number used to choose which route resolves a given request when several routes match it using regexes simultaneously.", type = "integer", default = 0 }, },
Expand Down
58 changes: 41 additions & 17 deletions kong/db/schema/typedefs.lua
Original file line number Diff line number Diff line change
Expand Up @@ -497,36 +497,54 @@ local function validate_host_with_wildcards(host)
return typedefs.host_with_optional_port.custom_validator(no_wildcards)
end

local function validate_path_with_regexes(path)

local function is_regex_pattern(pattern)
return pattern:sub(1, 1) == "~"
end


local function is_valid_regex_pattern(pattern)
local regex = pattern:sub(2) -- remove the leading "~"
-- the value will be interpreted as a regex by the router; but is it a
-- valid one? Let's dry-run it with the same options as our router.
local _, _, err = ngx.re.find("", regex, "aj")
if err then
return nil,
string.format("invalid regex: '%s' (PCRE returned: %s)",
regex, err)
end

return true
end


local function validate_path_with_regexes(path)
local ok, err, err_code = typedefs.path.custom_validator(path)

if err_code == "percent" then
return ok, err, err_code
end

if path:sub(1, 1) ~= "~" then
-- prefix matching. let's check if it's normalized form
local normalized = normalize(path, true)
if path ~= normalized then
return nil, "non-normalized path, consider use '" .. normalized .. "' instead"
end
if is_regex_pattern(path) then
return is_valid_regex_pattern(path)
end

return true
-- prefix matching. let's check if it's normalized form
local normalized = normalize(path, true)
if path ~= normalized then
return nil, "non-normalized path, consider use '" .. normalized .. "' instead"
end

path = path:sub(2)
return true
end

-- the value will be interpreted as a regex by the router; but is it a
-- valid one? Let's dry-run it with the same options as our router.
local _, _, err = ngx.re.find("", path, "aj")
if err then
return nil,
string.format("invalid regex: '%s' (PCRE returned: %s)",
path, err)

local function validate_regex_or_plain_pattern(pattern)
if not is_regex_pattern(pattern) then
return true
end

return true
return is_valid_regex_pattern(pattern)
end


Expand Down Expand Up @@ -628,6 +646,12 @@ typedefs.headers = Schema.define {
description = "A map of header names to arrays of header values."
}

typedefs.regex_or_plain_pattern = Schema.define {
type = "string",
custom_validator = validate_regex_or_plain_pattern,
description = "A string representing a regex or plain pattern."
}

typedefs.no_headers = Schema.define(typedefs.headers { eq = null, description = "A null value representing no headers." })

typedefs.semantic_version = Schema.define {
Expand Down
11 changes: 11 additions & 0 deletions spec/01-unit/01-db/01-schema/06-routes_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,17 @@ describe("routes schema (flavor = " .. flavor .. ")", function()
assert.falsy(ok)
assert.equal("length must be at least 1", err.headers[1])
end)

it("value must be a plain pattern or a valid regex pattern", function()
local route = {
headers = { location = { "~[" } },
protocols = { "http" },
}

local ok, err = Routes:validate(route)
assert.falsy(ok)
assert.match("invalid regex", err.headers[1])
end)
end)

describe("methods attribute", function()
Expand Down

1 comment on commit b5f2fd2

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bazel Build

Docker image available kong/kong:b5f2fd2b5dff689b8bc490afb8a8004b63d965e6
Artifacts available https://github.com/Kong/kong/actions/runs/9593223875

Please sign in to comment.