diff options
Diffstat (limited to 'custom/extensions/auth-file.lua')
| -rw-r--r-- | custom/extensions/auth-file.lua | 73 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 file changed, 29 insertions, 44 deletions
diff --git a/custom/extensions/auth-file.lua b/custom/extensions/auth-file.lua index 74a04b6..957bd49 100644 --- a/custom/extensions/auth-file.lua +++ b/custom/extensions/auth-file.lua @@ -11,11 +11,9 @@ -- be the same Lua that cgit was built against. Lua 5.5 will not do, because -- luaossl has no 5.5 build. -- --- Serve cgit over HTTPS and terminate TLS in the web server in front of it. --- The session cookie is marked Secure by default, so a browser only sends it --- back over HTTPS, and on an instance served over plain HTTP with no TLS --- anywhere the cookie never comes back and login appears to loop until --- cookie_insecure below is set. +-- The session cookie is marked Secure by default, so a browser only sends +-- it back over HTTPS. On an instance served over plain HTTP login loops +-- until cookie_insecure below is set. -- -- Two libraries are needed. luaossl provides openssl.rand and openssl.hmac and -- lives at <https://github.com/wahern/luaossl>, and luaposix provides @@ -42,16 +40,10 @@ -- luarocks install luaossl OPENSSL_DIR="$(brew --prefix openssl)" -- luarocks install luaposix -- --- Some distributions package both as well, for example lua-luaossl and --- lua-posix on Debian, and such a package has to be built for the same Lua --- version as cgit. --- --- The cookie carries only a user name and there is no server-side session --- store, so deleting an account does not revoke a cookie already issued until --- it expires, and instances that share a secret file accept each other's --- cookies. The login form carries no CSRF token. Both are acceptable for --- gating read access to a git browser, so weigh them before guarding anything --- more sensitive. +-- There is no server-side session store and no CSRF token, so a deleted +-- account's cookie stays valid until it expires and instances sharing a +-- secret file accept each other's cookies. That is acceptable for gating +-- read access to a git browser, so weigh it before guarding anything more. local sysstat = require("posix.sys.stat") local unistd = require("posix.unistd") @@ -59,7 +51,6 @@ local rand = require("openssl.rand") local hmac = require("openssl.hmac") -- The values that follow are the configuration and are meant to be edited. --- Nothing below them needs changing for ordinary use. -- Accounts live one per line as username:hash. Generate a hash with -- mkpasswd -m sha-512 -R 300000 @@ -73,7 +64,7 @@ local groups_filename = "/etc/cgit-auth/groups" -- Per-repository access lives one per line as reponame:group1,group2 and so -- on. A repository named here is protected and one that is not named is -- public. The repository name has to match exactly, while group and user names --- match whatever their case. +-- match regardless of case. local repos_filename = "/etc/cgit-auth/repos" -- Where the cookie-signing secret is stored, created on first use. It must be @@ -91,8 +82,7 @@ local cookie_name = "cgitauth" -- more tightly. local cookie_path = "/" --- Leave this false so the cookie is marked Secure and only travels over HTTPS. --- Set it true only if cgit is served over plain HTTP with no TLS anywhere. +-- Set this true only if cgit is served over plain HTTP with no TLS anywhere. local cookie_insecure = false -- A throwaway hash of the documented shape, used only to spend the same work @@ -104,9 +94,8 @@ local dummy_hash = "$6$rounds=300000$0000000000000000$" -- open decodes is kept here for the calls that follow. local action, http, cgit, post --- The two lookups below, account_hash and repo_userset, are the only part of --- this script that differs from auth-inline.lua. Replacing them is all it --- takes to keep accounts somewhere else. +-- The two lookups below, account_hash and repo_userset, are the only part +-- of this script that differs from auth-inline.lua. local function trim(s) return (string.gsub(s, "^%s*(.-)%s*$", "%1")) @@ -118,14 +107,12 @@ local function add_names(list, set) end end --- A missing or unreadable users file is not fatal, and neither is a line that --- does not parse, so a broken file turns every login down rather than failing --- the request outright. +-- A missing, unreadable or unparsable users file turns every login down +-- rather than failing the request outright. -- --- The hash is trimmed as well as the name because reading by line strips the --- newline but not a carriage return, so a users file saved with CRLF endings --- would otherwise hand crypt a hash with a trailing \r and fail every login --- with nothing in the log to say why. +-- The hash is trimmed as well as the name because reading by line strips +-- the newline but not a carriage return, so a CRLF users file would hand +-- crypt a hash with a trailing \r and fail every login. function account_hash(user) if user == nil then return nil @@ -224,14 +211,9 @@ local function pattern_escape(s) return (string.gsub(s, "([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1")) end --- The stored token was already URL encoded by secure_value, so it comes back --- verbatim and the write path in set_cookie stays symmetric with this read --- path. Decoding it here would break the signature check for any value --- carrying a percent escape. --- --- The name is escaped because it lands in a pattern. A cookie_name holding a --- magic character, say "cgit-auth", would otherwise read as a pattern and stop --- matching its own cookie while matching names nobody configured. +-- The token comes back still URL encoded by secure_value. Decoding it here +-- would break the signature check for any value carrying a percent escape. +-- The name is escaped because it lands in a Lua pattern. function get_cookie(cookies, name) cookies = string.gsub(";" .. (cookies or "") .. ";", "%s*;%s*", ";") return string.match(cookies, ";" .. pattern_escape(name) .. "=(.-);") @@ -516,18 +498,21 @@ function body() html_attr(secure_value("redirect", target, 0)) html("'>") html("<table>") - html("<tr><td><label for='username'>Username:</label></td><td><input id='username' name='username' autocomplete='username' autofocus></td></tr>") - html("<tr><td><label for='password'>Password:</label></td><td><input id='password' name='password' type='password' autocomplete='current-password'></td></tr>") - html("<tr><td colspan='2'><input value='Login' type='submit'></td></tr>") + html("<tr><td><label for='username'>Username:</label></td><td>") + html("<input id='username' name='username'") + html(" autocomplete='username' autofocus></td></tr>") + html("<tr><td><label for='password'>Password:</label></td><td>") + html("<input id='password' name='password' type='password'") + html(" autocomplete='current-password'></td></tr>") + html("<tr><td colspan='2'>") + html("<input value='Login' type='submit'></td></tr>") html("</table></form>") return 0 end --- cgit calls filter_open with the action name followed by the request fields --- in a fixed order, so they are unpacked here into the tables the functions --- above read. Only a post reaches filter_write, carrying the form body, and --- filter_close is where the action finally runs and answers cgit. +-- filter_open unpacks the action and request fields cgit passes in fixed +-- order, filter_write collects a post body, and filter_close runs the action. local actions = {} actions["authenticate-post"] = authenticate_post |
