the-bastion/tests/functional/tests.d/370-mfa.sh
2020-12-03 13:20:53 +00:00

388 lines
18 KiB
Bash

# vim: set filetype=sh ts=4 sw=4 sts=4 et:
# shellcheck shell=bash
# shellcheck disable=SC2086,SC2016,SC2046
# below: convoluted way that forces shellcheck to source our caller
# shellcheck source=tests/functional/launch_tests_on_instance.sh
. "$(dirname "${BASH_SOURCE[0]}")"/dummy
testsuite_mfa()
{
grant accountCreate
grant accountModify
# create account4
success mfa a0_create_a4 $a0 --osh accountCreate --always-active --account $account4 --uid $uid4 --public-key "\"$(cat $account4key1file.pub)\""
json .error_code OK .command accountCreate .value null
# set account4 as mfa password required
success mfa a0_accountModify_passreq_a4 $a0 --osh accountModify --account $account4 --mfa-password-required yes
json .error_code OK .command accountModify .value.mfa_password_required.error_code OK
# set account4 as mfa password required (dupe)
success mfa a0_accountModify_passreq_a4_dupe $a0 --osh accountModify --account $account4 --mfa-password-required yes
json .error_code OK .command accountModify .value.mfa_password_required.error_code OK_NO_CHANGE
# now try to connect with account4
run mfa a4_connect_with_passreq $a4 --osh groupList
retvalshouldbe 122
json .error_code KO_MFA_PASSWORD_SETUP_REQUIRED
# setup our password, step1
run mfa a4_setup_pass_step1of2 $a4f --osh selfMFASetupPassword --yes
retvalshouldbe 124
contain 'enter this:'
a4_password_tmp=$(get_stdout | grep -Eo 'enter this: [a-zA-Z0-9_-]+' | sed -e 's/enter this: //')
# setup our password, step2
a4_password=']BkL>3x#T)g~~B#rLv^!T2&N'
script mfa a4_setup_pass_step2of2 "echo 'set timeout 30; \
spawn $a4 --osh selfMFASetupPassword --yes; \
expect \":\" { sleep 0.2; send \"$a4_password_tmp\\n\"; }; \
expect \":\" { sleep 0.2; send \"$a4_password\\n\"; }; \
expect \":\" { sleep 0.2; send \"$a4_password\\n\"; }; \
expect eof; \
lassign [wait] pid spawnid value value; \
exit \$value' | expect -f -"
retvalshouldbe 0
unset a4_password_tmp
nocontain 'enter this:'
nocontain 'unchanged'
nocontain 'sorry'
json .command selfMFASetupPassword .error_code OK
# now try to connect after we have a pass
run mfa a4_connect_after_pass $a4f --osh groupList
if [ "$HAS_MFA" = 1 ] || [ "$HAS_MFA_PASSWORD" = 1 ]; then
# now we need a password, we don't enter it so it'll timeout (124)
retvalshouldbe 124
contain 'Multi-Factor Authentication enabled, an additional authentication factor is required (password).'
contain REGEX 'Password:|Password for'
nocontain 'JSON_OUTPUT'
else
# our system doesn't support MFA so it still works without asking for a password
retvalshouldbe 0
nocontain 'Multi-Factor Authentication enabled'
nocontain REGEX 'Password:|Password for'
json .command groupList .error_code OK_EMPTY
fi
if [ "$HAS_PAMTESTER" = 1 ]; then
grant groupCreate
success mfa a0_create_g3 $a0 --osh groupCreate --group $group3 --algo rsa --size 4096 --owner $account4
revoke groupCreate
# setup group to force JIT egress MFA
script mfa a4_modify_g3_egress_mfa "echo 'set timeout 30; \
spawn $a4 --osh groupModify --group $group3 --mfa-required any; \
expect \":\" { sleep 0.2; send \"$a4_password\\n\"; }; \
expect eof; \
lassign [wait] pid spawnid value value; \
exit \$value' | expect -f -"
retvalshouldbe 0
contain 'Multi-Factor Authentication enabled, an additional authentication factor is required (password).'
contain REGEX 'Password:|Password for'
json .command groupModify .error_code OK
# check that the MFA is set for the group
script mfa a4_verify_g3_egress_mfa "echo 'set timeout 30; \
spawn $a4 --osh groupInfo --group $group3; \
expect \":\" { sleep 0.2; send \"$a4_password\\n\"; }; \
expect eof; \
lassign [wait] pid spawnid value value; \
exit \$value' | expect -f -"
retvalshouldbe 0
contain 'Multi-Factor Authentication enabled, an additional authentication factor is required (password).'
contain REGEX 'Password:|Password for'
json .command groupInfo .error_code OK
json .value.mfa_required any
# add 127.7.7.7 to this group
script mfa a4_add_g3_server "echo 'set timeout 30; \
spawn $a4 --osh groupAddServer --group $group3 --host 127.7.7.7 --user-any --port-any --force; \
expect \":\" { sleep 0.2; send \"$a4_password\\n\"; }; \
expect eof; \
lassign [wait] pid spawnid value value; \
exit \$value' | expect -f -"
retvalshouldbe 0
contain 'Multi-Factor Authentication enabled, an additional authentication factor is required (password).'
contain REGEX 'Password:|Password for'
# connect to 127.7.7.7 with MFA JIT, bad password
script mfa a4_connect_g3_server_badpass "echo 'set timeout 45; \
spawn $a4 root@127.7.7.7; \
expect \"is required (password)\" { sleep 0.1; }; \
expect \":\" { sleep 0.2; send \"$a4_password\\n\"; }; \
expect \"is required (password)\" { sleep 0.1; }; \
expect \":\" { sleep 0.2; send \"BADPASSWORD\\n\"; }; \
expect \"is required (password)\" { sleep 0.1; }; \
expect \":\" { sleep 0.2; send \"BADPASSWORD\\n\"; }; \
expect \"is required (password)\" { sleep 0.1; }; \
expect \":\" { sleep 0.2; send \"BADPASSWORD\\n\\n\"; }; \
expect eof; \
lassign [wait] pid spawnid value value; \
exit \$value' | expect -f -"
retvalshouldbe 125
contain 'Multi-Factor Authentication enabled, an additional authentication factor is required (password).'
contain REGEX 'Password:|Password for'
contain 'pamtester: '
nocontain 'Permission denied'
# connect to 127.7.7.7 with MFA JIT, good password
script mfa a4_connect_g3_server_goodpass "echo 'set timeout 30; \
spawn $a4 root@127.7.7.7; \
expect \":\" { sleep 0.2; send \"$a4_password\\n\"; }; \
expect \"is required (password)\" { sleep 0.1; }; \
expect \":\" { sleep 0.2; send \"$a4_password\\n\"; }; \
expect eof; \
lassign [wait] pid spawnid value value; \
exit \$value' | expect -f -"
retvalshouldbe 255
contain 'Multi-Factor Authentication enabled, an additional authentication factor is required (password).'
contain REGEX 'Password:|Password for'
contain 'pamtester: successfully authenticated'
contain 'Permission denied'
# create another account
success mfa a0_create_a3 $a0 --osh accountCreate --always-active --account $account3 --uid $uid3 --public-key "\"$(cat $account3key1file.pub)\""
json .error_code OK .command accountCreate .value null
# set the account as bypass
success mfa a0_set_a3_as_robot $a0 --osh accountModify --account $account3 --mfa-password-required bypass
json .command accountModify .error_code OK
# add to JIT MFA group
script mfa a0_add_a3_as_member "echo 'set timeout 30; \
spawn $a4 --osh groupAddMember --group $group3 --account $account3; \
expect \":\" { sleep 0.2; send \"$a4_password\\n\"; }; \
expect eof; \
lassign [wait] pid spawnid value value; \
exit \$value' | expect -f -"
json .command groupAddMember .error_code OK
# connect to 127.7.7.7 with MFA JIT, no MFA needed
run mfa a3_connect_g3_server_mfa_bypass $a3 root@127.7.7.7
retvalshouldbe 255
nocontain 'pamtester: successfully authenticated'
contain 'Permission denied'
# remove the account bypass
success mfa a0_unset_a3_as_robot $a0 --osh accountModify --account $account3 --mfa-password-required no
json .command accountModify .error_code OK
# connect to 127.7.7.7 with MFA JIT, password setup needed
run mfa a3_connect_mfa_jit_need_pass_setup $a3 root@127.7.7.7
json .error_code KO_MFA_ANY_SETUP_REQUIRED
grant groupDelete
script mfa a0_delete_g3 "$a0 --osh groupDelete --group $group3 <<< \"$group3\""
revoke groupDelete
grant accountDelete
script mfa a0_delete_a3 $a0 --osh accountDelete --account $account3 "<<< \"Yes, do as I say and delete $account3, kthxbye\""
retvalshouldbe 0
json .command accountDelete .error_code OK
revoke accountDelete
fi
# change our password
a4_password_new="rkw=*Ffyqs23"
if [ "$HAS_MFA" = 1 ] || [ "$HAS_MFA_PASSWORD" = 1 ]; then
script mfa a4_change_pass "echo 'set timeout 30; \
spawn $a4 --osh selfMFASetupPassword --yes; \
expect \":\" { sleep 0.2; send \"$a4_password\\n\"; }; \
expect \":\" { sleep 0.2; send \"$a4_password\\n\"; }; \
expect \":\" { sleep 0.2; send \"$a4_password_new\\n\"; }; \
expect \":\" { sleep 0.2; send \"$a4_password_new\\n\"; }; \
expect eof; \
lassign [wait] pid spawnid value value; \
exit \$value' | expect -f -"
retvalshouldbe 0
contain 'Multi-Factor Authentication enabled, an additional authentication factor is required (password).'
contain REGEX 'Password:|Password for'
else
script mfa a4_change_pass "echo 'set timeout 30; \
spawn $a4 --osh selfMFASetupPassword --yes; \
expect \":\" { sleep 0.2; send \"$a4_password\\n\"; }; \
expect \":\" { sleep 0.2; send \"$a4_password_new\\n\"; }; \
expect \":\" { sleep 0.2; send \"$a4_password_new\\n\"; }; \
expect eof; \
lassign [wait] pid spawnid value value; \
exit \$value' | expect -f -"
retvalshouldbe 0
nocontain 'Multi-Factor Authentication enabled'
fi
nocontain 'enter this:'
nocontain 'unchanged'
json .command selfMFASetupPassword .error_code OK
a4_password="$a4_password_new"
unset a4_password_new
if [ "$HAS_MFA" = 1 ] || [ "$HAS_MFA_PASSWORD" = 1 ]; then
script mfa a4_connect_with_pass "echo 'set timeout 30; \
spawn $a4 --osh groupList; \
expect \":\" { sleep 0.2; send \"$a4_password\\n\"; }; \
expect eof; \
lassign [wait] pid spawnid value value; \
exit \$value' | expect -f -"
retvalshouldbe 0
contain 'Multi-Factor Authentication enabled, an additional authentication factor is required (password).'
contain REGEX 'Password:|Password for'
json .command groupList .error_code OK_EMPTY
fi
# set account4 as mfa totp required
success mfa a0_accountModify_totpreq_a4 $a0 --osh accountModify --account $account4 --mfa-totp-required yes
json .error_code OK .command accountModify .value.mfa_totp_required.error_code OK
# set account4 as mfa totp required (dupe)
success mfa a0_accountModify_totpreq_a4_dupe $a0 --osh accountModify --account $account4 --mfa-totp-required yes
json .error_code OK .command accountModify .value.mfa_totp_required.error_code OK_NO_CHANGE
# now try to connect with account4
if [ "$HAS_MFA" = 1 ] || [ "$HAS_MFA_PASSWORD" = 1 ]; then
script mfa a4_connect_with_totpreq "echo 'set timeout 30; \
spawn $a4 --osh groupList; \
expect \":\" { sleep 0.2; send \"$a4_password\\n\"; }; \
expect eof; \
lassign [wait] pid spawnid value value; \
exit \$value' | expect -f -"
else
run mfa a4_connect_with_totpreq $a4 --osh groupList
fi
retvalshouldbe 123
json .error_code KO_MFA_TOTP_SETUP_REQUIRED
if [ "$HAS_MFA" = 1 ]; then
# setup totp
script mfa a4_setup_totp "echo 'set timeout 30; \
spawn $a4 --osh selfMFASetupTOTP --no-confirm; \
expect \"word:\" { sleep 0.2; send \"$a4_password\\n\"; }; \
expect \"word:\" { sleep 0.2; send \"$a4_password\\n\"; }; \
expect eof; \
lassign [wait] pid spawnid value value; \
exit \$value' | expect -f -"
retvalshouldbe 0
contain 'Multi-Factor Authentication enabled, an additional authentication factor is required (password).'
contain REGEX 'Password:|Password for'
a4_totp_code_1=$(get_stdout | grep -A1 'Your emergency scratch codes are:' | tail -n1 | tr -d '[:space:]')
#a4_totp_code_2=$(get_stdout | grep -A2 'Your emergency scratch codes are:' | tail -n1 | tr -d '[:space:]')
#a4_totp_code_3=$(get_stdout | grep -A3 'Your emergency scratch codes are:' | tail -n1 | tr -d '[:space:]')
#a4_totp_code_4=$(get_stdout | grep -A4 'Your emergency scratch codes are:' | tail -n1 | tr -d '[:space:]')
# login and fail without totp (timeout)
script mfa a4_connect_after_totp_fail "echo 'set timeout 30; \
spawn $a4 --osh groupList; \
expect \"word:\" { sleep 0.2; send \"$a4_password\\n\"; }; \
expect eof; \
lassign [wait] pid spawnid value value; \
exit \$value' | expect -f -"
retvalshouldbe 124
contain 'Multi-Factor Authentication enabled, an additional authentication factor is required (password).'
contain 'Multi-Factor Authentication enabled, an additional authentication factor is required (OTP).'
contain 'Your password expires on'
contain 'in 89 days'
contain REGEX 'Password:|Password for'
contain 'Verification code:'
nocontain 'JSON_OUTPUT'
# success with password + totp
script mfa a4_connect_after_totp_ok "echo 'set timeout 30; \
spawn $a4 --osh groupList; \
expect \"word:\" { sleep 0.2; send \"$a4_password\\n\"; }; \
expect \"code:\" { sleep 0.2; send \"$a4_totp_code_1\\n\"; }; \
expect eof; \
lassign [wait] pid spawnid value value; \
exit \$value' | expect -f -"
retvalshouldbe 0
contain 'Multi-Factor Authentication enabled, an additional authentication factor is required (password).'
contain 'Multi-Factor Authentication enabled, an additional authentication factor is required (OTP).'
contain REGEX 'Password:|Password for'
contain 'Verification code:'
json .command groupList .error_code OK_EMPTY
# totp scratch codes don't work twice
script mfa a4_connect_after_totp_dupe "echo 'set timeout 30; \
spawn $a4 --osh groupList; \
expect \"word:\" { sleep 0.2; send \"$a4_password\\n\"; }; \
expect \"code:\" { sleep 0.2; send \"$a4_totp_code_1\\n\"; }; \
expect \"word:\" { exit 222; }; \
expect eof; \
lassign [wait] pid spawnid value value; \
exit \$value' | expect -f -"
retvalshouldbe 222
contain 'Multi-Factor Authentication enabled, an additional authentication factor is required (password).'
contain 'Multi-Factor Authentication enabled, an additional authentication factor is required (OTP).'
contain REGEX 'Password:|Password for'
contain 'Verification code:'
nocontain 'JSON_OUTPUT'
# set pam bypass on account4 (dupe)
success mfa a0_set_pambypass_a4 $a0 --osh accountModify --account $account4 --pam-auth-bypass yes
json .error_code OK .command accountModify .value.pam_auth_bypass.error_code OK
# set pam bypass on account4
success mfa a0_set_pambypass_a4_dupe $a0 --osh accountModify --account $account4 --pam-auth-bypass yes
json .error_code OK .command accountModify .value.pam_auth_bypass.error_code OK_NO_CHANGE
# we don't provide password or totp, it should work because bypass
success mfa a4_pam_auth_bypass $a4 --osh groupList
json .command groupList .error_code OK_EMPTY
# remove requirement of password and totp for account4, also remove bypass
success mfa a0_remove_mfa_req_a4 $a0 --osh accountModify --account $account4 --pam-auth-bypass no --mfa-totp-required no --mfa-password-required no
json .error_code OK .command accountModify .value.pam_auth_bypass.error_code OK .value.mfa_totp_required.error_code OK .value.mfa_password_required.error_code OK
# remove requirement of password and totp for account4, also remove bypass (dupe)
success mfa a0_remove_mfa_req_a4_dupe $a0 --osh accountModify --account $account4 --pam-auth-bypass no --mfa-totp-required no --mfa-password-required no
json .error_code OK .command accountModify .value.pam_auth_bypass.error_code OK_NO_CHANGE .value.mfa_totp_required.error_code OK_NO_CHANGE .value.mfa_password_required.error_code OK_NO_CHANGE
# FIXME
# # reset totp
# script mfa a4_reset_totp "echo 'set timeout 30; \
# spawn $a4 --osh selfMFAResetTOTP; \
# expect \"word:\" { send_user \"premier password\\n\"; send \"$a4_password\\n\"; }; \
# expect \"code:\" { send_user \"premier code\\n\"; send \"$a4_totp_code_2\\n\"; }; \
# expect \"word:\" { send_user \"second password\\n\"; send \"$a4_password\\n\"; }; \
# expect \"code:\" { send_user \"second code\\n\"; send \"$a4_totp_code_3\\n\"; }; \
# expect eof; \
# lassign [wait] pid spawnid value value; \
# exit \$value' | expect -f -"
# retvalshouldbe 0
# json .error_code OK .command selfMFAResetTOTP
#
# # reset password
# script mfa a4_reset_password "echo 'set timeout 30; \
# spawn $a4 --osh selfMFAResetPassword; \
# expect \"word:\" { send \"$a4_password\\n\"; }; \
# expect eof; \
# lassign [wait] pid spawnid value value; \
# exit \$value' | expect -f -"
# retvalshouldbe 0
# json .error_code OK .command selfMFAResetPassword
# # now we no longer need MFA
# success mfa a4_mfa_deconfigured $a4 --osh groupList
# json .command groupList .error_code OK_EMPTY
fi
grant accountRevokeCommand
revoke accountModify
grant accountDelete
# remove account
script mfa a0_delete_a4 $a0 --osh accountDelete --account $account4 "<<< \"Yes, do as I say and delete $account4, kthxbye\""
retvalshouldbe 0
json .command accountDelete .error_code OK
revoke accountDelete
}
testsuite_mfa