@@ -10,6 +10,7 @@ SKIP_IINIT_FOR_PASSWORD=yes
1010export TESTUSER=" john"
1111export FIRST_PASSWORD=" =i;r@o\\ d&s" # somerods
1212export SECOND_PASSWORD=" otherrods"
13+ export CLIENT_AUTH_ERROR_EXITCODE=123
1314
1415ssl_hash () {
1516 openssl passwd -6 " $1 "
@@ -32,7 +33,7 @@ setup() {
3233 jq ' .irods_client_server_policy="CS_NEG_REFUSE"' > $CLIENT_JSON .$$ < $CLIENT_JSON && \
3334 mv $CLIENT_JSON .$$ $CLIENT_JSON
3435
35- sudo apt install irods-auth-plugin-pam-interactive-{client,server}
36+ sudo apt install -y irods-auth-plugin-pam-interactive-{client,server}
3637 SERVER_CONFIG=server_config.json
3738
3839 sudo -s << -EOF
@@ -57,11 +58,6 @@ setup() {
5758 sudo cp $BATS_TEST_DIRNAME /files_for_test012/pam_interactive /etc/pam.d/
5859 sudo mkdir /t012 && sudo gcc -o /t012/pam_clear_token.so -fno-stack-protector -shared -fPIC $BATS_TEST_DIRNAME /files_for_test012/pam_clear_token.c
5960
60- db_file=/t012/pam_userdb.db
61- sudo db_load -T -t hash " $db_file " <<< " ${TESTUSER}" $' \n ' " $( ssl_hash _${SECOND_PASSWORD} ) "
62- sudo chown root:root " $db_file "
63- sudo chmod 600 " $db_file "
64-
6561 # Tests require only the irods_environment.json
6662 rm -f ~ /.irods/.irodsA
6763
@@ -72,14 +68,20 @@ setup() {
7268 touch /tmp/test012_flag
7369}
7470
75- @test " pam_interactive_test_multistep_with_correct_passwords" {
76- :
77- echo "
71+ encode_2nd_password () {
72+ db_file=/t012/pam_userdb.db
73+ sudo db_load -T -t hash " $db_file " <<< " ${TESTUSER}" $' \n ' " $( ssl_hash ${1} ) "
74+ sudo chown root:root " $db_file "
75+ sudo chmod 600 " $db_file "
76+ }
77+
78+ SCRIPT="
7879import getpass
79- import irods
8080import os
81+
82+ import irods
83+ from irods.auth import ClientAuthError
8184from unittest.mock import patch
82- from irods.auth import FORCE_PASSWORD_PROMPT
8385
8486def getpass_new_callable(answers=()):
8587 class iterate_answers:
@@ -96,26 +98,55 @@ def getpass_new_callable(answers=()):
9698
9799home = None
98100
101+ pw_count = 0
102+
99103with patch(
100104 'getpass.getpass',
101105 new_callable=getpass_new_callable(answers=[os.environ['FIRST_PASSWORD'],os.environ['SECOND_PASSWORD']])
102106) as m:
103107 try:
104- sess = irods.helpers.make_session(test_server_version=False)
105- sess.set_auth_option_for_scheme('pam_interactive', FORCE_PASSWORD_PROMPT, True)
106- home = sess.collections.get(f'/{sess.zone}/home/{sess.username}')
108+ sess = irods.helpers.make_session(test_server_version=False)
109+ sess.set_auth_option_for_scheme('pam_interactive', irods.auth.FORCE_PASSWORD_PROMPT, True)
110+ home = sess.collections.get(f'/{sess.zone}/home/{sess.username}')
111+ except ClientAuthError as exc:
112+ # Note: The write to stdout, and the specific exit code, are necessary for the test assertions.
113+ # in test " pam_interactive_test_multistep_with_incorrect_2nd_password" below.
114+ print(f'ERROR: {exc!r}')
115+ exit(int(os.environ['CLIENT_AUTH_ERROR_EXITCODE']))
107116 finally:
108- pw_count = m.count
117+ pw_count = m.count
118+
119+ # Assert both passwords were prompted for.
120+ if pw_count < 2:
121+ print(f'************************ {pw_count = } < 2')
122+ exit(3)
109123
110- #if pw_count < 2:
111- # print(f'************************ {pw_count = } < 2')
112- # exit(3)
124+ # Assert home is defined, ie a session was successfully created and used to retrieve a collection object
113125if home is None:
114126 exit(2)
127+
115128username = os.environ['TESTUSER']
129+
130+ # Assert home contains the expected username.
116131if not home.path.endswith(f'/{username}'):
117132 exit(1)
118- " > /tmp/test012.py
119- # ##############################
120- python /tmp/test012.py >&3 2>&1
133+ "
134+
135+ @test " pam_interactive_test_multistep_with_incorrect_2nd_password" {
136+
137+ # We are using a deliberately munged password.
138+ encode_2nd_password " _${SECOND_PASSWORD} "
139+ local STATUS=" "
140+ OUTPUT=$( python -c " $SCRIPT " 2>&1 ) || STATUS=$?
141+
142+ # Here, we assert the process's exit and output conform to expectation. We want to
143+ # enforce that the stdout output stream contains the thrown exception name ("ClientAuthError")
144+ # as well as that the process exits with a particular error status.
145+ [ $STATUS = $CLIENT_AUTH_ERROR_EXITCODE ]
146+ [[ $OUTPUT =~ ClientAuthError ]]
147+ }
148+
149+ @test " pam_interactive_test_multistep_with_correct_2nd_password" {
150+ encode_2nd_password " ${SECOND_PASSWORD} "
151+ python -c " $SCRIPT "
121152}
0 commit comments