test_anastasis_reducer_recovery_hanging.sh (10590B)
1 #!/bin/bash 2 # This file is in the public domain. 3 # Runs tests with a 'hanging' Anastasis provider. 4 5 set -eu 6 #set -x 7 8 # Exit, with status code "skip" (no 'real' failure) 9 function exit_skip() { 10 echo " SKIP: $1" 11 exit 77 12 } 13 14 # Exit, with error message (hard failure) 15 function exit_fail() { 16 echo " FAIL: $1" 17 exit 1 18 } 19 20 # Cleanup to run whenever we exit 21 function cleanup() 22 { 23 for n in $(jobs -p) 24 do 25 kill -SIGCONT $n # in case suspended... 26 kill $n 2> /dev/null || true 27 done 28 rm -rf $CONF $R1FILE $R2FILE $B1FILE $B2FILE $TMP_DIR 29 wait 30 } 31 32 function sync_providers() { 33 infile=$1 34 outfile=$2 35 echo "Synchronizing providers" 36 # Sync with providers (up to 3 providers aren't synced here) 37 for x in 1 2 3; do 38 echo "Synchronizing providers (round $x)" 39 #anastasis-reducer sync_providers < $infile > $outfile 2> /dev/null || true 40 anastasis-reducer sync_providers < $infile > $outfile || true 41 CODE=$(jq -r -e ".code // 0" < $outfile) 42 # ANASTASIS_REDUCER_PROVIDERS_ALREADY_SYNCED 43 # FIXME: Temporary workaround for C reducer. See #7227. 44 if test "$CODE" = "8420"; then 45 # restore previous non-error state 46 cat $infile > $outfile 47 break 48 fi 49 # ANASTASIS_REDUCER_ACTION_INVALID 50 if test "$CODE" = "8400"; then 51 # restore previous non-error state 52 cat $infile > $outfile 53 break 54 fi 55 if test "$CODE" != "0"; then 56 exit_fail "Expected no error or 8420/8400, got $CODE" 57 fi 58 cat $outfile > $infile 59 done 60 echo "Providers synced." 61 } 62 63 64 CONF_1="test_anastasis_reducer_free_1.conf" 65 CONF_2="test_anastasis_reducer_free_2.conf" 66 CONF_3="test_anastasis_reducer_free_3.conf" 67 CONF_4="test_anastasis_reducer_free_4.conf" 68 69 70 # Configuration file will be edited, so we create one 71 # from the template. 72 CONF=$(mktemp test_reducerXXXXXX.conf) 73 cp test_reducer.conf $CONF 74 75 TMP_DIR=`mktemp -d keys-tmp-XXXXXX` 76 B1FILE=`mktemp test_reducer_stateB1XXXXXX` 77 B2FILE=`mktemp test_reducer_stateB2XXXXXX` 78 R1FILE=`mktemp test_reducer_stateR1XXXXXX` 79 R2FILE=`mktemp test_reducer_stateR2XXXXXX` 80 export B1FILE 81 export B2FILE 82 export R1FILE 83 export R2FILE 84 85 # Install cleanup handler (except for kill -9) 86 trap cleanup EXIT 87 88 # Check we can actually run 89 echo -n "Testing for jq" 90 jq -h > /dev/null || exit_skip "jq required" 91 echo " FOUND" 92 echo -n "Testing for timeout" 93 timeout --help > /dev/null || exit_skip "timeout required" 94 echo " FOUND" 95 echo -n "Testing for anastasis-reducer ..." 96 anastasis-reducer -h > /dev/null || exit_skip "anastasis-reducer required" 97 echo " FOUND" 98 99 echo -n "Testing for anastasis-httpd" 100 anastasis-httpd -h >/dev/null </dev/null || exit_skip " MISSING" 101 echo " FOUND" 102 103 echo -n "Initialize anastasis database ..." 104 # Name of the Postgres database we will use for the script. 105 # Will be dropped, do NOT use anything that might be used 106 # elsewhere 107 TARGET_DB_1=`anastasis-config -c $CONF_1 -s stasis-postgres -o CONFIG | sed -e "s/^postgres:\/\/\///"` 108 TARGET_DB_2=`anastasis-config -c $CONF_2 -s stasis-postgres -o CONFIG | sed -e "s/^postgres:\/\/\///"` 109 TARGET_DB_3=`anastasis-config -c $CONF_3 -s stasis-postgres -o CONFIG | sed -e "s/^postgres:\/\/\///"` 110 TARGET_DB_4=`anastasis-config -c $CONF_4 -s stasis-postgres -o CONFIG | sed -e "s/^postgres:\/\/\///"` 111 112 dropdb $TARGET_DB_1 >/dev/null 2>/dev/null || true 113 createdb $TARGET_DB_1 || exit_skip "Could not create database $TARGET_DB_1" 114 anastasis-dbinit -c $CONF_1 2> anastasis-dbinit_1.log 115 dropdb $TARGET_DB_2 >/dev/null 2>/dev/null || true 116 createdb $TARGET_DB_2 || exit_skip "Could not create database $TARGET_DB_2" 117 anastasis-dbinit -c $CONF_2 2> anastasis-dbinit_2.log 118 dropdb $TARGET_DB_3 >/dev/null 2>/dev/null || true 119 createdb $TARGET_DB_3 || exit_skip "Could not create database $TARGET_DB_3" 120 anastasis-dbinit -c $CONF_3 2> anastasis-dbinit_3.log 121 dropdb $TARGET_DB_4 >/dev/null 2>/dev/null || true 122 createdb $TARGET_DB_4 || exit_skip "Could not create database $TARGET_DB_4" 123 anastasis-dbinit -c $CONF_4 2> anastasis-dbinit_4.log 124 125 echo " OK" 126 127 echo -n "Launching anastasis services ..." 128 PREFIX="" #valgrind 129 $PREFIX anastasis-httpd -c $CONF_1 2> anastasis-httpd_1.log & 130 PPID_1=$! 131 $PREFIX anastasis-httpd -c $CONF_2 2> anastasis-httpd_2.log & 132 PPID_2=$! 133 $PREFIX anastasis-httpd -c $CONF_3 2> anastasis-httpd_3.log & 134 PPID_3=$! 135 $PREFIX anastasis-httpd -c $CONF_4 2> anastasis-httpd_4.log & 136 PPID_4=$! 137 export PPID_1 138 export PPID_2 139 export PPID_3 140 export PPID_4 141 142 echo -n "Waiting for anastasis services ..." 143 144 # Wait for anastasis services to be available 145 for n in `seq 1 50` 146 do 147 echo -n "." 148 sleep 0.1 149 OK=0 150 # anastasis_01 151 wget --tries=1 --timeout=1 http://localhost:8086/ -o /dev/null -O /dev/null >/dev/null || continue 152 # anastasis_02 153 wget --tries=1 --timeout=1 http://localhost:8087/ -o /dev/null -O /dev/null >/dev/null || continue 154 # anastasis_03 155 wget --tries=1 --timeout=1 http://localhost:8088/ -o /dev/null -O /dev/null >/dev/null || continue 156 # anastasis_04 157 wget --tries=1 --timeout=1 http://localhost:8089/ -o /dev/null -O /dev/null >/dev/null || continue 158 OK=1 159 break 160 done 161 162 if [ 1 != $OK ] 163 then 164 exit_skip "Failed to launch anastasis services" 165 fi 166 echo "OK" 167 168 echo -n "Running backup logic ...," 169 anastasis-reducer -b > $B1FILE 170 echo -n "." 171 anastasis-reducer -a \ 172 '{"continent": "Demoworld"}' \ 173 select_continent < $B1FILE > $B2FILE 174 echo -n "." 175 anastasis-reducer -a \ 176 '{"country_code": "xx"}' \ 177 select_country < $B2FILE > $B1FILE 178 echo -n "." 179 180 kill -SIGSTOP $PPID_4 181 START=`date '+%s'` 182 timeout 10 anastasis-reducer -L DEBUG -a \ 183 '{"identity_attributes": { 184 "full_name": "Max Musterman", 185 "sq_number": "4", 186 "birthdate": "2000-01-01"}}' \ 187 enter_user_attributes < $B1FILE > $B2FILE || true 188 END=`date '+%s'` 189 DELTA=`expr $END - $START` 190 kill -SIGCONT $PPID_4 191 192 if test $DELTA -ge 5 193 then 194 exit_fail "Reducer hangs on suspended provider in 'enter_user_attributes'" 195 fi 196 197 cat $B2FILE > $B1FILE 198 echo -n "," 199 sync_providers $B1FILE $B2FILE 200 echo -n "," 201 # "91GPWWR" encodes "Hans" 202 anastasis-reducer -a \ 203 '{"authentication_method": { 204 "type": "question", 205 "instructions": "What is your name?", 206 "challenge": "91GPWWR" 207 } }' \ 208 add_authentication < $B2FILE > $B1FILE 209 echo -n "." 210 # "64S36" encodes "123" 211 anastasis-reducer -a \ 212 '{"authentication_method": { 213 "type": "question", 214 "instructions": "How old are you?", 215 "challenge": "64S36" 216 } }' \ 217 add_authentication < $B1FILE > $B2FILE 218 echo -n "." 219 # "9NGQ4WR" encodes "Mars" 220 anastasis-reducer -a \ 221 '{"authentication_method": { 222 "type": "question", 223 "instructions": "Where do you live?", 224 "challenge": "9NGQ4WR" 225 } }' \ 226 add_authentication < $B2FILE > $B1FILE 227 echo -n "." 228 # Finished adding authentication methods 229 anastasis-reducer \ 230 next < $B1FILE > $B2FILE 231 232 233 echo -n "," 234 # Finished policy review 235 anastasis-reducer \ 236 next < $B2FILE > $B1FILE 237 echo -n "." 238 239 # Note: 'secret' must here be a Crockford base32-encoded value 240 anastasis-reducer -a \ 241 '{"secret": { "value" : "VERYHARDT0GVESSSECRET", "mime" : "text/plain" }}' \ 242 enter_secret < $B1FILE > $B2FILE 243 anastasis-reducer next $B2FILE $B1FILE 244 echo " OK" 245 246 echo -n "Final backup checks ..." 247 STATE=`jq -r -e .backup_state < $B1FILE` 248 if test "$STATE" != "BACKUP_FINISHED" 249 then 250 exit_fail "Expected new state to be 'BACKUP_FINISHED', got '$STATE'" 251 fi 252 253 jq -r -e .core_secret < $B1FILE > /dev/null && exit_fail "'core_secret' was not cleared upon success" 254 255 echo " OK" 256 257 258 echo -n "Running recovery basic logic ..." 259 anastasis-reducer -r > $R1FILE 260 anastasis-reducer -a \ 261 '{"continent": "Demoworld"}' \ 262 select_continent < $R1FILE > $R2FILE 263 anastasis-reducer -a \ 264 '{"country_code": "xx" }' \ 265 select_country < $R2FILE > $R1FILE 266 anastasis-reducer -a '{"identity_attributes": { "full_name": "Max Musterman", "sq_number": "4", "birthdate": "2000-01-01" }}' enter_user_attributes < $R1FILE > $R2FILE 267 268 269 STATE=`jq -r -e .recovery_state < $R2FILE` 270 if test "$STATE" != "SECRET_SELECTING" 271 then 272 exit_fail "Expected new state to be 'SECRET_SELECTING', got '$STATE'" 273 fi 274 echo " OK" 275 276 echo -n "Adding provider (to ensure it is loaded)" 277 anastasis-reducer -a '{"provider_url" : "http://localhost:8086/" }' add_provider < $R2FILE > $R1FILE 278 echo " OK" 279 280 echo -n "Selecting secret to recover" 281 anastasis-reducer -a '{"attribute_mask": 0, "providers" : [ { "version": 1, "url" : "http://localhost:8086/" } ] }' select_version < $R1FILE > $R2FILE 282 283 STATE=`jq -r -e .recovery_state < $R2FILE` 284 if test "$STATE" != "CHALLENGE_SELECTING" 285 then 286 exit_fail "Expected new state to be 'CHALLENGE_SELECTING', got '$STATE'" 287 fi 288 echo " OK" 289 290 cat $R2FILE > $R1FILE 291 sync_providers $R1FILE $R2FILE 292 293 echo -n "Running challenge logic ..." 294 295 cat $R2FILE | jq . 296 297 UUID0=`jq -r -e .recovery_information.challenges[0].uuid < $R2FILE` 298 UUID1=`jq -r -e .recovery_information.challenges[1].uuid < $R2FILE` 299 UUID2=`jq -r -e .recovery_information.challenges[2].uuid < $R2FILE` 300 UUID0Q=`jq -r -e .recovery_information.challenges[0].instructions < $R2FILE` 301 UUID1Q=`jq -r -e .recovery_information.challenges[1].instructions < $R2FILE` 302 UUID2Q=`jq -r -e .recovery_information.challenges[2].instructions < $R2FILE` 303 304 if test "$UUID2Q" = 'How old are you?' 305 then 306 AGE_UUID=$UUID2 307 elif test "$UUID1Q" = 'How old are you?' 308 then 309 AGE_UUID=$UUID1 310 else 311 AGE_UUID=$UUID0 312 fi 313 314 if test "$UUID2Q" = 'What is your name?' 315 then 316 NAME_UUID=$UUID2 317 elif test "$UUID1Q" = 'What is your name?' 318 then 319 NAME_UUID=$UUID1 320 else 321 NAME_UUID=$UUID0 322 fi 323 324 anastasis-reducer -a \ 325 "$(jq -n ' 326 { 327 uuid: $UUID 328 }' \ 329 --arg UUID "$NAME_UUID" 330 )" \ 331 select_challenge < $R2FILE > $R1FILE 332 333 anastasis-reducer -a '{"answer": "Hans"}' \ 334 solve_challenge < $R1FILE > $R2FILE 335 336 anastasis-reducer -a \ 337 "$(jq -n ' 338 { 339 uuid: $UUID 340 }' \ 341 --arg UUID "$AGE_UUID" 342 )" \ 343 select_challenge < $R2FILE > $R1FILE 344 345 anastasis-reducer -a '{"answer": "123"}' \ 346 solve_challenge < $R1FILE > $R2FILE 347 348 echo " OK" 349 350 echo -n "Checking recovered secret ..." 351 # finally: check here that we recovered the secret... 352 353 STATE=$(jq -r -e .recovery_state < "$R2FILE") 354 if test "$STATE" != "RECOVERY_FINISHED" 355 then 356 jq -e . $R2FILE 357 exit_fail "Expected new state to be 'RECOVERY_FINISHED', got '$STATE'" 358 fi 359 360 SECRET=$(jq -r -e .core_secret.value < "$R2FILE") 361 if test "$SECRET" != "VERYHARDT0GVESSSECRET" 362 then 363 jq -e . "$R2FILE" 364 exit_fail "Expected recovered secret to be 'VERYHARDT0GVESSSECRET', got '$SECRET'" 365 fi 366 367 MIME=$(jq -r -e .core_secret.mime < "$R2FILE") 368 if test "$MIME" != "text/plain" 369 then 370 jq -e . $R2FILE 371 exit_fail "Expected recovered mime to be 'text/plain', got '$MIME'" 372 fi 373 374 echo " OK" 375 376 exit 0