Skip to content

Commit 9ce937a

Browse files
committed
Add UUID user id version of refresh_user_creds unit tests.
1 parent 3aff220 commit 9ce937a

1 file changed

Lines changed: 261 additions & 3 deletions

File tree

tests/test_mig_shared_griddaemons.py

Lines changed: 261 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,20 @@
2727

2828
"""Unit tests for the griddaemons helper functions"""
2929

30+
import binascii
3031
import os
3132
import time
3233
import unittest
3334

3435
# Imports required for the unit test wrapping
36+
from mig.shared.base import client_id_dir, distinguished_name_to_user
3537
from mig.shared.defaults import (
36-
# X509_USER_ID_FORMAT, UUID_USER_ID_FORMAT,
37-
READ_WRITE_ACCESS, READ_ONLY_ACCESS, WRITE_ONLY_ACCESS
38+
X509_USER_ID_FORMAT, UUID_USER_ID_FORMAT,
39+
READ_WRITE_ACCESS, READ_ONLY_ACCESS, WRITE_ONLY_ACCESS,
40+
keyword_auto
3841
)
3942
from mig.shared.useradm import (
40-
_ensure_dirs_needed_for_userdb # , generate_password_hash
43+
_ensure_dirs_needed_for_userdb, create_user # , generate_password_hash
4144
)
4245

4346
# Imports of the code under test
@@ -67,6 +70,34 @@
6770
TEST_USER_PW_HASH = "PBKDF2$sha256$10000$XMZGaar/pU4PvWDr$w0dYjezF6JGtSiYPexyZMt3lM1234uxi"
6871

6972

73+
def _provision_uuid_test_user(configuration, client_id, client_overrides=None):
74+
"""Helper to provision test users when UUID format is used"""
75+
# TODO: merge something like this version into standard _provision_test_user?
76+
# IMPORTANT: we need to use explicit create_user here for UUID format!
77+
user_dict = distinguished_name_to_user(client_id)
78+
# NOTE: generate unique and short id based on id to avoid test collisions
79+
user_dict["unique_id"] = binascii.hexlify(
80+
client_id.encode('utf8')).decode('ascii')
81+
user_dict["short_id"] = binascii.hexlify(
82+
user_dict["email"].encode('utf8')).decode('ascii')
83+
user_dict["comment"] = "This is the user account comment"
84+
user_dict["locality"] = ""
85+
user_dict["organizational_unit"] = ""
86+
user_dict["password"] = ""
87+
user_dict["password_hash"] = ""
88+
if client_overrides is not None:
89+
user_dict.update(client_overrides)
90+
91+
create_user(
92+
user_dict,
93+
configuration,
94+
keyword_auto,
95+
default_renew=True,
96+
ask_renew=False,
97+
)
98+
return user_dict
99+
100+
70101
def _prepare_auth_files(home_path, auth_protos=None):
71102
"""Helper to create helper auth files for on eor more auth_protos.
72103
If None is passed ssh, ftps and davs auth files will be made.
@@ -760,6 +791,8 @@ def _provide_configuration(self):
760791

761792
def before_each(self):
762793
"""Set up test configuration and reset state before each test."""
794+
# Force X509 user id format
795+
self.configuration.site_user_id_format = X509_USER_ID_FORMAT
763796
# Ensure required directories exist
764797
_ensure_dirs_needed_for_userdb(self.configuration)
765798
self.expected_user_db_home = os.path.normpath(
@@ -952,6 +985,231 @@ def test_refresh_user_creds_invalid_protocol(self):
952985
self.assertEqual(len(changed_users), 0)
953986
self.assertEqual(len(updated_conf['users']), 0)
954987

988+
# TODO: merge X509 and UUID versions?
989+
990+
991+
class MigSharedGriddaemonsLogin__refresh_user_creds_uuid_user_id(MigTestCase, UserAssertMixin):
992+
"""Unit tests for the griddaemons login refresh_user_creds helper with UUID users."""
993+
994+
def _provide_configuration(self):
995+
"""Return a test configuration instance."""
996+
return 'testconfig'
997+
998+
def before_each(self):
999+
"""Set up test configuration and reset state before each test."""
1000+
# Force UUID user id format
1001+
self.configuration.site_user_id_format = UUID_USER_ID_FORMAT
1002+
# Ensure required directories exist
1003+
ensure_dirs_exist(self.configuration.mig_system_files)
1004+
_ensure_dirs_needed_for_userdb(self.configuration)
1005+
self.expected_user_db_home = os.path.normpath(
1006+
self.configuration.user_db_home
1007+
)
1008+
self.expected_user_db_file = os.path.join(
1009+
self.expected_user_db_home, "MiG-users.db"
1010+
)
1011+
# NOTE: we need to set a password_hash for https test to work with
1012+
overrides = {}
1013+
overrides["password_hash"] = TEST_USER_PW_HASH
1014+
1015+
user_dict = _provision_uuid_test_user(self.configuration, TEST_USER_DN,
1016+
overrides)
1017+
self.test_user_id = user_id = user_dict['unique_id']
1018+
client_dir = client_id_dir(TEST_USER_DN)
1019+
self.test_user_home = os.path.join(self.configuration.user_home,
1020+
user_id)
1021+
self.test_user_dir = os.path.basename(self.test_user_home)
1022+
self.test_user_home_x509 = os.path.join(self.configuration.user_home,
1023+
client_dir)
1024+
self.test_user_dir_x509 = os.path.basename(self.test_user_home_x509)
1025+
# Make sure X509 and alias links are provisioned as well
1026+
if not os.path.islink(self.test_user_home_x509):
1027+
os.symlink(self.test_user_home, self.test_user_home_x509)
1028+
alias_link_path = os.path.join(self.configuration.user_home,
1029+
TEST_USER_EMAIL)
1030+
if not os.path.islink(alias_link_path):
1031+
os.symlink(self.test_user_home_x509, alias_link_path)
1032+
1033+
ALIAS_FIELD = 'email'
1034+
self.configuration.user_sftp_alias = ALIAS_FIELD
1035+
self.configuration.user_ftps_alias = ALIAS_FIELD
1036+
self.configuration.user_davs_alias = ALIAS_FIELD
1037+
1038+
# Common daemon configuration
1039+
self.configuration.daemon_conf = {}
1040+
self.configuration.daemon_conf['time_stamp'] = 0
1041+
self.configuration.daemon_conf['users'] = []
1042+
self.configuration.daemon_conf['root_dir'] = self.configuration.user_home
1043+
self.configuration.daemon_conf['db_path'] = self.expected_user_db_file
1044+
self.configuration.daemon_conf['allow_publickey'] = True
1045+
self.configuration.daemon_conf['allow_password'] = True
1046+
self.configuration.daemon_conf['allow_digest'] = False
1047+
self.configuration.daemon_conf['user_alias'] = ALIAS_FIELD
1048+
1049+
def test_refresh_user_creds_ssh_protocol(self):
1050+
"""Test refreshing user credentials for SSH protocol."""
1051+
username = TEST_USER_EMAIL
1052+
_prepare_auth_files(self.test_user_home, ['ssh'])
1053+
1054+
# Call the function under test
1055+
(updated_conf, changed_users) = refresh_user_creds(
1056+
configuration=self.configuration,
1057+
protocol='ssh',
1058+
username=username
1059+
)
1060+
1061+
# The user should be in the changed list
1062+
self.assertIn(username, changed_users)
1063+
1064+
# Verify that Login objects were added to users
1065+
user_logins = [obj for obj in updated_conf['users']
1066+
if obj.username == TEST_USER_DN or
1067+
obj.username == username]
1068+
# We expect at least one login (the main username) and possibly aliases
1069+
self.assertGreaterEqual(len(user_logins), 1)
1070+
1071+
# Check that at least one login has the correct home directory
1072+
# TODO: is this X509 dir what we want here or the UUID one?
1073+
home_found = any(login.home == self.test_user_dir_x509 for login in
1074+
user_logins)
1075+
self.assertTrue(home_found)
1076+
1077+
def test_refresh_user_creds_davs_protocol(self):
1078+
"""Test refreshing user credentials for DAVS protocol."""
1079+
username = TEST_USER_EMAIL
1080+
_prepare_auth_files(self.test_user_home, ['davs'])
1081+
1082+
# Call the function under test
1083+
(updated_conf, changed_users) = refresh_user_creds(
1084+
configuration=self.configuration,
1085+
protocol='davs',
1086+
username=username
1087+
)
1088+
1089+
# The user should be in the changed list
1090+
self.assertIn(username, changed_users)
1091+
1092+
# Verify that Login objects were added to users
1093+
user_logins = [obj for obj in updated_conf['users']
1094+
if obj.username == username]
1095+
self.assertEqual(len(user_logins), 1)
1096+
# TODO: is this X509 dir what we want here or the UUID one?
1097+
self.assertEqual(user_logins[0].home, self.test_user_dir_x509)
1098+
1099+
def test_refresh_user_creds_ftps_protocol(self):
1100+
"""Test refreshing user credentials for FTPS protocol."""
1101+
username = TEST_USER_EMAIL
1102+
_prepare_auth_files(self.test_user_home, ['ftps'])
1103+
1104+
# Call the function under test
1105+
(updated_conf, changed_users) = refresh_user_creds(
1106+
configuration=self.configuration,
1107+
protocol='ftps',
1108+
username=username
1109+
)
1110+
1111+
# The user should be in the changed list
1112+
self.assertIn(username, changed_users)
1113+
1114+
# Verify that Login objects were added to users
1115+
user_logins = [obj for obj in updated_conf['users']
1116+
if obj.username == username]
1117+
self.assertEqual(len(user_logins), 1)
1118+
# TODO: is this X509 dir what we want here or the UUID one?
1119+
self.assertEqual(user_logins[0].home, self.test_user_dir_x509)
1120+
1121+
def test_refresh_user_creds_https_protocol(self):
1122+
"""Test refreshing user credentials for HTTPS protocol (uses user DB)."""
1123+
username = TEST_USER_EMAIL
1124+
1125+
# Call the function under test
1126+
(updated_conf, changed_users) = refresh_user_creds(
1127+
configuration=self.configuration,
1128+
protocol='https',
1129+
username=username
1130+
)
1131+
1132+
# The user alias should be in the changed list
1133+
self.assertIn(TEST_USER_EMAIL, changed_users)
1134+
1135+
# Verify that Login objects were added to users for the username and its aliases
1136+
user_logins = [obj for obj in updated_conf['users']
1137+
if obj.username == TEST_USER_DN or
1138+
obj.username == username]
1139+
# We expect at least the main username and possibly aliases
1140+
self.assertGreaterEqual(len(user_logins), 1)
1141+
1142+
# Check that at least one login has the correct home directory
1143+
# TODO: is this X509 dir what we want here or the UUID one?
1144+
home_found = any(login.home == self.test_user_dir_x509 for login in
1145+
user_logins)
1146+
self.assertTrue(home_found)
1147+
1148+
def test_refresh_user_creds_no_changes(self):
1149+
"""Test that no changes are reported when credentials are unchanged."""
1150+
username = TEST_USER_EMAIL
1151+
_prepare_auth_files(self.test_user_home, ['ssh'])
1152+
1153+
# Pre-populate the users list with a Login object that has
1154+
# last_update set to the current time (simulating no changes)
1155+
current_time = time.time()
1156+
dummy_user = Login(
1157+
configuration=self.configuration,
1158+
username=username,
1159+
home=self.test_user_home,
1160+
password=TEST_USER_PW_HASH,
1161+
digest=None,
1162+
public_key=TEST_USER_PUB_KEY,
1163+
chroot=True,
1164+
access=None,
1165+
ip_addr=None,
1166+
user_dict=None)
1167+
dummy_user.last_update = current_time
1168+
self.configuration.daemon_conf['users'].append(dummy_user)
1169+
1170+
# Call the function under test
1171+
(updated_conf, changed_users) = refresh_user_creds(
1172+
configuration=self.configuration,
1173+
protocol='ssh',
1174+
username=username
1175+
)
1176+
1177+
# No changes should be reported
1178+
self.assertEqual(len(changed_users), 0)
1179+
# The user list should still contain only our dummy user
1180+
self.assertEqual(len(updated_conf['users']), 1)
1181+
self.assertEqual(updated_conf['users'][0].username, username)
1182+
1183+
def test_refresh_user_creds_missing_user(self):
1184+
"""Test that a missing user is skipped."""
1185+
username = 'nosuchuser'
1186+
1187+
# Call the function under test
1188+
(updated_conf, changed_users) = refresh_user_creds(
1189+
configuration=self.configuration,
1190+
protocol='ssh',
1191+
username=username
1192+
)
1193+
1194+
# No changes should be reported because the home directory is missing
1195+
self.assertEqual(len(changed_users), 0)
1196+
self.assertEqual(len(updated_conf['users']), 0)
1197+
1198+
def test_refresh_user_creds_invalid_protocol(self):
1199+
"""Test that an invalid protocol returns early without changes."""
1200+
username = TEST_USER_EMAIL
1201+
1202+
# Call the function under test with an invalid protocol
1203+
(updated_conf, changed_users) = refresh_user_creds(
1204+
configuration=self.configuration,
1205+
protocol='invalid',
1206+
username=username
1207+
)
1208+
1209+
# No changes should be reported
1210+
self.assertEqual(len(changed_users), 0)
1211+
self.assertEqual(len(updated_conf['users']), 0)
1212+
9551213

9561214
if __name__ == '__main__':
9571215
unittest.main()

0 commit comments

Comments
 (0)