Git fork

t5563: refactor for multi-stage authentication

Some HTTP authentication schemes, such as NTLM- and Kerberos-based
options, require more than one round trip to authenticate. Currently,
these can only be supported in libcurl, since Git does not have support
for this in the credential helper protocol.

However, in a future commit, we'll add support for this functionality
into the credential helper protocol and Git itself. Because we don't
really want to implement either NTLM or Kerberos, both of which are
complex protocols, we'll want to test this using a fake credential
authentication scheme. In order to do so, update t5563 and its backend
to allow us to accept multiple sets of credentials and respond with
different behavior in each case.

Since we can now provide any number of possible status codes, provide a
non-specific reason phrase so we don't have to generate a more specific
one based on the response. The reason phrase is mandatory according to
the status-line production in RFC 7230, but clients SHOULD ignore it,
and curl does (except to print it).

Each entry in the authorization and challenge fields contains an ID,
which indicates a corresponding credential and response. If the
response is a 200 status, then we continue to execute git-http-backend.
Otherwise, we print the corresponding status and response. If no ID is
matched, we use the default response with a status of 401.

Note that there is an implicit order to the parameters. The ID is
always first and the creds or response value is always last, and
therefore may contain spaces, equals signs, or other arbitrary data.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>

authored by

brian m. carlson and committed by
Junio C Hamano
37417b77 bd590bde

+66 -47
+13 -4
t/lib-httpd/nph-custom-auth.sh
··· 19 # 20 21 if test -n "$HTTP_AUTHORIZATION" && \ 22 - grep -Fqsx "${HTTP_AUTHORIZATION}" "$VALID_CREDS_FILE" 23 then 24 # Note that although git-http-backend returns a status line, it 25 # does so using a CGI 'Status' header. Because this script is an 26 # No Parsed Headers (NPH) script, we must return a real HTTP 27 # status line. 28 # This is only a test script, so we don't bother to check for 29 # the actual status from git-http-backend and always return 200. 30 - echo 'HTTP/1.1 200 OK' 31 - exec "$GIT_EXEC_PATH"/git-http-backend 32 fi 33 34 echo 'HTTP/1.1 401 Authorization Required' 35 if test -f "$CHALLENGE_FILE" 36 then 37 - cat "$CHALLENGE_FILE" 38 fi 39 echo
··· 19 # 20 21 if test -n "$HTTP_AUTHORIZATION" && \ 22 + grep -Fqs "creds=${HTTP_AUTHORIZATION}" "$VALID_CREDS_FILE" 23 then 24 + idno=$(grep -F "creds=${HTTP_AUTHORIZATION}" "$VALID_CREDS_FILE" | sed -e 's/^id=\([a-z0-9-][a-z0-9-]*\) .*$/\1/') 25 + status=$(sed -ne "s/^id=$idno.*status=\\([0-9][0-9][0-9]\\).*\$/\\1/p" "$CHALLENGE_FILE" | head -n1) 26 # Note that although git-http-backend returns a status line, it 27 # does so using a CGI 'Status' header. Because this script is an 28 # No Parsed Headers (NPH) script, we must return a real HTTP 29 # status line. 30 # This is only a test script, so we don't bother to check for 31 # the actual status from git-http-backend and always return 200. 32 + echo "HTTP/1.1 $status Nonspecific Reason Phrase" 33 + if test "$status" -eq 200 34 + then 35 + exec "$GIT_EXEC_PATH"/git-http-backend 36 + else 37 + sed -ne "s/^id=$idno.*response=//p" "$CHALLENGE_FILE" 38 + echo 39 + exit 40 + fi 41 fi 42 43 echo 'HTTP/1.1 401 Authorization Required' 44 if test -f "$CHALLENGE_FILE" 45 then 46 + sed -ne 's/^id=default.*response=//p' "$CHALLENGE_FILE" 47 fi 48 echo
+53 -43
t/t5563-simple-http-auth.sh
··· 63 64 # Basic base64(alice:secret-passwd) 65 cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && 66 - Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== 67 EOF 68 69 cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && 70 - WWW-Authenticate: Basic realm="example.com" 71 EOF 72 73 test_config_global credential.helper test-helper && ··· 100 101 # Basic base64(alice:secret-passwd) 102 cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && 103 - Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== 104 EOF 105 106 cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && 107 - WWW-Authenticate: Basic realm="example.com" 108 EOF 109 110 test_config_global credential.helper test-helper && ··· 137 138 # Basic base64(alice:secret-passwd) 139 cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && 140 - Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== 141 EOF 142 143 cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && 144 - WWW-Authenticate: Basic realm="example.com" 145 EOF 146 147 test_config_global credential.helper test-helper && ··· 174 175 # Basic base64(alice:secret-passwd) 176 cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && 177 - Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== 178 EOF 179 180 cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && 181 - WWW-Authenticate: FooBar param1="value1" param2="value2" 182 - WWW-Authenticate: Bearer authorize_uri="id.example.com" p=1 q=0 183 - WWW-Authenticate: Basic realm="example.com" 184 EOF 185 186 test_config_global credential.helper test-helper && ··· 214 215 # Basic base64(alice:secret-passwd) 216 cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && 217 - Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== 218 EOF 219 220 cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && 221 - www-authenticate: foobar param1="value1" param2="value2" 222 - WWW-AUTHENTICATE: BEARER authorize_uri="id.example.com" p=1 q=0 223 - WwW-aUtHeNtIcAtE: baSiC realm="example.com" 224 EOF 225 226 test_config_global credential.helper test-helper && ··· 254 255 # Basic base64(alice:secret-passwd) 256 cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && 257 - Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== 258 EOF 259 260 # Note that leading and trailing whitespace is important to correctly 261 # simulate a continuation/folded header. 262 cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && 263 - WWW-Authenticate: FooBar param1="value1" 264 - param2="value2" 265 - WWW-Authenticate: Bearer authorize_uri="id.example.com" 266 - p=1 267 - q=0 268 - WWW-Authenticate: Basic realm="example.com" 269 EOF 270 271 test_config_global credential.helper test-helper && ··· 299 300 # Basic base64(alice:secret-passwd) 301 cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && 302 - Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== 303 EOF 304 305 CHALLENGE="$HTTPD_ROOT_PATH/custom-auth.challenge" && 306 307 # Note that leading and trailing whitespace is important to correctly 308 # simulate a continuation/folded header. 309 - printf "WWW-Authenticate: FooBar param1=\"value1\"\r\n" >"$CHALLENGE" && 310 - printf " \r\n" >>"$CHALLENGE" && 311 - printf " param2=\"value2\"\r\n" >>"$CHALLENGE" && 312 - printf "WWW-Authenticate: Bearer authorize_uri=\"id.example.com\"\r\n" >>"$CHALLENGE" && 313 - printf " p=1\r\n" >>"$CHALLENGE" && 314 - printf " \r\n" >>"$CHALLENGE" && 315 - printf " q=0\r\n" >>"$CHALLENGE" && 316 - printf "WWW-Authenticate: Basic realm=\"example.com\"\r\n" >>"$CHALLENGE" && 317 318 test_config_global credential.helper test-helper && 319 git ls-remote "$HTTPD_URL/custom_auth/repo.git" && ··· 346 347 # Basic base64(alice:secret-passwd) 348 cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && 349 - Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== 350 EOF 351 352 CHALLENGE="$HTTPD_ROOT_PATH/custom-auth.challenge" && 353 354 # Note that leading and trailing whitespace is important to correctly 355 # simulate a continuation/folded header. 356 - printf "WWW-Authenticate: FooBar param1=\"value1\"\r\n" >"$CHALLENGE" && 357 - printf " \r\n" >>"$CHALLENGE" && 358 - printf "\tparam2=\"value2\"\r\n" >>"$CHALLENGE" && 359 - printf "WWW-Authenticate: Basic realm=\"example.com\"" >>"$CHALLENGE" && 360 361 test_config_global credential.helper test-helper && 362 git ls-remote "$HTTPD_URL/custom_auth/repo.git" && ··· 389 390 # Basic base64(a-git-token) 391 cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && 392 - Bearer YS1naXQtdG9rZW4= 393 EOF 394 395 CHALLENGE="$HTTPD_ROOT_PATH/custom-auth.challenge" && 396 397 cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && 398 - WWW-Authenticate: FooBar param1="value1" param2="value2" 399 - WWW-Authenticate: Bearer authorize_uri="id.example.com" p=1 q=0 400 - WWW-Authenticate: Basic realm="example.com" 401 EOF 402 403 test_config_global credential.helper test-helper && ··· 433 434 # Basic base64(a-git-token) 435 cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && 436 - Bearer YS1naXQtdG9rZW4= 437 EOF 438 439 CHALLENGE="$HTTPD_ROOT_PATH/custom-auth.challenge" && 440 441 cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && 442 - WWW-Authenticate: FooBar param1="value1" param2="value2" 443 - WWW-Authenticate: Bearer authorize_uri="id.example.com" p=1 q=0 444 - WWW-Authenticate: Basic realm="example.com" 445 EOF 446 447 test_config_global credential.helper test-helper &&
··· 63 64 # Basic base64(alice:secret-passwd) 65 cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && 66 + id=1 creds=Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== 67 EOF 68 69 cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && 70 + id=1 status=200 71 + id=default response=WWW-Authenticate: Basic realm="example.com" 72 EOF 73 74 test_config_global credential.helper test-helper && ··· 101 102 # Basic base64(alice:secret-passwd) 103 cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && 104 + id=1 creds=Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== 105 EOF 106 107 cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && 108 + id=1 status=200 109 + id=default response=WWW-Authenticate: Basic realm="example.com" 110 EOF 111 112 test_config_global credential.helper test-helper && ··· 139 140 # Basic base64(alice:secret-passwd) 141 cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && 142 + id=1 creds=Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== 143 EOF 144 145 cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && 146 + id=1 status=200 147 + id=default response=WWW-Authenticate: Basic realm="example.com" 148 EOF 149 150 test_config_global credential.helper test-helper && ··· 177 178 # Basic base64(alice:secret-passwd) 179 cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && 180 + id=1 creds=Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== 181 EOF 182 183 cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && 184 + id=1 status=200 185 + id=default response=WWW-Authenticate: FooBar param1="value1" param2="value2" 186 + id=default response=WWW-Authenticate: Bearer authorize_uri="id.example.com" p=1 q=0 187 + id=default response=WWW-Authenticate: Basic realm="example.com" 188 EOF 189 190 test_config_global credential.helper test-helper && ··· 218 219 # Basic base64(alice:secret-passwd) 220 cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && 221 + id=1 creds=Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== 222 EOF 223 224 cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && 225 + id=1 status=200 226 + id=default response=www-authenticate: foobar param1="value1" param2="value2" 227 + id=default response=WWW-AUTHENTICATE: BEARER authorize_uri="id.example.com" p=1 q=0 228 + id=default response=WwW-aUtHeNtIcAtE: baSiC realm="example.com" 229 EOF 230 231 test_config_global credential.helper test-helper && ··· 259 260 # Basic base64(alice:secret-passwd) 261 cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && 262 + id=1 creds=Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== 263 EOF 264 265 # Note that leading and trailing whitespace is important to correctly 266 # simulate a continuation/folded header. 267 cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && 268 + id=1 status=200 269 + id=default response=WWW-Authenticate: FooBar param1="value1" 270 + id=default response= param2="value2" 271 + id=default response=WWW-Authenticate: Bearer authorize_uri="id.example.com" 272 + id=default response= p=1 273 + id=default response= q=0 274 + id=default response=WWW-Authenticate: Basic realm="example.com" 275 EOF 276 277 test_config_global credential.helper test-helper && ··· 305 306 # Basic base64(alice:secret-passwd) 307 cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && 308 + id=1 creds=Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== 309 EOF 310 311 CHALLENGE="$HTTPD_ROOT_PATH/custom-auth.challenge" && 312 313 # Note that leading and trailing whitespace is important to correctly 314 # simulate a continuation/folded header. 315 + printf "id=1 status=200\n" >"$CHALLENGE" && 316 + printf "id=default response=WWW-Authenticate: FooBar param1=\"value1\"\r\n" >>"$CHALLENGE" && 317 + printf "id=default response= \r\n" >>"$CHALLENGE" && 318 + printf "id=default response= param2=\"value2\"\r\n" >>"$CHALLENGE" && 319 + printf "id=default response=WWW-Authenticate: Bearer authorize_uri=\"id.example.com\"\r\n" >>"$CHALLENGE" && 320 + printf "id=default response= p=1\r\n" >>"$CHALLENGE" && 321 + printf "id=default response= \r\n" >>"$CHALLENGE" && 322 + printf "id=default response= q=0\r\n" >>"$CHALLENGE" && 323 + printf "id=default response=WWW-Authenticate: Basic realm=\"example.com\"\r\n" >>"$CHALLENGE" && 324 325 test_config_global credential.helper test-helper && 326 git ls-remote "$HTTPD_URL/custom_auth/repo.git" && ··· 353 354 # Basic base64(alice:secret-passwd) 355 cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && 356 + id=1 creds=Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== 357 EOF 358 359 CHALLENGE="$HTTPD_ROOT_PATH/custom-auth.challenge" && 360 361 # Note that leading and trailing whitespace is important to correctly 362 # simulate a continuation/folded header. 363 + printf "id=1 status=200\n" >"$CHALLENGE" && 364 + printf "id=default response=WWW-Authenticate: FooBar param1=\"value1\"\r\n" >>"$CHALLENGE" && 365 + printf "id=default response= \r\n" >>"$CHALLENGE" && 366 + printf "id=default response=\tparam2=\"value2\"\r\n" >>"$CHALLENGE" && 367 + printf "id=default response=WWW-Authenticate: Basic realm=\"example.com\"" >>"$CHALLENGE" && 368 369 test_config_global credential.helper test-helper && 370 git ls-remote "$HTTPD_URL/custom_auth/repo.git" && ··· 397 398 # Basic base64(a-git-token) 399 cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && 400 + id=1 creds=Bearer YS1naXQtdG9rZW4= 401 EOF 402 403 CHALLENGE="$HTTPD_ROOT_PATH/custom-auth.challenge" && 404 405 cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && 406 + id=1 status=200 407 + id=default response=WWW-Authenticate: FooBar param1="value1" param2="value2" 408 + id=default response=WWW-Authenticate: Bearer authorize_uri="id.example.com" p=1 q=0 409 + id=default response=WWW-Authenticate: Basic realm="example.com" 410 EOF 411 412 test_config_global credential.helper test-helper && ··· 442 443 # Basic base64(a-git-token) 444 cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && 445 + id=1 creds=Bearer YS1naXQtdG9rZW4= 446 EOF 447 448 CHALLENGE="$HTTPD_ROOT_PATH/custom-auth.challenge" && 449 450 cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && 451 + id=1 status=200 452 + id=default response=WWW-Authenticate: FooBar param1="value1" param2="value2" 453 + id=default response=WWW-Authenticate: Bearer authorize_uri="id.example.com" p=1 q=0 454 + id=default response=WWW-Authenticate: Basic realm="example.com" 455 EOF 456 457 test_config_global credential.helper test-helper &&