test_merchant_instance_auth.sh (17136B)
1 #!/usr/bin/env bash 2 # This file is part of TALER 3 # Copyright (C) 2014-2023 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 20 # Cleanup to run whenever we exit 21 function my_cleanup() 22 { 23 for n in $(jobs -p) 24 do 25 kill "$n" 2> /dev/null || true 26 done 27 wait 28 if [ -n "${LAST_RESPONSE+x}" ] 29 then 30 rm -f "${LAST_RESPONSE}" 31 fi 32 } 33 34 . setup.sh 35 36 setup -c test_template.conf -m 37 CONF="test_template.conf.edited" 38 LAST_RESPONSE=$(mktemp -p "${TMPDIR:-/tmp}" test_response.conf-XXXXXX) 39 40 echo -n "Configuring 'admin' instance ..." >&2 41 42 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 43 http://localhost:9966/management/instances \ 44 -d '{"auth":{"method":"token","password":"new_pw"},"id":"admin","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \ 45 -w "%{http_code}" -s -o /dev/null) 46 47 if [ "$STATUS" != "204" ] 48 then 49 exit_fail "Expected 204, instance created. got: $STATUS" >&2 50 fi 51 52 53 BASIC_AUTH=$(echo -n admin:new_pw | base64) 54 55 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 56 -H "Authorization: Basic $BASIC_AUTH" \ 57 http://localhost:9966/private/token \ 58 -d '{"scope":"spa"}' \ 59 -w "%{http_code}" -s -o $LAST_RESPONSE) 60 61 62 if [ "$STATUS" != "200" ] 63 then 64 exit_fail "Expected 200 OK. Got: $STATUS" 65 fi 66 67 TOKEN=$(jq -e -r .access_token < $LAST_RESPONSE) 68 69 echo " OK" >&2 70 71 echo -n "Setting up bank account..." >&2 72 73 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 74 -H "Authorization: Bearer $TOKEN" \ 75 http://localhost:9966/private/accounts \ 76 -d '{"payto_uri":"payto://x-taler-bank/localhost:8082/43?receiver-name=user43"}' \ 77 -w "%{http_code}" -s -o /dev/null) 78 79 80 if [ "$STATUS" != "200" ] 81 then 82 exit_fail "Expected 200 OK. Got: $STATUS" 83 fi 84 85 echo " OK" >&2 86 87 # Check both refund endpoints with scoped bearer tokens. An unknown order 88 # must reach the refund handler (404/2005) only when the scope permits refunds. 89 for SCOPE in readonly order-simple order-pos order-pos:refreshable order-mgmt order-full 90 do 91 echo -n "Checking refund access for ${SCOPE} ..." >&2 92 STATUS=$(curl -H "Content-Type: application/json" \ 93 -H "Authorization: Basic $BASIC_AUTH" \ 94 http://localhost:9966/private/token \ 95 -d "$(jq -n --arg scope "$SCOPE" '{scope: $scope}')" \ 96 -w "%{http_code}" -s -o "$LAST_RESPONSE") 97 if [ "$STATUS" != "200" ] 98 then 99 cat "$LAST_RESPONSE" >&2 100 exit_fail "Expected 200, ${SCOPE} token created. Got: $STATUS" 101 fi 102 SCOPED_TOKEN=$(jq -e -r .access_token < "$LAST_RESPONSE") 103 104 case "$SCOPE" in 105 readonly|order-simple) 106 EXPECTED_STATUS=401 107 EXPECTED_CODE=2015 # TALER_EC_MERCHANT_GENERIC_UNAUTHORIZED 108 ;; 109 *) 110 EXPECTED_STATUS=404 111 EXPECTED_CODE=2005 # TALER_EC_MERCHANT_GENERIC_ORDER_UNKNOWN 112 ;; 113 esac 114 for ENDPOINT in refund refund-external 115 do 116 case "$ENDPOINT" in 117 refund) 118 REFUND_BODY='{"refund":"TESTKUDOS:1","reason":"scope test"}' 119 ;; 120 refund-external) 121 REFUND_BODY='{"method":"cash","id":"scope-test","amount":"TESTKUDOS:1","reason":"scope test"}' 122 ;; 123 esac 124 STATUS=$(curl -H "Content-Type: application/json" \ 125 -H "Authorization: Bearer $SCOPED_TOKEN" \ 126 "http://localhost:9966/private/orders/unknown-order/${ENDPOINT}" \ 127 -d "$REFUND_BODY" \ 128 -w "%{http_code}" -s -o "$LAST_RESPONSE") 129 if [ "$STATUS" != "$EXPECTED_STATUS" ] || 130 [ "$(jq -r .code < "$LAST_RESPONSE")" != "$EXPECTED_CODE" ] 131 then 132 cat "$LAST_RESPONSE" >&2 133 exit_fail "Expected ${EXPECTED_STATUS}/${EXPECTED_CODE} for ${SCOPE} on ${ENDPOINT}. Got: $STATUS" 134 fi 135 done 136 echo " OK" >&2 137 done 138 139 # Kill merchant 140 kill -TERM "$SETUP_PID" 141 wait 142 unset SETUP_PID 143 144 setup -c test_template.conf \ 145 -ef \ 146 -u "exchange-account-2" \ 147 -r "merchant-exchange-default" 148 149 NEW_SECRET="different_value" 150 151 taler-merchant-exchangekeyupdate \ 152 -c "${CONF}" \ 153 -L DEBUG \ 154 -t \ 155 2> taler-merchant-exchangekeyupdate2.log 156 taler-merchant-passwd \ 157 -c "${CONF}" \ 158 -L DEBUG \ 159 "$NEW_SECRET" \ 160 2> taler-merchant-passwd.log 161 taler-merchant-httpd \ 162 -c "${CONF}" \ 163 -L DEBUG \ 164 2> taler-merchant-httpd2.log & 165 # Install cleanup handler (except for kill -9) 166 trap my_cleanup EXIT 167 168 echo -n "Waiting for the merchant..." >&2 169 # Wait for merchant to be available (usually the slowest) 170 for n in $(seq 1 50) 171 do 172 echo -n "." >&2 173 sleep 0.1 174 OK=0 175 # merchant 176 wget --waitretry=0 \ 177 --timeout=1 \ 178 http://localhost:9966/ \ 179 -o /dev/null \ 180 -O /dev/null \ 181 >/dev/null || continue 182 OK=1 183 break 184 done 185 186 if [ "x$OK" != "x1" ] 187 then 188 exit_fail "Failed to (re)start merchant backend" 189 fi 190 191 echo " OK" >&2 192 193 BASIC_AUTH=$(echo -n "admin:$NEW_SECRET" | base64) 194 195 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 196 -H "Authorization: Basic $BASIC_AUTH" \ 197 http://localhost:9966/private/token \ 198 -d '{"scope":"spa"}' \ 199 -w "%{http_code}" -s -o $LAST_RESPONSE) 200 201 202 if [ "$STATUS" != "200" ] 203 then 204 exit_fail "Expected 200 OK. Got: $STATUS" 205 fi 206 207 TOKEN=$(jq -e -r .access_token < $LAST_RESPONSE) 208 209 echo -n "Making sure merchant KYC data is current ..." >&2 210 211 taler-merchant-kyccheck \ 212 -c "${CONF}" \ 213 -L DEBUG \ 214 -t \ 215 2> taler-merchant-kyccheck.log 216 217 sleep 1 218 echo " OK" 219 220 echo -n "Creating order to test auth is ok..." >&2 221 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 222 'http://localhost:9966/private/orders' \ 223 -H 'Authorization: Bearer '"$TOKEN" \ 224 -d '{"order":{"amount":"TESTKUDOS:1","summary":"payme"}}' \ 225 -w "%{http_code}" -s -o "$LAST_RESPONSE") 226 227 if [ "$STATUS" != "200" ] 228 then 229 cat "$LAST_RESPONSE" >&2 230 exit_fail "Expected 200, order created. got: $STATUS" 231 fi 232 233 ORDER_ID=$(jq -e -r .order_id < "$LAST_RESPONSE") 234 ORD_TOKEN=$(jq -e -r .token < "$LAST_RESPONSE") 235 236 STATUS=$(curl "http://localhost:9966/private/orders/${ORDER_ID}" \ 237 -H 'Authorization: Bearer '"$TOKEN" \ 238 -w "%{http_code}" -s -o "$LAST_RESPONSE") 239 240 if [ "$STATUS" != "200" ] 241 then 242 cat "$LAST_RESPONSE" >&2 243 exit_fail "Expected 200, getting order info before claming it. got: $STATUS" 244 fi 245 246 PAY_URL=$(jq -e -r .taler_pay_uri < "$LAST_RESPONSE") 247 248 echo "OK order ${ORDER_ID} with ${ORD_TOKEN} and ${PAY_URL}" >&2 249 250 echo -n "Configuring 'second' instance ..." >&2 251 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 252 -H 'Authorization: Bearer '"$TOKEN" \ 253 http://localhost:9966/management/instances \ 254 -d '{"auth":{"method":"token","password":"second"},"id":"second","name":"second","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \ 255 -w "%{http_code}" -s -o "$LAST_RESPONSE") 256 257 if [ "$STATUS" != "204" ] 258 then 259 cat "$LAST_RESPONSE" >&2 260 exit_fail "Expected 204, instance created. got: $STATUS" 261 fi 262 263 echo "OK" >&2 264 265 echo -n "Configuring 'third' instance ..." >&2 266 267 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 268 -H 'Authorization: Bearer '"$TOKEN" \ 269 http://localhost:9966/management/instances \ 270 -d '{"auth":{"method":"token","password":"third"},"id":"third","name":"third","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \ 271 -w "%{http_code}" -s -o "$LAST_RESPONSE") 272 273 if [ "$STATUS" != "204" ] 274 then 275 cat "$LAST_RESPONSE" >&2 276 exit_fail "Expected 204, instance created. got: $STATUS" 277 fi 278 279 echo "OK" >&2 280 281 echo -n "Updating 'second' instance token using the 'new_one' auth token..." >&2 282 283 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 284 -H 'Authorization: Bearer '"$TOKEN" \ 285 http://localhost:9966/management/instances/second/auth \ 286 -d '{"method":"token","password":"new_one"}' \ 287 -w "%{http_code}" -s -o "$LAST_RESPONSE") 288 289 if [ "$STATUS" != "204" ] 290 then 291 cat "$LAST_RESPONSE" >&2 292 exit_fail "Expected 204, instance auth token changed. got: $STATUS" 293 fi 294 NEW_SECRET="new_one" 295 echo " OK" >&2 296 297 BASIC_AUTH2=$(echo -n second:$NEW_SECRET | base64) 298 299 echo -n "Requesting login token..." >&2 300 301 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 302 -H 'Authorization: Basic '"$BASIC_AUTH2" \ 303 http://localhost:9966/instances/second/private/token \ 304 -d '{"scope":"readonly","refreshable":true}' \ 305 -w "%{http_code}" -s -o "$LAST_RESPONSE") 306 307 if [ "$STATUS" != "200" ] 308 then 309 jq < "$LAST_RESPONSE" >&2 310 exit_fail "Expected 200, login token created. got: $STATUS" 311 fi 312 313 TOKEN=$(jq -e -r .access_token < "$LAST_RESPONSE") 314 315 echo " OK" >&2 316 317 echo -n "Requesting login token... (spa)" >&2 318 319 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 320 -H 'Authorization: Basic '"$BASIC_AUTH2" \ 321 http://localhost:9966/instances/second/private/token \ 322 -d '{"scope":"spa"}' \ 323 -w "%{http_code}" -s -o "$LAST_RESPONSE") 324 325 if [ "$STATUS" != "200" ] 326 then 327 jq < "$LAST_RESPONSE" >&2 328 exit_fail "Expected 200, login token created. got: $STATUS" 329 fi 330 331 RWTOKEN=$(jq -e -r .access_token < "$LAST_RESPONSE") 332 333 echo " OK" >&2 334 335 echo -n "Using login token..." >&2 336 337 STATUS=$(curl "http://localhost:9966/instances/second/private/orders" \ 338 -H 'Authorization: Bearer '"$TOKEN" \ 339 -w "%{http_code}" -s -o "$LAST_RESPONSE") 340 341 if [ "$STATUS" != "200" ] 342 then 343 jq < "$LAST_RESPONSE" >&2 344 exit_fail "Expected 200, getting orders. got: $STATUS" 345 fi 346 347 echo " OK" >&2 348 349 echo -n "Updating 'second' instance token using the 'second' auth token..." >&2 350 351 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 352 -H 'Authorization: Bearer '"$RWTOKEN" \ 353 http://localhost:9966/instances/second/private/auth \ 354 -d '{"method":"token","password":"again"}' \ 355 -w "%{http_code}" -s -o "$LAST_RESPONSE") 356 357 if [ "$STATUS" != "401" ] || 358 [ "$(jq -r .code < "$LAST_RESPONSE")" != "2604" ] 359 then 360 cat "$LAST_RESPONSE" >&2 361 exit_fail "Expected missing old password to fail with 401/2604. Got: $STATUS" 362 fi 363 364 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 365 -H 'Authorization: Bearer '"$RWTOKEN" \ 366 http://localhost:9966/instances/second/private/auth \ 367 -d '{"method":"token","password":"again","old_password":"wrong"}' \ 368 -w "%{http_code}" -s -o "$LAST_RESPONSE") 369 370 if [ "$STATUS" != "401" ] || 371 [ "$(jq -r .code < "$LAST_RESPONSE")" != "2604" ] 372 then 373 cat "$LAST_RESPONSE" >&2 374 exit_fail "Expected wrong old password to fail with 401/2604. Got: $STATUS" 375 fi 376 377 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 378 -H 'Authorization: Bearer '"$RWTOKEN" \ 379 http://localhost:9966/instances/second/private/auth \ 380 -d '{"method":"token","password":"again","old_password":"new_one"}' \ 381 -w "%{http_code}" -s -o "$LAST_RESPONSE") 382 383 BASIC_AUTH2=$(echo -n second:again | base64) 384 385 if [ "$STATUS" != "204" ] 386 then 387 cat $LAST_RESPONSE >&2 388 exit_fail "Expected 204, instance not authorized. got: $STATUS" 389 fi 390 391 echo " OK" >&2 392 393 echo -n "Updating 'third' instance token using the 'second' auth token..." >&2 394 395 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 396 -H 'Authorization: Bearer '"$RWTOKEN" \ 397 http://localhost:9966/management/instances/third/auth \ 398 -d '{"method":"token","password":"new_one"}' \ 399 -w "%{http_code}" -s -o "$LAST_RESPONSE") 400 401 if [ "$STATUS" != "401" ] 402 then 403 cat $LAST_RESPONSE >&2 404 exit_fail "Expected 401, instance not authorized. got: $STATUS" 405 fi 406 407 echo " OK" >&2 408 409 echo -n "Refreshing login token... (expected failure)" >&2 410 411 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 412 -H 'Authorization: Bearer '"$TOKEN" \ 413 http://localhost:9966/instances/second/private/token \ 414 -d '{"scope":"spa","refreshable":true}' \ 415 -w "%{http_code}" -s -o "$LAST_RESPONSE") 416 417 if [ "$STATUS" != "403" ] 418 then 419 jq < "$LAST_RESPONSE" >&2 420 exit_fail "Expected 403, refused to upgrade login token. got: $STATUS" 421 fi 422 423 echo " OK" >&2 424 425 echo -n "Refreshing login token... (expected failure)" >&2 426 427 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 428 -H 'Authorization: Bearer '"$RWTOKEN" \ 429 http://localhost:9966/instances/second/private/token \ 430 -d '{"scope":"spa","refreshable":true}' \ 431 -w "%{http_code}" -s -o "$LAST_RESPONSE") 432 433 if [ "$STATUS" != "401" ] 434 then 435 jq < "$LAST_RESPONSE" >&2 436 exit_fail "Expected 401, refused to upgrade login token. got: $STATUS" 437 fi 438 439 echo " OK" >&2 440 441 echo -n "Creating refreshable login token..." >&2 442 443 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 444 -H 'Authorization: Basic '"$BASIC_AUTH2" \ 445 http://localhost:9966/instances/second/private/token \ 446 -d '{"scope":"spa:refreshable"}' \ 447 -w "%{http_code}" -s -o "$LAST_RESPONSE") 448 449 if [ "$STATUS" != "200" ] 450 then 451 jq < "$LAST_RESPONSE" >&2 452 exit_fail "Expected 200, login token created. got: $STATUS" 453 fi 454 455 RWTOKEN=$(jq -e -r .access_token < "$LAST_RESPONSE") 456 457 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 458 -H 'Authorization: Bearer '"$RWTOKEN" \ 459 http://localhost:9966/instances/second/private/token \ 460 -d '{"scope":"spa","refreshable":true}' \ 461 -w "%{http_code}" -s -o "$LAST_RESPONSE") 462 463 if [ "$STATUS" != "200" ] 464 then 465 jq < "$LAST_RESPONSE" >&2 466 exit_fail "Expected 200. got: $STATUS" 467 fi 468 469 echo " OK" >&2 470 471 472 echo -n "Requesting another login token... (read)" >&2 473 474 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 475 -H 'Authorization: Basic '"$BASIC_AUTH2" \ 476 http://localhost:9966/instances/second/private/token \ 477 -d '{"scope":"readonly", "refreshable": false}' \ 478 -w "%{http_code}" -s -o "$LAST_RESPONSE") 479 480 if [ "$STATUS" != "200" ] 481 then 482 jq < "$LAST_RESPONSE" >&2 483 exit_fail "Expected 200, login token created. got: $STATUS" 484 fi 485 486 RTOKEN=$(jq -e -r .access_token < "$LAST_RESPONSE") 487 488 echo " OK" >&2 489 490 echo -n "Requesting another login token... (read:refreshable)" >&2 491 492 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 493 -H 'Authorization: Basic '"$BASIC_AUTH2" \ 494 http://localhost:9966/instances/second/private/token \ 495 -d '{"scope":"readonly:refreshable", "description": "readonly but refreshable"}' \ 496 -w "%{http_code}" -s -o "$LAST_RESPONSE") 497 498 if [ "$STATUS" != "200" ] 499 then 500 jq < "$LAST_RESPONSE" >&2 501 exit_fail "Expected 200, login token created. got: $STATUS" 502 fi 503 504 RTOKEN=$(jq -e -r .access_token < "$LAST_RESPONSE") 505 506 echo " OK" >&2 507 508 echo "Getting last 2 login tokens." >&2 509 510 STATUS=$(curl -H "Content-Type: application/json" \ 511 -H "Authorization: Bearer $RWTOKEN" \ 512 'http://localhost:9966/instances/second/private/tokens?limit=-2' \ 513 -w "%{http_code}" -s -o $LAST_RESPONSE) 514 515 if [ "$STATUS" != "200" ] 516 then 517 jq < "$LAST_RESPONSE" >&2 518 exit_fail "Expected 200 OK. Got: $STATUS" 519 fi 520 521 TOKEN_SERIAL=$(jq -e -r .tokens[0].serial < "$LAST_RESPONSE") 522 523 echo -n "Deleting second login token by serial..." >&2 524 525 STATUS=$(curl -H "Content-Type: application/json" -X DELETE \ 526 -H 'Authorization: Bearer '"$RWTOKEN" \ 527 http://localhost:9966/instances/second/private/tokens/$TOKEN_SERIAL \ 528 -w "%{http_code}" -s -o "$LAST_RESPONSE") 529 530 if [ "$STATUS" != "204" ] 531 then 532 jq < "$LAST_RESPONSE" >&2 533 exit_fail "Expected 204, login token deleted. got: $STATUS" 534 fi 535 echo " OK" >&2 536 537 echo -n "Using deleted login token $RTOKEN..." >&2 538 539 STATUS=$(curl "http://localhost:9966/instances/second/private/orders" \ 540 -H 'Authorization: Bearer '"$RTOKEN" \ 541 -w "%{http_code}" -s -o "$LAST_RESPONSE") 542 543 if [ "$STATUS" != "401" ] 544 then 545 jq < "$LAST_RESPONSE" >&2 546 exit_fail "Expected 401, token was deleted. got: $STATUS" 547 fi 548 549 echo " OK" >&2 550 551 552 echo -n "Deleting login token..." >&2 553 554 STATUS=$(curl -H "Content-Type: application/json" -X DELETE \ 555 -H 'Authorization: Bearer '"$TOKEN" \ 556 http://localhost:9966/instances/second/private/token \ 557 -w "%{http_code}" -s -o "$LAST_RESPONSE") 558 559 if [ "$STATUS" != "204" ] 560 then 561 jq < "$LAST_RESPONSE" >&2 562 exit_fail "Expected 204, login token deleted. got: $STATUS" 563 fi 564 echo " OK" >&2 565 566 echo -n "Using deleted login token..." >&2 567 568 STATUS=$(curl "http://localhost:9966/instances/second/private/orders" \ 569 -H 'Authorization: Bearer '"$TOKEN" \ 570 -w "%{http_code}" -s -o "$LAST_RESPONSE") 571 572 if [ "$STATUS" != "401" ] 573 then 574 jq < "$LAST_RESPONSE" >&2 575 exit_fail "Expected 401, token was deleted. got: $STATUS" 576 fi 577 578 echo " OK" >&2 579 580 581 echo "Test PASSED" 582 583 exit 0