Skip to content

Commit

Permalink
feat(cors): Support private network access (#11523)
Browse files Browse the repository at this point in the history
The Access-Control-Request-Private-Network header in crossing-origin pre-light requests is supported through adding a new parameter private_network which determines whether the Access-Control-Allow-Private-Network header should be carried in the response headers with true as the value.

FTI-5258
  • Loading branch information
liverpool8056 authored Sep 11, 2023
1 parent b0ca424 commit c738e45
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 28 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG/unreleased/kong/11523.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"message": "**CORS**: Support the `Access-Control-Request-Private-Network` header in crossing-origin pre-light requests"
"type": "feature"
"scope": "Plugin"
"prs":
- 11523
"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 @@ -96,4 +96,10 @@ return {
"response_headers",
},
},

[3005000000] = {
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
local rate_limit, 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 3.5.0
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.0", expected_cors)
end)

it("does not remove `config.private_network` from DP nodes that are already compatible", function()
do_assert(utils.uuid(), "3.5.0", cors)
end)
end)
end)
end)
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

1 comment on commit c738e45

@khcp-gha-bot
Copy link

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:c738e45071a5c2899d1d57ace76564d714953e5b
Artifacts available https://github.com/Kong/kong/actions/runs/6146918325

Please sign in to comment.