Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[backport 3.4] feat(cors): Support private network access (#11523) #12599

Merged
merged 2 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions changelog/unreleased/kong/11523.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"message": "**CORS**: Support the `Access-Control-Request-Private-Network` header in crossing-origin pre-light requests"
"type": "feature"
"scope": "Plugin"
"jiras":
- "FTI-5258"
6 changes: 6 additions & 0 deletions kong/clustering/compat/removed_fields.lua
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,10 @@ return {
"sync_rate",
},
},

[3004003000] = {
cors = {
"private_network",
}
}
}
5 changes: 5 additions & 0 deletions kong/plugins/cors/handler.lua
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,11 @@ function CorsHandler:access(conf)
set_header("Access-Control-Max-Age", tostring(conf.max_age))
end

if conf.private_network and
kong.request.get_header("Access-Control-Request-Private-Network") == 'true' then
set_header("Access-Control-Allow-Private-Network", 'true')
end

return kong.response.exit(HTTP_OK)
end

Expand Down
1 change: 1 addition & 0 deletions kong/plugins/cors/schema.lua
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ return {
}, }, },
{ max_age = { description = "Indicates how long the results of the preflight request can be cached, in `seconds`.", type = "number" }, },
{ credentials = { description = "Flag to determine whether the `Access-Control-Allow-Credentials` header should be sent with `true` as the value.", type = "boolean", required = true, default = false }, },
{ private_network = { description = "Flag to determine whether the `Access-Control-Allow-Private-Network` header should be sent with `true` as the value.", type = "boolean", required = true, default = false }, },
{ preflight_continue = { description = "A boolean value that instructs the plugin to proxy the `OPTIONS` preflight request to the Upstream service.", type = "boolean", required = true, default = false }, },
}, }, },
},
Expand Down
72 changes: 44 additions & 28 deletions spec/02-integration/09-hybrid_mode/09-config-compat_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ end
local function get_plugin(node_id, node_version, name)
local res, err = cluster_client({ id = node_id, version = node_version })
assert.is_nil(err)
assert.is_table(res and res.config and res.config.plugins,
assert.is_table(res and res.config_table and res.config_table.plugins,
"invalid response from clustering client")

local plugin
for _, p in ipairs(res.config.plugins) do
for _, p in ipairs(res.config_table.plugins or {}) do
if p.name == name then
plugin = p
break
Expand Down Expand Up @@ -108,7 +108,7 @@ describe("CP/DP config compat transformations #" .. strategy, function()
end)

describe("plugin config fields", function()
local rate_limit, opentelemetry, zipkin
local rate_limit, opentelemetry, zipkin, cors

lazy_setup(function()
rate_limit = admin.plugins:insert {
Expand All @@ -125,59 +125,75 @@ describe("CP/DP config compat transformations #" .. strategy, function()
-- ]]
},
}

cors = admin.plugins:insert {
name = "cors",
enabled = true,
config = {
-- [[ new fields in 3.4.3
private_network = false
-- ]]
}
}
end)

lazy_teardown(function()
admin.plugins:remove({ id = rate_limit.id })
end)

it("removes new fields before sending them to older DP nodes", function()
local id = utils.uuid()
local plugin = get_plugin(id, "3.0.0", rate_limit.name)
local function do_assert(node_id, node_version, expected_entity)
local plugin = get_plugin(node_id, node_version, expected_entity.name)
assert.same(expected_entity.config, plugin.config)
assert.equals(CLUSTERING_SYNC_STATUS.NORMAL, get_sync_status(node_id))
end

it("removes new fields before sending them to older DP nodes", function()
--[[
For 3.0.x
should not have: error_code, error_message, sync_rate
--]]
local expected = utils.cycle_aware_deep_copy(rate_limit.config)
expected.error_code = nil
expected.error_message = nil
expected.sync_rate = nil
assert.same(expected, plugin.config)
assert.equals(CLUSTERING_SYNC_STATUS.NORMAL, get_sync_status(id))
local expected = utils.cycle_aware_deep_copy(rate_limit)
expected.config.error_code = nil
expected.config.error_message = nil
expected.config.sync_rate = nil
do_assert(utils.uuid(), "3.0.0", expected)


--[[
For 3.2.x
should have: error_code, error_message
should not have: sync_rate
--]]
id = utils.uuid()
plugin = get_plugin(id, "3.2.0", rate_limit.name)
expected = utils.cycle_aware_deep_copy(rate_limit.config)
expected.sync_rate = nil
assert.same(expected, plugin.config)
assert.equals(CLUSTERING_SYNC_STATUS.NORMAL, get_sync_status(id))
expected = utils.cycle_aware_deep_copy(rate_limit)
expected.config.sync_rate = nil
do_assert(utils.uuid(), "3.2.0", expected)


--[[
For 3.3.x,
should have: error_code, error_message
should not have: sync_rate
--]]
id = utils.uuid()
plugin = get_plugin(id, "3.3.0", rate_limit.name)
expected = utils.cycle_aware_deep_copy(rate_limit.config)
expected.sync_rate = nil
assert.same(expected, plugin.config)
assert.equals(CLUSTERING_SYNC_STATUS.NORMAL, get_sync_status(id))
expected = utils.cycle_aware_deep_copy(rate_limit)
expected.config.sync_rate = nil
do_assert(utils.uuid(), "3.3.0", expected)
end)

it("does not remove fields from DP nodes that are already compatible", function()
local id = utils.uuid()
local plugin = get_plugin(id, "3.4.0", rate_limit.name)
assert.same(rate_limit.config, plugin.config)
assert.equals(CLUSTERING_SYNC_STATUS.NORMAL, get_sync_status(id))
do_assert(utils.uuid(), "3.4.0", rate_limit)
end)

describe("compatibility test for cors plugin", function()
it("removes `config.private_network` before sending them to older(less than 3.5.0.0) DP nodes", function()
assert.not_nil(cors.config.private_network)
local expected_cors = utils.cycle_aware_deep_copy(cors)
expected_cors.config.private_network = nil
do_assert(utils.uuid(), "3.4.2", expected_cors)
end)

it("does not remove `config.private_network` from DP nodes that are already compatible", function()
do_assert(utils.uuid(), "3.4.3", cors)
end)
end)

describe("compatibility tests for opentelemetry plugin", function()
Expand Down
28 changes: 28 additions & 0 deletions spec/03-plugins/13-cors/01-access_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,10 @@ for _, strategy in helpers.each_strategy() do
hosts = { "cors12.com" },
})

local route13 = bp.routes:insert({
hosts = { "cors13.com" },
})

local mock_upstream = bp.services:insert {
host = helpers.mock_upstream_hostname,
port = helpers.mock_upstream_port,
Expand Down Expand Up @@ -437,6 +441,16 @@ for _, strategy in helpers.each_strategy() do
}
}

bp.plugins:insert {
name = "cors",
route = { id = route13.id },
config = {
preflight_continue = false,
private_network = true,
origins = { 'allowed-domain.test' }
}
}

bp.plugins:insert {
name = "cors",
route = { id = route_timeout.id },
Expand Down Expand Up @@ -705,6 +719,20 @@ for _, strategy in helpers.each_strategy() do
assert.res_status(200, res)
assert.is_nil(res.headers["Access-Control-Allow-Origin"])
end)

it("support private-network", function()
local res = assert(proxy_client:send {
method = "OPTIONS",
headers = {
["Host"] = "cors13.com",
["Origin"] = "allowed-domain.test",
["Access-Control-Request-Private-Network"] = "true",
["Access-Control-Request-Method"] = "PUT",
}
})
assert.res_status(200, res)
assert.equal("true", res.headers["Access-Control-Allow-Private-Network"])
end)
end)

describe("HTTP method: others", function()
Expand Down
Loading