#!/bin/sh # Checks auth-file.lua and auth-inline.lua, the shipped auth filters, which # differ only in where accounts live. The unit checks meet luaossl and # luaposix with deterministic stand-ins from the harness, and once more the # real libraries wherever they are installed, proving tampered and expired # cookies turned away, header injection stripped, unsafe redirects refused # and the login flows answering as documented. Through cgit itself an # unedited copy protects nothing, with or without the modules. When the # binary's own Lua lacks them a protected repository stays closed, and when # it has them a login opens one. A unit run is one test of some two hundred # checks, and the names of those that failed show only under -v. test_description='Check the shipped auth extensions' CGIT_TEST_NO_CREATE_REPOS=YesPlease . ./setup.sh . "$TEST_OUTPUT_DIRECTORY/extensions/lib.sh" # The unit checks run once more against the real luaossl and luaposix # wherever an interpreter has them and its crypt(3) checks a SHA-512 hash. auth_hash=$(openssl passwd -6 -salt testsalt "open sesame" 2>/dev/null) || auth_hash= # With no standalone Lua the unit checks still count, as skipped. test -z "$interpreters" || test_set_prereq STANDALONE_LUA for lua in ${interpreters:-lua} do for variant in inline file do test_expect_success STANDALONE_LUA "auth-$variant checks under $lua" ' mkdir "unit-$lua-$variant" && "$lua" "$EXT_TEST_DIRECTORY/test-auth.lua" \ "$EXTENSIONS_DIRECTORY/auth-$variant.lua" $variant "$PWD/unit-$lua-$variant" ' done auth_libs=AUTH_LIBS_$(echo "$lua" | tr a-z. A-Z_) if test -n "$auth_hash" && "$lua" -e " require('openssl.hmac') require('openssl.rand') require('posix.sys.stat') assert(require('posix.unistd').crypt('open sesame', '$auth_hash') == '$auth_hash') " >/dev/null 2>&1 then test_set_prereq $auth_libs fi for variant in inline file do test_expect_success "STANDALONE_LUA,$auth_libs" "auth-$variant checks against the real libraries under $lua" ' mkdir "real-$lua-$variant" && "$lua" "$EXT_TEST_DIRECTORY/test-auth.lua" \ "$EXTENSIONS_DIRECTORY/auth-$variant.lua" $variant "$PWD/real-$lua-$variant" "$auth_hash" ' done done # Both filters say a change to the code they share belongs in both, and the # only difference allowed is where each defines trim. test_expect_success 'the two auth filters share their code word for word' ' sed -n "/^-- The url helpers below/,\$p" "$EXTENSIONS_DIRECTORY/auth-file.lua" >file-tail && sed -n "/^-- The url helpers below/,\$p" "$EXTENSIONS_DIRECTORY/auth-inline.lua" >inline-whole && sed "/^-- Lua patterns backtrack/,/^\$/d" inline-whole >inline-tail && test_line_count -gt 300 file-tail && test_cmp file-tail inline-tail && sed -n "/^-- Lua patterns backtrack/,/^end\$/p" "$EXTENSIONS_DIRECTORY/auth-file.lua" >file-trim && sed -n "/^-- Lua patterns backtrack/,/^end\$/p" "$EXTENSIONS_DIRECTORY/auth-inline.lua" >inline-trim && test_line_count = 14 file-trim && test_cmp file-trim inline-trim ' test_expect_success 'create a repository with one commit' ' test_create_repo repos/authy && ( cd repos/authy && echo content >file && git add file && git commit -m "guarded commit" ) ' if test "$CGIT_HAS_LUA" -eq 1 && ! cgit_lua_probe "$PWD/repos/authy/.git" openssl.rand openssl.hmac posix.sys.stat posix.unistd then test_set_prereq CGIT_LUA_NOAUTH say 'cgit lua lacks luaossl or luaposix, expecting protected pages refused' elif test "$CGIT_HAS_LUA" -eq 1 && test -n "$auth_hash" then # A login through cgit also needs the crypt(3) behind cgit's own Lua to # check the hash. cat >crypt-probe.lua <<-EOF function filter_open(...) end function filter_write(str) end function filter_close() if require("posix.unistd").crypt("open sesame", "$auth_hash") == "$auth_hash" then html("CRYPT_PROBE_YES") end return 0 end EOF cgitrc_repo crypt-probe-rc authy "repo.commit-filter=lua:$PWD/crypt-probe.lua" if cgit_rc crypt-probe-rc "url=authy/commit/" | grep CRYPT_PROBE_YES >/dev/null then test_set_prereq CGIT_LUA_AUTH fi fi test_expect_success CGIT_LUA 'point cgit at the unedited auth filter' ' cgitrc_repo cgitrc authy "auth-filter=lua:$EXTENSIONS_DIRECTORY/auth-inline.lua" ' test_expect_success CGIT_LUA 'an unedited copy protects nothing' ' cgit_ok cgitrc "url=authy/log/" >tmp && test_grep ">guarded commit" tmp ' # The secret has to be one not made yet, or a host secret already readable # would sign the form wherever luaposix alone is missing. test_expect_success CGIT_LUA_NOAUTH 'without the modules a protected repository stays closed' ' cat >protect.awk <<-\EOF && /^local secret_filename = / { print "local secret_filename = \"" secret "\""; next } { print } /^local protected_repos = [{]$/ { print "\t[\"authy\"] = { alice = true }," } EOF awk -v secret="$PWD/guarded-secret" -f protect.awk "$EXTENSIONS_DIRECTORY/auth-inline.lua" >guarded.lua && grep "\"authy\"" guarded.lua && grep "guarded-secret" guarded.lua && cgitrc_repo guardedrc authy "auth-filter=lua:$PWD/guarded.lua" && cgit_rc guardedrc "url=authy/log/" >tmp 2>err && ! grep "guarded commit" tmp && grep "

Logins are unavailable" tmp && grep -E "^\[cgit\] .*module .(openssl\.rand|openssl\.hmac|posix\.sys\.stat|posix\.unistd). not found" err ' # A login through cgit itself, from the form to the protected repository's # pages, opened with the cookie it grants and closed again without it. test_expect_success CGIT_LUA_AUTH 'a login through cgit opens a protected repository' ' cat >grant.awk <<-EOF && /^local secret_filename = / { print "local secret_filename = \"$PWD/login-secret\""; next } { print } /^local protected_repos = [{]\$/ { print "\t[\"authy\"] = { alice = true }," } /^local users = [{]\$/ { print "\talice = \"$auth_hash\"," } EOF awk -f grant.awk "$EXTENSIONS_DIRECTORY/auth-inline.lua" >granted.lua && grep "login-secret" granted.lua && grep "testsalt" granted.lua && grep "\"authy\"" granted.lua && cgitrc_repo grantrc authy "auth-filter=lua:$PWD/granted.lua" && (export HTTPS=on && cgit_ok grantrc "url=authy/log/") >form && grep "

post && ( export CGIT_CONFIG="$PWD/grantrc" QUERY_STRING=p=login REQUEST_METHOD=POST \ HTTPS=on CONTENT_LENGTH=${#body} CONTENT_TYPE=application/x-www-form-urlencoded && cgit answer 2>err ) && test_must_be_empty err && grep "^Status: 302" answer && grep "^Location: /authy/log/\$" answer && cookie=$(sed -n "s/^Set-Cookie: \(__Host-cgitauth=[^;]*\);.*/\1/p" answer) && test -n "$cookie" && (export HTTPS=on HTTP_COOKIE="$cookie" && cgit_ok grantrc "url=authy/log/") >tmp && grep ">guarded commit" tmp && (export HTTPS=on && cgit_ok grantrc "url=authy/log/") >tmp && grep "seen exit 1 EOF cgitrc_repo seenrc team/tools.git "auth-filter=exec:$PWD/seen.sh" \ "repo.path=$PWD/repos/authy/.git" "repo.name=tools.git" && echo team/tools.git >expect && cgit_ok seenrc "url=team/tools.git/log/" >tmp && grep ">guarded commit" tmp && test_cmp expect seen && rm seen && cgit_ok seenrc "r=team/tools.git&p=log" >tmp && grep ">guarded commit" tmp && test_cmp expect seen && mkdir -p scan/team && git clone -q --bare repos/authy scan/team/tools.git && cat >scanrc <<-EOF && virtual-root=/ cache-size=0 auth-filter=exec:$PWD/seen.sh section-from-path=1 scan-path=$PWD/scan EOF cgit_ok scanrc "" >tmp && grep ">tools.git" tmp && rm seen && cgit_ok scanrc "url=team/tools.git/log/" >tmp && grep ">guarded commit" tmp && test_cmp expect seen ' # A filter of the test's own turns every visitor away, which needs no Lua. # Until a visitor is let in, the header of a protected repository shows the # site's description in place of its own and no owner, even for a # repository hidden from the index. test_expect_success 'the login page keeps the repository to itself' ' write_script deny.sh <<-\EOF && test "$1" = body && echo "

sign in

" exit 0 EOF cgitrc_repo denyrc authy "root-desc=the whole site" "auth-filter=exec:$PWD/deny.sh" \ "repo.desc=the secret plan" "repo.owner=Mallory Owner" "repo.hide=1" && cgit_ok denyrc "url=authy/log/" >tmp && test_grep "

sign in

" tmp && test_grep "

the whole site

" tmp && test_grep "" tmp && test_grep ! "secret plan" tmp && test_grep ! "Mallory" tmp && write_script letin.sh <<-\EOF && exit 1 EOF sed "s|deny.sh|letin.sh|" denyrc >letinrc && cgit_ok letinrc "url=authy/log/" >tmp && test_grep "secret plan" tmp && test_grep "Mallory Owner" tmp ' # The login page answers in place of whatever page was asked for, so it is # kept out of a search index, whatever the site allows for its own pages. test_expect_success 'the login page asks not to be indexed' ' cgit_ok denyrc "url=authy/log/" >tmp && test_grep "" tmp && { echo "robots=" && cat denyrc } >norobotsrc && cgit_ok norobotsrc "url=authy/log/" >tmp && test_grep "" tmp ' test_done