diff options
author | Jason A. Donenfeld | 2018-07-15 03:22:12 +0200 |
---|---|---|
committer | Jason A. Donenfeld | 2018-07-15 03:30:57 +0200 |
commit | b73df8098f261ecbd4bc5ba689f9766a1a75f9a0 (patch) | |
tree | aebcaab97994951531547194cf9f51ba353dd4ad /filters/simple-authentication.lua | |
parent | auth-filters: do not crash on nil username (diff) | |
download | cgit-b73df8098f261ecbd4bc5ba689f9766a1a75f9a0.tar.gz cgit-b73df8098f261ecbd4bc5ba689f9766a1a75f9a0.zip |
auth-filters: generate secret securely
This is much better than having the user generate it themselves. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'filters/simple-authentication.lua')
-rw-r--r-- | filters/simple-authentication.lua | 50 |
1 files changed, 42 insertions, 8 deletions
diff --git a/filters/simple-authentication.lua b/filters/simple-authentication.lua index 596c041..bf35632 100644 --- a/filters/simple-authentication.lua +++ b/filters/simple-authentication.lua | |||
@@ -3,7 +3,12 @@ | |||
3 | -- Requirements: | 3 | -- Requirements: |
4 | -- luacrypto >= 0.3 | 4 | -- luacrypto >= 0.3 |
5 | -- <http://mkottman.github.io/luacrypto/> | 5 | -- <http://mkottman.github.io/luacrypto/> |
6 | -- luaposix | ||
7 | -- <https://github.com/luaposix/luaposix> | ||
6 | -- | 8 | -- |
9 | local sysstat = require("posix.sys.stat") | ||
10 | local unistd = require("posix.unistd") | ||
11 | local crypto = require("crypto") | ||
7 | 12 | ||
8 | 13 | ||
9 | -- | 14 | -- |
@@ -31,11 +36,9 @@ local users = { | |||
31 | bob = "ilikelua" | 36 | bob = "ilikelua" |
32 | } | 37 | } |
33 | 38 | ||
34 | -- All cookies will be authenticated based on this secret. Make it something | 39 | -- Set this to a path this script can write to for storing a persistent |
35 | -- totally random and impossible to guess. It should be large. | 40 | -- cookie secret, which should be guarded. |
36 | local secret = "BE SURE TO CUSTOMIZE THIS STRING TO SOMETHING BIG AND RANDOM" | 41 | local secret_filename = "/var/cache/cgit/auth-secret" |
37 | |||
38 | |||
39 | 42 | ||
40 | -- | 43 | -- |
41 | -- | 44 | -- |
@@ -191,7 +194,38 @@ end | |||
191 | -- | 194 | -- |
192 | -- | 195 | -- |
193 | 196 | ||
194 | local crypto = require("crypto") | 197 | local secret = nil |
198 | |||
199 | -- Loads a secret from a file, creates a secret, or returns one from memory. | ||
200 | function get_secret() | ||
201 | if secret ~= nil then | ||
202 | return secret | ||
203 | end | ||
204 | local secret_file = io.open(secret_filename, "r") | ||
205 | if secret_file == nil then | ||
206 | local old_umask = sysstat.umask(63) | ||
207 | local temporary_filename = secret_filename .. ".tmp." .. crypto.hex(crypto.rand.bytes(16)) | ||
208 | local temporary_file = io.open(temporary_filename, "w") | ||
209 | if temporary_file == nil then | ||
210 | os.exit(177) | ||
211 | end | ||
212 | temporary_file:write(crypto.hex(crypto.rand.bytes(32))) | ||
213 | temporary_file:close() | ||
214 | unistd.link(temporary_filename, secret_filename) -- Intentionally fails in the case that another process is doing the same. | ||
215 | unistd.unlink(temporary_filename) | ||
216 | sysstat.umask(old_umask) | ||
217 | secret_file = io.open(secret_filename, "r") | ||
218 | end | ||
219 | if secret_file == nil then | ||
220 | os.exit(177) | ||
221 | end | ||
222 | secret = secret_file:read() | ||
223 | secret_file:close() | ||
224 | if secret:len() ~= 64 then | ||
225 | os.exit(177) | ||
226 | end | ||
227 | return secret | ||
228 | end | ||
195 | 229 | ||
196 | -- Returns value of cookie if cookie is valid. Otherwise returns nil. | 230 | -- Returns value of cookie if cookie is valid. Otherwise returns nil. |
197 | function validate_value(expected_field, cookie) | 231 | function validate_value(expected_field, cookie) |
@@ -231,7 +265,7 @@ function validate_value(expected_field, cookie) | |||
231 | end | 265 | end |
232 | 266 | ||
233 | -- Lua hashes strings, so these comparisons are time invariant. | 267 | -- Lua hashes strings, so these comparisons are time invariant. |
234 | if hmac ~= crypto.hmac.digest("sha256", field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt, secret) then | 268 | if hmac ~= crypto.hmac.digest("sha256", field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt, get_secret()) then |
235 | return nil | 269 | return nil |
236 | end | 270 | end |
237 | 271 | ||
@@ -256,7 +290,7 @@ function secure_value(field, value, expiration) | |||
256 | value = url_encode(value) | 290 | value = url_encode(value) |
257 | field = url_encode(field) | 291 | field = url_encode(field) |
258 | authstr = field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt | 292 | authstr = field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt |
259 | authstr = authstr .. "|" .. crypto.hmac.digest("sha256", authstr, secret) | 293 | authstr = authstr .. "|" .. crypto.hmac.digest("sha256", authstr, get_secret()) |
260 | return authstr | 294 | return authstr |
261 | end | 295 | end |
262 | 296 | ||