From beb45b17933cbc371f5bc8bd08589b4f22bf316e Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 26 Jun 2022 16:01:29 +0200 Subject: -add test case for #7227 --- src/cli/test_anastasis_reducer_recovery_hanging.sh | 376 +++++++++++++++++++++ 1 file changed, 376 insertions(+) create mode 100755 src/cli/test_anastasis_reducer_recovery_hanging.sh diff --git a/src/cli/test_anastasis_reducer_recovery_hanging.sh b/src/cli/test_anastasis_reducer_recovery_hanging.sh new file mode 100755 index 0000000..dba9ee4 --- /dev/null +++ b/src/cli/test_anastasis_reducer_recovery_hanging.sh @@ -0,0 +1,376 @@ +#!/bin/bash +# This file is in the public domain. +# Runs tests with a 'hanging' Anastasis provider. + +set -eu +set -x + +# Exit, with status code "skip" (no 'real' failure) +function exit_skip() { + echo " SKIP: $1" + exit 77 +} + +# Exit, with error message (hard failure) +function exit_fail() { + echo " FAIL: $1" + exit 1 +} + +# Cleanup to run whenever we exit +function cleanup() +{ + for n in `jobs -p` + do + kill $n 2> /dev/null || true + done + rm -rf $CONF $R1FILE $R2FILE $B1FILE $B2FILE $TMP_DIR + wait +} + +function sync_providers() { + infile=$1 + outfile=$2 + echo "Synchronizing providers" + # Sync with providers (up to 3 providers aren't synced here) + for x in 1 2 3; do + echo "Synchronizing providers (round $x)" + #anastasis-reducer sync_providers < $infile > $outfile 2> /dev/null || true + anastasis-reducer sync_providers < $infile > $outfile || true + CODE=$(jq -r -e ".code // 0" < $outfile) + # ANASTASIS_REDUCER_PROVIDERS_ALREADY_SYNCED + # FIXME: Temporary workaround for C reducer. See #7227. + if test "$CODE" = "8420"; then + # restore previous non-error state + cat $infile > $outfile + break + fi + # ANASTASIS_REDUCER_ACTION_INVALID + if test "$CODE" = "8400"; then + # restore previous non-error state + cat $infile > $outfile + break + fi + if test "$CODE" != "0"; then + exit_fail "Expected no error or 8420/8400, got $CODE" + fi + cat $outfile > $infile + done + echo "Providers synced." +} + + +CONF_1="test_anastasis_reducer_free_1.conf" +CONF_2="test_anastasis_reducer_free_2.conf" +CONF_3="test_anastasis_reducer_free_3.conf" +CONF_4="test_anastasis_reducer_free_4.conf" + + +# Configuration file will be edited, so we create one +# from the template. +CONF=`mktemp test_reducerXXXXXX.conf` +cp test_reducer.conf $CONF + +TMP_DIR=`mktemp -d keys-tmp-XXXXXX` +B1FILE=`mktemp test_reducer_stateB1XXXXXX` +B2FILE=`mktemp test_reducer_stateB2XXXXXX` +R1FILE=`mktemp test_reducer_stateR1XXXXXX` +R2FILE=`mktemp test_reducer_stateR2XXXXXX` +export B1FILE +export B2FILE +export R1FILE +export R2FILE + +# Install cleanup handler (except for kill -9) +trap cleanup EXIT + +# Check we can actually run +echo -n "Testing for jq" +jq -h > /dev/null || exit_skip "jq required" +echo " FOUND" +echo -n "Testing for timeout" +timeout --help > /dev/null || exit_skip "timeout required" +echo " FOUND" +echo -n "Testing for anastasis-reducer ..." +anastasis-reducer -h > /dev/null || exit_skip "anastasis-reducer required" +echo " FOUND" + +echo -n "Testing for anastasis-httpd" +anastasis-httpd -h >/dev/null /dev/null 2>/dev/null || true +createdb $TARGET_DB_1 || exit_skip "Could not create database $TARGET_DB_1" +anastasis-dbinit -c $CONF_1 2> anastasis-dbinit_1.log +dropdb $TARGET_DB_2 >/dev/null 2>/dev/null || true +createdb $TARGET_DB_2 || exit_skip "Could not create database $TARGET_DB_2" +anastasis-dbinit -c $CONF_2 2> anastasis-dbinit_2.log +dropdb $TARGET_DB_3 >/dev/null 2>/dev/null || true +createdb $TARGET_DB_3 || exit_skip "Could not create database $TARGET_DB_3" +anastasis-dbinit -c $CONF_3 2> anastasis-dbinit_3.log +dropdb $TARGET_DB_4 >/dev/null 2>/dev/null || true +createdb $TARGET_DB_4 || exit_skip "Could not create database $TARGET_DB_4" +anastasis-dbinit -c $CONF_4 2> anastasis-dbinit_4.log + +echo " OK" + +echo -n "Launching anastasis services ..." +PREFIX="" #valgrind +$PREFIX anastasis-httpd -c $CONF_1 2> anastasis-httpd_1.log & +PPID_1=$! +$PREFIX anastasis-httpd -c $CONF_2 2> anastasis-httpd_2.log & +PPID_2=$! +$PREFIX anastasis-httpd -c $CONF_3 2> anastasis-httpd_3.log & +PPID_3=$! +$PREFIX anastasis-httpd -c $CONF_4 2> anastasis-httpd_4.log & +PPID_4=$! +export PPID_1 +export PPID_2 +export PPID_3 +export PPID_4 + +echo -n "Waiting for anastasis services ..." + +# Wait for anastasis services to be available +for n in `seq 1 50` +do + echo -n "." + sleep 0.1 + OK=0 + # anastasis_01 + wget --tries=1 --timeout=1 http://localhost:8086/ -o /dev/null -O /dev/null >/dev/null || continue + # anastasis_02 + wget --tries=1 --timeout=1 http://localhost:8087/ -o /dev/null -O /dev/null >/dev/null || continue + # anastasis_03 + wget --tries=1 --timeout=1 http://localhost:8088/ -o /dev/null -O /dev/null >/dev/null || continue + # anastasis_04 + wget --tries=1 --timeout=1 http://localhost:8089/ -o /dev/null -O /dev/null >/dev/null || continue + OK=1 + break +done + +if [ 1 != $OK ] +then + exit_skip "Failed to launch anastasis services" +fi +echo "OK" + +echo -n "Running backup logic ...," +anastasis-reducer -b > $B1FILE +echo -n "." +anastasis-reducer -a \ + '{"continent": "Demoworld"}' \ + select_continent < $B1FILE > $B2FILE +echo -n "." +anastasis-reducer -a \ + '{"country_code": "xx"}' \ + select_country < $B2FILE > $B1FILE +echo -n "." + +kill -SIGSTOP $PPID_4 +START=`date '+%s'` +timeout 10 anastasis-reducer -L DEBUG -a \ + '{"identity_attributes": { + "full_name": "Max Musterman", + "sq_number": "4", + "birthdate": "2000-01-01"}}' \ + enter_user_attributes < $B1FILE > $B2FILE || true +END=`date '+%s'` +DELTA=`expr $END - $START` +kill -SIGCONT $PPID_4 + +if test $DELTA -ge 5 +then + bash + exit_fail "Reducer hangs on suspended provider in 'enter_user_attributes'" +fi + +cat $B2FILE > $B1FILE +echo -n "," +sync_providers $B1FILE $B2FILE +echo -n "," +# "91GPWWR" encodes "Hans" +anastasis-reducer -a \ + '{"authentication_method": { + "type": "question", + "instructions": "What is your name?", + "challenge": "91GPWWR" + } }' \ + add_authentication < $B2FILE > $B1FILE +echo -n "." +# "64S36" encodes "123" +anastasis-reducer -a \ + '{"authentication_method": { + "type": "question", + "instructions": "How old are you?", + "challenge": "64S36" + } }' \ + add_authentication < $B1FILE > $B2FILE +echo -n "." +# "9NGQ4WR" encodes "Mars" +anastasis-reducer -a \ + '{"authentication_method": { + "type": "question", + "instructions": "Where do you live?", + "challenge": "9NGQ4WR" + } }' \ + add_authentication < $B2FILE > $B1FILE +echo -n "." +# Finished adding authentication methods +anastasis-reducer \ + next < $B1FILE > $B2FILE + + +echo -n "," +# Finished policy review +anastasis-reducer \ + next < $B2FILE > $B1FILE +echo -n "." + +# Note: 'secret' must here be a Crockford base32-encoded value +anastasis-reducer -a \ + '{"secret": { "value" : "VERYHARDT0GVESSSECRET", "mime" : "text/plain" }}' \ + enter_secret < $B1FILE > $B2FILE +anastasis-reducer next $B2FILE $B1FILE +echo " OK" + +echo -n "Final backup checks ..." +STATE=`jq -r -e .backup_state < $B1FILE` +if test "$STATE" != "BACKUP_FINISHED" +then + exit_fail "Expected new state to be 'BACKUP_FINISHED', got '$STATE'" +fi + +jq -r -e .core_secret < $B1FILE > /dev/null && exit_fail "'core_secret' was not cleared upon success" + +echo " OK" + + +echo -n "Running recovery basic logic ..." +anastasis-reducer -r > $R1FILE +anastasis-reducer -a \ + '{"continent": "Demoworld"}' \ + select_continent < $R1FILE > $R2FILE +anastasis-reducer -a \ + '{"country_code": "xx" }' \ + select_country < $R2FILE > $R1FILE +anastasis-reducer -a '{"identity_attributes": { "full_name": "Max Musterman", "sq_number": "4", "birthdate": "2000-01-01" }}' enter_user_attributes < $R1FILE > $R2FILE + + +STATE=`jq -r -e .recovery_state < $R2FILE` +if test "$STATE" != "SECRET_SELECTING" +then + exit_fail "Expected new state to be 'SECRET_SELECTING', got '$STATE'" +fi +echo " OK" + +echo -n "Adding provider (to ensure it is loaded)" +anastasis-reducer -a '{"provider_url" : "http://localhost:8086/" }' add_provider < $R2FILE > $R1FILE +echo " OK" + +echo -n "Selecting secret to recover" +anastasis-reducer -a '{"attribute_mask": 0, "providers" : [ { "version": 1, "url" : "http://localhost:8086/" } ] }' select_version < $R1FILE > $R2FILE + +STATE=`jq -r -e .recovery_state < $R2FILE` +if test "$STATE" != "CHALLENGE_SELECTING" +then + exit_fail "Expected new state to be 'CHALLENGE_SELECTING', got '$STATE'" +fi +echo " OK" + +cat $R2FILE > $R1FILE +sync_providers $R1FILE $R2FILE + +echo -n "Running challenge logic ..." + +cat $R2FILE | jq . + +UUID0=`jq -r -e .recovery_information.challenges[0].uuid < $R2FILE` +UUID1=`jq -r -e .recovery_information.challenges[1].uuid < $R2FILE` +UUID2=`jq -r -e .recovery_information.challenges[2].uuid < $R2FILE` +UUID0Q=`jq -r -e .recovery_information.challenges[0].instructions < $R2FILE` +UUID1Q=`jq -r -e .recovery_information.challenges[1].instructions < $R2FILE` +UUID2Q=`jq -r -e .recovery_information.challenges[2].instructions < $R2FILE` + +if test "$UUID2Q" = 'How old are you?' +then + AGE_UUID=$UUID2 +elif test "$UUID1Q" = 'How old are you?' +then + AGE_UUID=$UUID1 +else + AGE_UUID=$UUID0 +fi + +if test "$UUID2Q" = 'What is your name?' +then + NAME_UUID=$UUID2 +elif test "$UUID1Q" = 'What is your name?' +then + NAME_UUID=$UUID1 +else + NAME_UUID=$UUID0 +fi + +anastasis-reducer -a \ + "$(jq -n ' + { + uuid: $UUID + }' \ + --arg UUID "$NAME_UUID" + )" \ + select_challenge < $R2FILE > $R1FILE + +anastasis-reducer -a '{"answer": "Hans"}' \ + solve_challenge < $R1FILE > $R2FILE + +anastasis-reducer -a \ + "$(jq -n ' + { + uuid: $UUID + }' \ + --arg UUID "$AGE_UUID" + )" \ + select_challenge < $R2FILE > $R1FILE + +anastasis-reducer -a '{"answer": "123"}' \ + solve_challenge < $R1FILE > $R2FILE + +echo " OK" + +echo -n "Checking recovered secret ..." +# finally: check here that we recovered the secret... + +STATE=`jq -r -e .recovery_state < $R2FILE` +if test "$STATE" != "RECOVERY_FINISHED" +then + jq -e . $R2FILE + exit_fail "Expected new state to be 'RECOVERY_FINISHED', got '$STATE'" +fi + +SECRET=`jq -r -e .core_secret.value < $R2FILE` +if test "$SECRET" != "VERYHARDT0GVESSSECRET" +then + jq -e . $R2FILE + exit_fail "Expected recovered secret to be 'VERYHARDT0GVESSSECRET', got '$SECRET'" +fi + +MIME=`jq -r -e .core_secret.mime < $R2FILE` +if test "$MIME" != "text/plain" +then + jq -e . $R2FILE + exit_fail "Expected recovered mime to be 'text/plain', got '$MIME'" +fi + +echo " OK" + +exit 0 -- cgit v1.2.3