anastasis

Credential backup and recovery protocol and service
Log | Files | Refs | Submodules | README | LICENSE

test_anastasis_reducer_recovery_no_pay.sh (10065B)


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