Skip to content

Commit 4bc39d0

Browse files
committed
a number of changes to read session from http authorization basic header
make the hmac part of the encryption key so the server can only decrypt the session data when the client provides the hmac during a request dont update session expiration when opening a session so the ttl can reflect the openidc token expiration allow disabling hmac check for use with openidc basic_auth_legacy -- relies on using hmac as encryption key to validate session credentials remove cookie storage driver as these changes were only designed and tested with server side storage (redis in particular) in mind
1 parent a7e28d0 commit 4bc39d0

File tree

6 files changed

+86
-284
lines changed

6 files changed

+86
-284
lines changed

lib/resty/session.lua

Lines changed: 79 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ local function prequire(prefix, package, default)
4040
end
4141

4242
local function setcookie(session, value, expires)
43+
if session.basic then
44+
return true
45+
end
46+
4347
if ngx.headers_sent then return nil, "Attempt to set session cookie after sending out response headers." end
4448
local c = session.cookie
4549
local i = 3
@@ -130,6 +134,23 @@ local function setcookie(session, value, expires)
130134
return true
131135
end
132136

137+
local function isEmpty(s)
138+
return s == nil or s == ''
139+
end
140+
141+
local function getbasic(session)
142+
-- extract the session credentials from basic authorization header
143+
local user, pass = var.remote_user, var.remote_passwd
144+
if isEmpty(user) or isEmpty(pass) then
145+
return
146+
end
147+
148+
ngx.log(ngx.DEBUG, "basic credentials, user: ", user, " password: ", pass)
149+
ngx.log(ngx.DEBUG, "session.cookie.lifetime = ", session.cookie.lifetime)
150+
151+
return session.encoder.encode(user) .. "|" .. time() + session.cookie.lifetime .. "|" .. (session.raw_hmac == true and session.encoder.encode(pass) or pass)
152+
end
153+
133154
local function getcookie(session, i)
134155
local name = session.name
135156
local n = { "cookie_", name }
@@ -151,21 +172,43 @@ local function save(session, close)
151172
session.expires = time() + session.cookie.lifetime
152173
local i, e, s = session.id, session.expires, session.storage
153174
local k = hmac(session.secret, i)
175+
if not session.data.hmacsalt then
176+
session.data.hmacsalt = ngx.encode_base64(require('resty.session.identifiers.random')({}))
177+
end
178+
ngx.log(ngx.DEBUG, "session.data.hmacsalt = ", session.data.hmacsalt)
154179
local d = session.serializer.serialize(session.data)
155180
local dkey
156181
if session.data.id_token ~= nil and session.data.id_token.sub ~= nil and session.data.id_token.sub ~= "" then
157182
ngx.log(ngx.DEBUG, "using session.data.id_token.sub in place of d in hmac: ", session.data.id_token.sub)
158183
dkey = session.data.id_token.sub
159184
end
160-
local h = hmac(k, concat{ i, e, dkey or d, session.key })
161-
local cookie, err = s:save(i, e, session.cipher:encrypt(d, k, i, session.key), h, close)
185+
local h = hmac(session.data.hmacsalt .. k, concat{ i, dkey or d, session.key })
186+
session.hmac = h
187+
local cryptkey
188+
if session.check.hmac == false and session.basic then
189+
cryptkey = hmac(k, ngx.var.remote_passwd)
190+
else
191+
cryptkey = hmac(k, h)
192+
end
193+
local d = session.cipher:encrypt(d, cryptkey, i, session.key)
194+
ngx.log(ngx.DEBUG, "i = ", ngx.encode_base64(i))
195+
ngx.log(ngx.DEBUG, "e = ", e, " session.cookie.lifetime = ", session.cookie.lifetime)
196+
ngx.log(ngx.DEBUG, "d = ", ngx.encode_base64(d))
197+
ngx.log(ngx.DEBUG, "h = ", ngx.encode_base64(h))
198+
ngx.log(ngx.DEBUG, "k = ", ngx.encode_base64(k))
199+
ngx.log(ngx.DEBUG, "cryptkey = " .. ngx.encode_base64(cryptkey))
200+
local cookie, err = s:save(i, e, d, h, close)
162201
if cookie then
163202
return setcookie(session, cookie)
164203
end
165204
return nil, err
166205
end
167206

168207
local function regenerate(session, flush)
208+
if session.basic then
209+
return true
210+
end
211+
169212
local i = session.present and session.id
170213
session.id = session:identifier()
171214
if flush then
@@ -183,7 +226,7 @@ local function init()
183226
defaults = {
184227
name = var.session_name or "session",
185228
identifier = var.session_identifier or "random",
186-
storage = var.session_storage or "cookie",
229+
storage = var.session_storage or "redis",
187230
serializer = var.session_serializer or "json",
188231
encoder = var.session_encoder or "base64",
189232
cipher = var.session_cipher or "aes",
@@ -201,7 +244,8 @@ local function init()
201244
ssi = enabled(var.session_check_ssi or false),
202245
ua = enabled(var.session_check_ua or true),
203246
scheme = enabled(var.session_check_scheme or true),
204-
addr = enabled(var.session_check_addr or false)
247+
addr = enabled(var.session_check_addr or false),
248+
hmac = enabled(var.session_check_hmac or true)
205249
}
206250
}
207251
defaults.secret = var.session_secret or secret
@@ -228,8 +272,10 @@ function session.new(opts)
228272
local g, h = prequire("resty.session.serializers.", y.serializer or z.serializer, "json")
229273
local i, j = prequire("resty.session.encoders.", y.encoder or z.encoder, "base64")
230274
local k, l = prequire("resty.session.ciphers.", y.cipher or z.cipher, "aes")
231-
local m, n = prequire("resty.session.storage.", y.storage or z.storage, "cookie")
275+
local m, n = prequire("resty.session.storage.", y.storage or z.storage, "redis")
232276
local self = {
277+
basic = ifnil(y.basic, false),
278+
raw_hmac = ifnil(y.raw_hmac, false),
233279
name = y.name or z.name,
234280
identifier = e,
235281
serializer = g,
@@ -250,14 +296,16 @@ function session.new(opts)
250296
ssi = ifnil(c.ssi, d.ssi),
251297
ua = ifnil(c.ua, d.ua),
252298
scheme = ifnil(c.scheme, d.scheme),
253-
addr = ifnil(c.addr, d.addr)
299+
addr = ifnil(c.addr, d.addr),
300+
hmac = ifnil(c.hmac, d.hmac)
254301
}
255302
}
256303
if y[f] and not self[f] then self[f] = y[f] end
257304
if y[h] and not self[h] then self[h] = y[h] end
258305
if y[j] and not self[j] then self[j] = y[j] end
259306
if y[l] and not self[l] then self[l] = y[l] end
260307
if y[n] and not self[n] then self[n] = y[n] end
308+
self.ciphertype = l
261309
self.cipher = k.new(self)
262310
self.storage = m.new(self)
263311
return setmetatable(self, session)
@@ -309,19 +357,31 @@ function session.open(opts)
309357
scheme
310358
}
311359
self.opened = true
312-
local cookie = getcookie(self)
360+
-- require aes storage cipher when self.check.hmac is false (otherwise there is nothing left to validate the session)
361+
if self.check.hmac == false and self.ciphertype ~= "aes" then
362+
ngx.log(ngx.ERR, "aes cipher required when check.hmac is disabled, the cipher is: ", self.ciphertype)
363+
return self, false
364+
end
365+
local cookie
366+
if self.basic then
367+
cookie = getbasic(self)
368+
else
369+
cookie = getcookie(self)
370+
end
313371
if cookie then
314372
ngx.log(ngx.DEBUG, "cookie present: ", cookie)
315373
local i, e, d, h = self.storage:open(cookie, self.cookie.lifetime)
316-
if i and e and e > time() and d and h then
374+
if i and tonumber(e) and d and h then
317375
ngx.log(ngx.DEBUG, "cookie session data retrieved")
318376
ngx.log(ngx.DEBUG, "i: " .. ngx.encode_base64(i))
319377
ngx.log(ngx.DEBUG, "e: " .. e .. " (time: " .. time() .. ")")
320378
ngx.log(ngx.DEBUG, "d: " .. ngx.encode_base64(d))
321379
ngx.log(ngx.DEBUG, "h: " .. ngx.encode_base64(h))
322380
local k = hmac(self.secret, i)
323381
ngx.log(ngx.DEBUG, "k: " .. ngx.encode_base64(k))
324-
d = self.cipher:decrypt(d, k, i, self.key)
382+
local cryptkey = hmac(k, h)
383+
ngx.log(ngx.DEBUG, "cryptkey: " .. ngx.encode_base64(cryptkey))
384+
d = self.cipher:decrypt(d, cryptkey, i, self.key)
325385
local dkey, ds = nil, d
326386
if d then
327387
ngx.log(ngx.DEBUG, "d decrypted: " .. d)
@@ -330,13 +390,18 @@ function session.open(opts)
330390
ngx.log(ngx.DEBUG, "using d.id_token.sub in place of d in hmac: ", d.id_token.sub)
331391
dkey = d.id_token.sub
332392
end
393+
ngx.log(ngx.DEBUG, "d.hmacsalt: ", d.hmacsalt)
394+
else
395+
ngx.log(ngx.DEBUG, "decryption failed")
333396
end
334-
if ds and hmac(k, concat{ i, e, dkey or ds, self.key }) == h then
397+
if ds and (self.check.hmac == false or hmac(d.hmacsalt .. k, concat{ i, dkey or ds, self.key }) == h) then
335398
self.id = i
336399
self.expires = e
337400
self.data = type(d) == "table" and d or {}
338401
self.present = true
339402
return self, true
403+
elseif d then
404+
ngx.log(ngx.DEBUG, "hmac validation failed")
340405
end
341406
end
342407
end
@@ -394,6 +459,10 @@ function session:destroy()
394459
end
395460

396461
function session:hide()
462+
if session.basic then
463+
return true
464+
end
465+
397466
local cookies = var.http_cookie
398467
if not cookies then
399468
return

lib/resty/session/storage/cookie.lua

Lines changed: 0 additions & 47 deletions
This file was deleted.

0 commit comments

Comments
 (0)