test_merchant_mfa.sh (19490B)
1 #!/usr/bin/env bash 2 # This file is part of TALER 3 # Copyright (C) 2025 Taler Systems SA 4 # 5 # TALER is free software; you can redistribute it and/or modify 6 # it under the terms of the GNU General Public License as 7 # published by the Free Software Foundation; either version 3, or 8 # (at your option) any later version. 9 # 10 # TALER is distributed in the hope that it will be useful, but 11 # WITHOUT ANY WARRANTY; without even the implied warranty of 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 # GNU General Public License for more details. 14 # 15 # You should have received a copy of the GNU General Public 16 # License along with TALER; see the file COPYING. If not, see 17 # <http://www.gnu.org/licenses/> 18 # 19 set -eu 20 21 . setup.sh 22 23 24 # Launch system. 25 setup \ 26 -c "test_merchant_mfa.conf" \ 27 -m 28 LAST_RESPONSE=$(mktemp -p "${TMPDIR:-/tmp}" test_response.conf-XXXXXX) 29 30 solve_challenge() 31 { 32 CHALLENGE_ID=$1 33 CHANNEL=$2 34 EXPECTED_ADDRESS=$3 35 36 rm -f "/tmp/test-merchant-$CHANNEL-tan.txt" \ 37 "/tmp/test-merchant-$CHANNEL-address.txt" 38 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 39 "http://localhost:9966/challenge/$CHALLENGE_ID" \ 40 -d '{}' \ 41 -w "%{http_code}" -s \ 42 -o "$LAST_RESPONSE") 43 if [ "$STATUS" != "200" ] 44 then 45 jq < "$LAST_RESPONSE" 46 exit_fail "Expected challenge transmission to return 200 OK. Got: $STATUS" 47 fi 48 49 TAN=$(head -n1 "/tmp/test-merchant-$CHANNEL-tan.txt" | awk '{print $1}') 50 ADDRESS=$(cat "/tmp/test-merchant-$CHANNEL-address.txt") 51 if [ "$ADDRESS" != "$EXPECTED_ADDRESS" ] 52 then 53 exit_fail "Expected $CHANNEL address '$EXPECTED_ADDRESS'. Got: $ADDRESS" 54 fi 55 56 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 57 "http://localhost:9966/challenge/$CHALLENGE_ID/confirm" \ 58 -d '{"tan":"'"$TAN"'"}' \ 59 -w "%{http_code}" -s \ 60 -o "$LAST_RESPONSE") 61 if [ "$STATUS" != "204" ] 62 then 63 jq < "$LAST_RESPONSE" 64 exit_fail "Expected challenge confirmation to return 204 No Content. Got: $STATUS" 65 fi 66 } 67 68 69 solve_response_challenges() 70 { 71 RESPONSE=$1 72 while IFS=$'\t' read -r CHALLENGE_ID CHANNEL 73 do 74 case "$CHANNEL" in 75 email) 76 solve_challenge "$CHALLENGE_ID" "$CHANNEL" "self@example.com" 77 ;; 78 sms) 79 solve_challenge "$CHALLENGE_ID" "$CHANNEL" "+4171234" 80 ;; 81 *) 82 exit_fail "Unexpected TAN channel: $CHANNEL" 83 ;; 84 esac 85 done < <(jq -r '.challenges[] | [.challenge_id, .tan_channel] | @tsv' "$RESPONSE") 86 } 87 88 echo -n "Configuring a merchant admin instance ..." 89 90 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 91 -H 'Authorization: Bearer secret-token:super_secret' \ 92 http://localhost:9966/management/instances \ 93 -d '{"auth":{"method":"external"},"id":"admin","name":"default","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 50000000},"default_pay_delay":{"d_us": 60000000}}' \ 94 -w "%{http_code}" -s \ 95 -o "$LAST_RESPONSE") 96 97 if [ "$STATUS" != "204" ] 98 then 99 jq < "$LAST_RESPONSE" 100 exit_fail "Expected 204 ok, instance created. got: $STATUS" 101 fi 102 103 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 104 -H 'Authorization: Bearer secret-token:super_secret' \ 105 http://localhost:9966/private/accounts \ 106 -d '{"payto_uri":"payto://x-taler-bank/localhost:8082/43?receiver-name=user43"}' \ 107 -w "%{http_code}" -s \ 108 -o "$LAST_RESPONSE") 109 110 111 if [ "$STATUS" != "200" ] 112 then 113 jq < "$LAST_RESPONSE" 114 exit_fail "Expected 200 OK. Got: $STATUS" 115 fi 116 117 echo " OK" 118 echo -n "Self-provision instance ..." 119 120 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 121 http://localhost:9966/instances \ 122 -d '{"auth":{"method":"token", "password":"pass1234"},"id":"self","name":"default","phone_number":"+4171234","email":"self@example.com","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 50000000},"default_pay_delay":{"d_us": 60000000}}' \ 123 -w "%{http_code}" -s \ 124 -o "$LAST_RESPONSE") 125 126 if [ "$STATUS" != "202" ] 127 then 128 jq < "$LAST_RESPONSE" 129 exit_fail "Expected 202 Accepted. Got: $STATUS" 130 fi 131 echo " OK" 132 133 C1=$(jq -r .challenges[0].challenge_id < "$LAST_RESPONSE") 134 C2=$(jq -r .challenges[1].challenge_id < "$LAST_RESPONSE") 135 136 echo -n "Requesting challenge $C1 " 137 138 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 139 "http://localhost:9966/challenge/$C1" \ 140 -d '{}' \ 141 -w "%{http_code}" -s \ 142 -o "$LAST_RESPONSE") 143 144 if [ "$STATUS" != "200" ] 145 then 146 jq < "$LAST_RESPONSE" 147 exit_fail "Expected 200 OK. Got: $STATUS" 148 fi 149 echo "OK" 150 151 TAN=$(cat /tmp/test-merchant-email-tan.txt | head -n1 | awk '{print $1}') 152 ADDR=$(cat /tmp/test-merchant-email-address.txt) 153 154 if [ "$ADDR" != "self@example.com" ] 155 then 156 exit_fail "Expected address 'self@example.com'. Got: $ADDR" 157 fi 158 159 echo -n "Sending challenge $C1 solution " 160 161 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 162 "http://localhost:9966/challenge/$C1/confirm" \ 163 -d '{"tan":"'"$TAN"'"}' \ 164 -w "%{http_code}" -s \ 165 -o "$LAST_RESPONSE") 166 167 if [ "$STATUS" != "204" ] 168 then 169 jq < "$LAST_RESPONSE" 170 exit_fail "Expected 204 OK. Got: $STATUS" 171 fi 172 echo "OK" 173 174 echo -n "Requesting challenge $C2 " 175 176 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 177 "http://localhost:9966/challenge/$C2" \ 178 -d '{}' \ 179 -w "%{http_code}" -s \ 180 -o "$LAST_RESPONSE") 181 182 if [ "$STATUS" != "200" ] 183 then 184 jq < "$LAST_RESPONSE" 185 exit_fail "Expected 200 OK. Got: $STATUS" 186 fi 187 echo "OK" 188 189 TAN=$(cat /tmp/test-merchant-sms-tan.txt | head -n1 | awk '{print $1}') 190 191 echo -n "Sending challenge $C2 solution " 192 193 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 194 "http://localhost:9966/challenge/$C2/confirm" \ 195 -d '{"tan":"'"$TAN"'"}' \ 196 -w "%{http_code}" -s \ 197 -o "$LAST_RESPONSE") 198 199 if [ "$STATUS" != "204" ] 200 then 201 jq < "$LAST_RESPONSE" 202 exit_fail "Expected 204 OK. Got: $STATUS" 203 fi 204 echo "OK" 205 206 207 echo -n "Retrying instance creation with other body " 208 209 STATUS=$(curl \ 210 -H "Content-Type: application/json" \ 211 -H "Taler-Challenge-Ids: $C1,$C2" \ 212 -X POST \ 213 http://localhost:9966/instances \ 214 -d '{"auth":{"method":"external"},"id":"self","name":"change","phone_number":"+4171234","email":"self@example.com","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 50000000},"default_pay_delay":{"d_us": 60000000}}' \ 215 -w "%{http_code}" -s \ 216 -o "$LAST_RESPONSE") 217 218 if [ "$STATUS" != "202" ] 219 then 220 jq < "$LAST_RESPONSE" 221 exit_fail "Expected 202 Accepted. Got: $STATUS" 222 fi 223 echo "OK" 224 225 226 227 echo -n "Retrying instance creation with original body " 228 229 STATUS=$(curl \ 230 -H "Content-Type: application/json" \ 231 -H "Taler-Challenge-Ids: $C1,$C2" \ 232 -X POST \ 233 http://localhost:9966/instances \ 234 -d '{"auth":{"method":"token", "password":"pass1234"},"id":"self","name":"default","phone_number":"+4171234","email":"self@example.com","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 50000000},"default_pay_delay":{"d_us": 60000000}}' \ 235 -w "%{http_code}" -s \ 236 -o "$LAST_RESPONSE") 237 238 if [ "$STATUS" != "204" ] 239 then 240 jq < "$LAST_RESPONSE" 241 exit_fail "Expected 204 OK. Got: $STATUS" 242 fi 243 244 echo "OK" 245 246 247 echo -n "Unauthorized trigger MFA to add bank account " 248 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 249 -H 'Authorization: Bearer secret-token:bad_password' \ 250 http://localhost:9966/instances/self/private/accounts \ 251 -d '{"payto_uri":"payto://x-taler-bank/localhost:8082/44?receiver-name=user44"}' \ 252 -w "%{http_code}" -s \ 253 -o "$LAST_RESPONSE") 254 255 if [ "$STATUS" != "401" ] 256 then 257 jq < "$LAST_RESPONSE" 258 exit_fail "Expected 401 Forbidden. Got: $STATUS" 259 fi 260 261 echo " OK" 262 263 264 echo -n "Do NOT Trigger MFA to add first bank account " 265 STATUS=$(curl \ 266 -H "Content-Type: application/json" \ 267 -X POST \ 268 -H 'Authorization: Bearer secret-token:pass1234' \ 269 http://localhost:9966/instances/self/private/accounts \ 270 -d '{"payto_uri":"payto://x-taler-bank/localhost:8082/44?receiver-name=user44"}' \ 271 -w "%{http_code}" -s \ 272 -o "$LAST_RESPONSE") 273 274 if [ "$STATUS" != "200" ] 275 then 276 jq < "$LAST_RESPONSE" 277 exit_fail "Expected 200 OK. Got: $STATUS" 278 fi 279 280 echo " OK" 281 282 283 echo -n "Trigger MFA to add 2nd bank account with 2-FA authorization " 284 STATUS=$(curl \ 285 -H "Content-Type: application/json" \ 286 -X POST \ 287 -H 'Authorization: Bearer secret-token:pass1234' \ 288 http://localhost:9966/instances/self/private/accounts \ 289 -d '{"payto_uri":"payto://x-taler-bank/localhost:8082/45?receiver-name=user45"}' \ 290 -w "%{http_code}" -s \ 291 -o "$LAST_RESPONSE") 292 293 if [ "$STATUS" != "202" ] 294 then 295 jq < "$LAST_RESPONSE" 296 exit_fail "Expected 202 Accepted. Got: $STATUS" 297 fi 298 299 echo " OK" 300 301 302 C1=$(jq -r .challenges[0].challenge_id < "$LAST_RESPONSE") 303 304 # Delete old TANs. 305 rm /tmp/test-merchant-*-tan.txt 306 echo -n "Requesting challenge $C1 " 307 308 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 309 "http://localhost:9966/challenge/$C1" \ 310 -d '{}' \ 311 -w "%{http_code}" -s \ 312 -o "$LAST_RESPONSE") 313 314 if [ "$STATUS" != "200" ] 315 then 316 jq < "$LAST_RESPONSE" 317 exit_fail "Expected 200 OK. Got: $STATUS" 318 fi 319 echo "OK" 320 321 TAN=$(cat /tmp/test-merchant-email-tan.txt | head -n1 | awk '{print $1}') 322 ADDR=$(cat /tmp/test-merchant-email-address.txt) 323 324 if [ "$ADDR" != "self@example.com" ] 325 then 326 exit_fail "Expected address 'self@example.com'. Got: $ADDR" 327 fi 328 329 echo -n "Sending challenge $C1 solution " 330 331 STATUS=$(curl \ 332 -H "Content-Type: application/json" \ 333 -X POST \ 334 "http://localhost:9966/challenge/$C1/confirm" \ 335 -d '{"tan":"'"$TAN"'"}' \ 336 -w "%{http_code}" -s \ 337 -o "$LAST_RESPONSE") 338 339 if [ "$STATUS" != "204" ] 340 then 341 jq < "$LAST_RESPONSE" 342 exit_fail "Expected 204 OK. Got: $STATUS" 343 fi 344 echo "OK" 345 346 echo -n "Finally, add 2nd bank account " 347 STATUS=$(curl \ 348 -X POST \ 349 -H "Content-Type: application/json" \ 350 -H "Taler-Challenge-Ids: $C1" \ 351 -H 'Authorization: Bearer secret-token:pass1234' \ 352 http://localhost:9966/instances/self/private/accounts \ 353 -d '{"payto_uri":"payto://x-taler-bank/localhost:8082/45?receiver-name=user45"}' \ 354 -w "%{http_code}" -s \ 355 -o "$LAST_RESPONSE") 356 357 if [ "$STATUS" != "200" ] 358 then 359 jq < "$LAST_RESPONSE" 360 exit_fail "Expected 200 OK. Got: $STATUS" 361 fi 362 363 echo " OK" 364 365 366 echo -n "Begin forgotten password reset " 367 STATUS=$(curl \ 368 -X POST \ 369 -H "Content-Type: application/json" \ 370 http://localhost:9966/instances/self/forgot-password \ 371 -d '{"method":"token","password":"amnesia"}' \ 372 -w "%{http_code}" -s \ 373 -o "$LAST_RESPONSE") 374 375 if [ "$STATUS" != "202" ] 376 then 377 jq < "$LAST_RESPONSE" 378 exit_fail "Expected 202 Accepted. Got: $STATUS" 379 fi 380 381 echo " OK" 382 383 C1=$(jq -r .challenges[0].challenge_id < "$LAST_RESPONSE") 384 C2=$(jq -r .challenges[1].challenge_id < "$LAST_RESPONSE") 385 386 echo -n "Requesting challenge $C1 " 387 388 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 389 "http://localhost:9966/challenge/$C1" \ 390 -d '{}' \ 391 -w "%{http_code}" -s \ 392 -o "$LAST_RESPONSE") 393 394 if [ "$STATUS" != "200" ] 395 then 396 jq < "$LAST_RESPONSE" 397 exit_fail "Expected 200 OK. Got: $STATUS" 398 fi 399 echo "OK" 400 401 TAN=$(cat /tmp/test-merchant-email-tan.txt | head -n1 | awk '{print $1}') 402 ADDR=$(cat /tmp/test-merchant-email-address.txt) 403 404 if [ "$ADDR" != "self@example.com" ] 405 then 406 exit_fail "Expected address 'self@example.com'. Got: $ADDR" 407 fi 408 409 echo -n "Sending challenge $C1 solution " 410 411 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 412 "http://localhost:9966/challenge/$C1/confirm" \ 413 -d '{"tan":"'"$TAN"'"}' \ 414 -w "%{http_code}" -s \ 415 -o "$LAST_RESPONSE") 416 417 if [ "$STATUS" != "204" ] 418 then 419 jq < "$LAST_RESPONSE" 420 exit_fail "Expected 204 OK. Got: $STATUS" 421 fi 422 echo "OK" 423 424 echo -n "Reject password reset with only one mandatory challenge solved " 425 STATUS=$(curl \ 426 -X POST \ 427 -H "Content-Type: application/json" \ 428 -H "Taler-Challenge-Ids: $C1" \ 429 http://localhost:9966/instances/self/forgot-password \ 430 -d '{"method":"token","password":"amnesia"}' \ 431 -w "%{http_code}" -s \ 432 -o "$LAST_RESPONSE") 433 434 if [ "$STATUS" != "202" ] || 435 [ "$(jq -r .combi_and < "$LAST_RESPONSE")" != "true" ] 436 then 437 jq < "$LAST_RESPONSE" 438 exit_fail "Expected both mandatory channels to remain required. Got: $STATUS" 439 fi 440 echo "OK" 441 442 443 echo -n "Requesting challenge $C2 " 444 445 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 446 "http://localhost:9966/challenge/$C2" \ 447 -d '{}' \ 448 -w "%{http_code}" -s \ 449 -o "$LAST_RESPONSE") 450 451 if [ "$STATUS" != "200" ] 452 then 453 jq < "$LAST_RESPONSE" 454 exit_fail "Expected 200 OK. Got: $STATUS" 455 fi 456 echo "OK" 457 458 TAN=$(cat /tmp/test-merchant-sms-tan.txt | head -n1 | awk '{print $1}') 459 460 echo -n "Sending challenge $C2 solution " 461 462 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 463 "http://localhost:9966/challenge/$C2/confirm" \ 464 -d '{"tan":"'"$TAN"'"}' \ 465 -w "%{http_code}" -s \ 466 -o "$LAST_RESPONSE") 467 468 if [ "$STATUS" != "204" ] 469 then 470 jq < "$LAST_RESPONSE" 471 exit_fail "Expected 204 OK. Got: $STATUS" 472 fi 473 echo "OK" 474 475 echo -n "Complete password reset " 476 STATUS=$(curl \ 477 -X POST \ 478 -H "Content-Type: application/json" \ 479 -H "Taler-Challenge-Ids: $C1,$C2" \ 480 http://localhost:9966/instances/self/forgot-password \ 481 -d '{"method":"token","password":"amnesia"}' \ 482 -w "%{http_code}" -s \ 483 -o "$LAST_RESPONSE") 484 485 if [ "$STATUS" != "204" ] 486 then 487 jq < "$LAST_RESPONSE" 488 exit_fail "Expected 204 No content. Got: $STATUS" 489 fi 490 491 echo " OK" 492 493 494 495 496 497 echo -n "Begin password reset with login token issuance " 498 TOKEN_RESET_BODY='{"method":"token","password":"recovered","token_duration":{"d_us":600000000}}' 499 STATUS=$(curl \ 500 -X POST \ 501 -H "Content-Type: application/json" \ 502 http://localhost:9966/instances/self/forgot-password \ 503 -d "$TOKEN_RESET_BODY" \ 504 -w "%{http_code}" -s \ 505 -o "$LAST_RESPONSE") 506 507 if [ "$STATUS" != "202" ] 508 then 509 jq < "$LAST_RESPONSE" 510 exit_fail "Expected 202 Accepted. Got: $STATUS" 511 fi 512 cp "$LAST_RESPONSE" "$LAST_RESPONSE.challenges" 513 RESET_CHALLENGE_IDS=$(jq -r '[.challenges[].challenge_id] | join(",")' \ 514 < "$LAST_RESPONSE") 515 solve_response_challenges "$LAST_RESPONSE.challenges" 516 echo "OK" 517 518 519 echo -n "Reject solved challenges for a modified token duration " 520 STATUS=$(curl \ 521 -X POST \ 522 -H "Content-Type: application/json" \ 523 -H "Taler-Challenge-Ids: $RESET_CHALLENGE_IDS" \ 524 http://localhost:9966/instances/self/forgot-password \ 525 -d '{"method":"token","password":"recovered","token_duration":{"d_us":300000000}}' \ 526 -w "%{http_code}" -s \ 527 -o "$LAST_RESPONSE") 528 529 if [ "$STATUS" != "202" ] 530 then 531 jq < "$LAST_RESPONSE" 532 exit_fail "Expected changed request body to require new challenges. Got: $STATUS" 533 fi 534 echo "OK" 535 536 537 echo -n "Complete password reset and receive login token " 538 STATUS=$(curl \ 539 -X POST \ 540 -H "Content-Type: application/json" \ 541 -H "Taler-Challenge-Ids: $RESET_CHALLENGE_IDS" \ 542 http://localhost:9966/instances/self/forgot-password \ 543 -d "$TOKEN_RESET_BODY" \ 544 -w "%{http_code}" -s \ 545 -o "$LAST_RESPONSE") 546 547 if [ "$STATUS" != "200" ] 548 then 549 jq < "$LAST_RESPONSE" 550 exit_fail "Expected 200 OK with login token. Got: $STATUS" 551 fi 552 RESET_TOKEN=$(jq -er \ 553 'select(.scope == "spa" and .refreshable == true) | .access_token' \ 554 < "$LAST_RESPONSE") 555 if [ "$(jq -r .token < "$LAST_RESPONSE")" != "$RESET_TOKEN" ] 556 then 557 exit_fail "Expected token and access_token response fields to match" 558 fi 559 echo "OK" 560 561 562 echo -n "Use login token returned by password reset " 563 STATUS=$(curl \ 564 -X GET \ 565 -H "Authorization: Bearer $RESET_TOKEN" \ 566 http://localhost:9966/instances/self/private/products \ 567 -w "%{http_code}" -s \ 568 -o "$LAST_RESPONSE") 569 570 if [ "$STATUS" != "200" ] 571 then 572 jq < "$LAST_RESPONSE" 573 exit_fail "Expected reset login token to authorize SPA access. Got: $STATUS" 574 fi 575 echo "OK" 576 577 578 echo -n "Self-provision second instance for instance-binding test " 579 OTHER_INSTANCE_BODY='{"auth":{"method":"token","password":"recovered"},"id":"other","name":"other","phone_number":"+4171234","email":"self@example.com","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us":50000000},"default_pay_delay":{"d_us":60000000}}' 580 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 581 http://localhost:9966/instances \ 582 -d "$OTHER_INSTANCE_BODY" \ 583 -w "%{http_code}" -s \ 584 -o "$LAST_RESPONSE") 585 586 if [ "$STATUS" != "202" ] 587 then 588 jq < "$LAST_RESPONSE" 589 exit_fail "Expected 202 Accepted. Got: $STATUS" 590 fi 591 cp "$LAST_RESPONSE" "$LAST_RESPONSE.challenges" 592 OTHER_CREATE_CHALLENGE_IDS=$(jq -r \ 593 '[.challenges[].challenge_id] | join(",")' < "$LAST_RESPONSE") 594 solve_response_challenges "$LAST_RESPONSE.challenges" 595 596 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 597 -H "Taler-Challenge-Ids: $OTHER_CREATE_CHALLENGE_IDS" \ 598 http://localhost:9966/instances \ 599 -d "$OTHER_INSTANCE_BODY" \ 600 -w "%{http_code}" -s \ 601 -o "$LAST_RESPONSE") 602 if [ "$STATUS" != "204" ] 603 then 604 jq < "$LAST_RESPONSE" 605 exit_fail "Expected 204 No Content. Got: $STATUS" 606 fi 607 echo "OK" 608 609 610 echo -n "Solve token-creation challenge for first instance " 611 TOKEN_BODY='{"scope":"spa","duration":{"d_us":600000000},"refreshable":true}' 612 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 613 -H 'Authorization: Bearer secret-token:recovered' \ 614 http://localhost:9966/instances/self/private/token \ 615 -d "$TOKEN_BODY" \ 616 -w "%{http_code}" -s \ 617 -o "$LAST_RESPONSE") 618 if [ "$STATUS" != "202" ] 619 then 620 jq < "$LAST_RESPONSE" 621 exit_fail "Expected 202 Accepted. Got: $STATUS" 622 fi 623 INSTANCE_CHALLENGE_ID=$(jq -r '.challenges[0].challenge_id' < "$LAST_RESPONSE") 624 INSTANCE_CHALLENGE_CHANNEL=$(jq -r '.challenges[0].tan_channel' < "$LAST_RESPONSE") 625 case "$INSTANCE_CHALLENGE_CHANNEL" in 626 email) 627 INSTANCE_CHALLENGE_ADDRESS=self@example.com 628 ;; 629 sms) 630 INSTANCE_CHALLENGE_ADDRESS=+4171234 631 ;; 632 *) 633 exit_fail "Unexpected TAN channel: $INSTANCE_CHALLENGE_CHANNEL" 634 ;; 635 esac 636 solve_challenge "$INSTANCE_CHALLENGE_ID" \ 637 "$INSTANCE_CHALLENGE_CHANNEL" \ 638 "$INSTANCE_CHALLENGE_ADDRESS" 639 echo "OK" 640 641 642 echo -n "Reject solved challenge at a different instance " 643 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 644 -H 'Authorization: Bearer secret-token:recovered' \ 645 -H "Taler-Challenge-Ids: $INSTANCE_CHALLENGE_ID" \ 646 http://localhost:9966/instances/other/private/token \ 647 -d "$TOKEN_BODY" \ 648 -w "%{http_code}" -s \ 649 -o "$LAST_RESPONSE") 650 if [ "$STATUS" != "202" ] 651 then 652 jq < "$LAST_RESPONSE" 653 exit_fail "Expected foreign challenge to be rejected with 202. Got: $STATUS" 654 fi 655 if jq -e --arg cid "$INSTANCE_CHALLENGE_ID" \ 656 '.challenges[] | select(.challenge_id == $cid)' "$LAST_RESPONSE" > /dev/null 657 then 658 exit_fail "Foreign challenge was returned as applicable to the other instance" 659 fi 660 echo "OK" 661 662 663 echo -n "Accept solved challenge at its original instance " 664 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 665 -H 'Authorization: Bearer secret-token:recovered' \ 666 -H "Taler-Challenge-Ids: $INSTANCE_CHALLENGE_ID" \ 667 http://localhost:9966/instances/self/private/token \ 668 -d "$TOKEN_BODY" \ 669 -w "%{http_code}" -s \ 670 -o "$LAST_RESPONSE") 671 if [ "$STATUS" != "200" ] 672 then 673 jq < "$LAST_RESPONSE" 674 exit_fail "Expected same-instance challenge to authorize request. Got: $STATUS" 675 fi 676 echo "OK" 677 678 679 echo "TEST PASSED" 680 681 exit 0