Skip to content

Commit

Permalink
feat(sessions): store session's meatadata
Browse files Browse the repository at this point in the history
  • Loading branch information
raoxiaoyan committed Dec 16, 2024
1 parent 358fff3 commit 7158135
Show file tree
Hide file tree
Showing 12 changed files with 277 additions and 18 deletions.
4 changes: 4 additions & 0 deletions changelog/unreleased/kong/session_store_metadata.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
message: |
**session**: Added two configurations `hash_subject` and `store_metadata` to store session's metadata.
type: feature
scope: "Plugin"
3 changes: 3 additions & 0 deletions kong-3.10.0-0.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -556,10 +556,13 @@ build = {
["kong.plugins.session.header_filter"] = "kong/plugins/session/header_filter.lua",
["kong.plugins.session.session"] = "kong/plugins/session/session.lua",
["kong.plugins.session.daos"] = "kong/plugins/session/daos.lua",
["kong.plugins.session.daos.session_metadatas"] = "kong/plugins/session/daos/session_metadatas.lua",
["kong.plugins.session.strategies.postgres.session_metadatas"] = "kong/plugins/session/strategies/postgres/session_metadatas.lua",
["kong.plugins.session.storage.kong"] = "kong/plugins/session/storage/kong.lua",
["kong.plugins.session.migrations.000_base_session"] = "kong/plugins/session/migrations/000_base_session.lua",
["kong.plugins.session.migrations.001_add_ttl_index"] = "kong/plugins/session/migrations/001_add_ttl_index.lua",
["kong.plugins.session.migrations.002_320_to_330"] = "kong/plugins/session/migrations/002_320_to_330.lua",
["kong.plugins.session.migrations.003_330_to_3100"] = "kong/plugins/session/migrations/003_330_to_3100.lua",
["kong.plugins.session.migrations"] = "kong/plugins/session/migrations/init.lua",

["kong.plugins.proxy-cache.handler"] = "kong/plugins/proxy-cache/handler.lua",
Expand Down
49 changes: 34 additions & 15 deletions kong/plugins/session/daos.lua
Original file line number Diff line number Diff line change
@@ -1,20 +1,39 @@
local typedefs = require "kong.db.schema.typedefs"


return {
{
primary_key = { "id" },
endpoint_key = "session_id",
name = "sessions",
cache_key = { "session_id" },
ttl = true,
db_export = false,
fields = {
{ id = typedefs.uuid },
{ session_id = { type = "string", unique = true, required = true } },
{ expires = { type = "integer" } },
{ data = { type = "string" } },
{ created_at = typedefs.auto_timestamp_s },
}
local sessions = {
primary_key = { "id" },
endpoint_key = "session_id",
name = "sessions",
cache_key = { "session_id" },
ttl = true,
db_export = false,
fields = {
{ id = typedefs.uuid },
{ session_id = { type = "string", unique = true, required = true } },
{ expires = { type = "integer" } },
{ data = { type = "string" } },
{ created_at = typedefs.auto_timestamp_s },
}
}

local session_metadatas = {
primary_key = { "id" },
name = "session_metadatas",
dao = "kong.plugins.session.daos.session_metadatas",
generate_admin_api = false,
db_export = false,
fields = {
{ id = typedefs.uuid },
{ session = { type = "foreign", reference = "sessions", required = true, on_delete = "cascade" } },
{ sid = { type = "string" } },
{ audience = { type = "string" } },
{ subject = { type = "string" } },
{ created_at = typedefs.auto_timestamp_s },
}
}

return {
sessions,
session_metadatas,
}
11 changes: 11 additions & 0 deletions kong/plugins/session/daos/session_metadatas.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
local session_metadatas = {}

function session_metadatas:select_by_audience_and_subject(audience, subject)
return self.strategy:select_by_audience_and_subject(audience, subject)
end

function session_metadatas:select_by_sid(sid)
return self.strategy:select_by_sid(sid)
end

return session_metadatas
22 changes: 22 additions & 0 deletions kong/plugins/session/migrations/003_330_to_3100.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
return {
postgres = {
up = [[
CREATE TABLE IF NOT EXISTS session_metadatas(
id uuid,
session_id uuid REFERENCES "sessions" ("id") ON DELETE CASCADE,
sid text UNIQUE,
subject text,
audience text,
created_at timestamp WITH TIME ZONE,
PRIMARY KEY (id)
);
DO $$
BEGIN
CREATE INDEX IF NOT EXISTS "session_id_idx" ON "session_metadatas" ("session_id");
EXCEPTION WHEN UNDEFINED_COLUMN THEN
-- Do nothing, accept existing state
END$$;
]],
},
}
1 change: 1 addition & 0 deletions kong/plugins/session/migrations/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ return {
"000_base_session",
"001_add_ttl_index",
"002_320_to_330",
"003_330_to_3100",
}
14 changes: 14 additions & 0 deletions kong/plugins/session/schema.lua
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,20 @@ return {
default = "session_logout"
}
},
{
hash_subject = {
description = "Whether to hash or not the subject when store_metadata is enabled.",
type = "boolean",
default = false
}
},
{
store_metadata = {
description = "Enables or disables to store metadata of sessions.",
type = "boolean",
default = false
}
},
},
shorthand_fields = {
-- TODO: deprecated forms, to be removed in Kong 4.0
Expand Down
2 changes: 2 additions & 0 deletions kong/plugins/session/session.lua
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ function _M.open_session(conf)
remember_absolute_timeout = conf.remember_absolute_timeout,
response_headers = conf.response_headers,
request_headers = conf.request_headers,
hash_subject = conf.hash_subject,
store_metadata = conf.store_metadata,
})
end

Expand Down
32 changes: 29 additions & 3 deletions kong/plugins/session/storage/kong.lua
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,36 @@ local function load_session_from_cache(key)
return kong.cache:get(cache_key, nil, load_session_from_db, key)
end

local function insert_session_metadata(metadata, session)
if not metadata then
return
end

local audiences = metadata.audiences
local subjects = metadata.subjects
local count = #audiences
for i = 1, count do
kong.db.session_metadatas:insert({
sid = session.session_id,
audience = audiences[i],
subject = subjects[i],
session = session,
})
end
end

local function insert_session(key, value, ttl, current_time, old_key, stale_ttl, remember)
local function insert_session(key, value, ttl, current_time, old_key, stale_ttl, metadata, remember)
DATA.session_id = key
DATA.data = value
DATA.expires = current_time + ttl

TTL.ttl = ttl

local insert_ok, insert_err = kong.db.sessions:insert(DATA, TTL)
if not insert_err then
insert_session_metadata(metadata, insert_ok)
end

if not old_key then
return insert_ok, insert_err
end
Expand Down Expand Up @@ -103,11 +124,11 @@ end

function storage:set(name, key, value, ttl, current_time, old_key, stale_ttl, metadata, remember)
if get_phase() == "header_filter" then
timer_at(0, insert_session_timer, key, value, ttl, current_time, old_key, stale_ttl, remember)
timer_at(0, insert_session_timer, key, value, ttl, current_time, old_key, stale_ttl, metadata, remember)
return true
end

return insert_session(key, value, ttl, current_time, old_key, stale_ttl, remember)
return insert_session(key, value, ttl, current_time, old_key, stale_ttl, metadata, remember)
end


Expand Down Expand Up @@ -137,4 +158,9 @@ function storage:delete(name, key, current_time, metadata)
end


function storage:read_metadata(name, audience, subject, current_time)
return kong.db.session_metadatas:select_by_audience_and_subject(audience, subject)
end


return storage
22 changes: 22 additions & 0 deletions kong/plugins/session/strategies/postgres/session_metadatas.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
local fmt = string.format

local session_metadatas = {}

function session_metadatas:select_by_audience_and_subject(audience, subject)
local qs = fmt(
"SELECT * FROM session_metadatas WHERE audience = %s AND subject = %s;",
kong.db.connector:escape_literal(audience),
kong.db.connector:escape_literal(subject))

return kong.db.connector:query(qs, "read")
end

function session_metadatas:select_by_sid(sid)
local qs = fmt(
"SELECT * FROM session_metadatas WHERE sid = %s;",
kong.db.connector:escape_literal(sid))

return kong.db.connector:query(qs, "read")
end

return session_metadatas
120 changes: 120 additions & 0 deletions spec/03-plugins/30-session/02-kong_storage_adapter_spec.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
local helpers = require "spec.helpers"
local cjson = require "cjson"
local sub = string.sub
local sha256_bin = require "kong.tools.sha256".sha256_bin
local encode_base64url = require "ngx.base64".encode_base64url

local function sha256_subject(key)
local subject, err = sha256_bin(key)
if err then
return nil, err
end

return encode_base64url(sub(subject, 1, 16))
end

for _, strategy in helpers.each_strategy() do
describe("Plugin: Session (kong storage adapter) [#" .. strategy .. "]", function()
Expand Down Expand Up @@ -31,6 +42,16 @@ for _, strategy in helpers.each_strategy() do
hosts = {"konghq.test"},
}

local route4 = bp.routes:insert {
paths = { "/metadata1" },
hosts = { "konghq.metadata1" },
}

local route5 = bp.routes:insert {
paths = { "/hash_subject" },
hosts = { "konghq.hash_subject" },
}

assert(bp.plugins:insert {
name = "session",
route = {
Expand Down Expand Up @@ -68,6 +89,33 @@ for _, strategy in helpers.each_strategy() do
}
})

assert(bp.plugins:insert {
name = "session",
route = {
id = route4.id,
},
config = {
storage = "kong",
store_metadata = true,
secret = "ultra top secret session",
response_headers = { "id", "timeout", "audience", "subject" }
}
})

assert(bp.plugins:insert {
name = "session",
route = {
id = route5.id,
},
config = {
storage = "kong",
hash_subject = true,
store_metadata = true,
secret = "ultra top secret session",
response_headers = { "id", "timeout", "audience", "subject" }
}
})

bp.plugins:insert {
name = "ctx-checker",
route = { id = route3.id },
Expand Down Expand Up @@ -117,6 +165,26 @@ for _, strategy in helpers.each_strategy() do
}
}

bp.plugins:insert {
name = "key-auth",
route = {
id = route4.id,
},
config = {
anonymous = anonymous.id
}
}

bp.plugins:insert {
name = "key-auth",
route = {
id = route5.id,
},
config = {
anonymous = anonymous.id
}
}

bp.plugins:insert {
name = "request-termination",
consumer = {
Expand Down Expand Up @@ -330,6 +398,58 @@ for _, strategy in helpers.each_strategy() do
local json = cjson.decode(assert.res_status(200, res))
assert.equal('beatles, ramones', json.headers['x-authenticated-groups'])
end)

it("store metadata", function()
local request = {
method = "GET",
path = "/metadata1",
headers = { host = "konghq.metadata1", },
}

request.headers.apikey = "kong"
client = helpers.proxy_ssl_client()
local res = assert(client:send(request))
assert.response(res).has.status(200)

local sid = res.headers["Session-Id"]
local audience = res.headers["Session-audience"]
local subject = res.headers["Session-subject"]

ngx.sleep(2)
subject = encode_base64url(subject)
audience = encode_base64url(audience)

local session_metadatas = kong.db.session_metadatas:select_by_sid(sid)
local metadata = session_metadatas[1]
assert.equal(subject, metadata.subject)
assert.equal(audience, metadata.audience)
assert.equal(sid, metadata.sid)
end)

it("store metadata with hash_subject", function()
local request = {
method = "GET",
path = "/hash_subject",
headers = { host = "konghq.hash_subject", },
}

request.headers.apikey = "kong"
client = helpers.proxy_ssl_client()
local res = assert(client:send(request))
assert.response(res).has.status(200)

local sid = res.headers["Session-Id"]
local audience = res.headers["Session-audience"]
local subject = res.headers["Session-subject"]
ngx.sleep(2)
subject = sha256_subject(subject)
audience = encode_base64url(audience)
local session_metadatas = kong.db.session_metadatas:select_by_sid(sid)
local metadata = session_metadatas[1]
assert.equal(subject, metadata.subject)
assert.equal(audience, metadata.audience)
assert.equal(sid, metadata.sid)
end)
end)
end)
end
Loading

0 comments on commit 7158135

Please sign in to comment.