Skip to content

Commit 3bc3a2d

Browse files
committed
cover the generated user record
1 parent 47ff7f3 commit 3bc3a2d

File tree

6 files changed

+116
-33
lines changed

6 files changed

+116
-33
lines changed

mig/server/createuser.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,8 @@ def _main(configuration, args,
216216
role=None,
217217
peer_pattern=None,
218218
slack_secs=0,
219-
hash_password=True
219+
hash_password=True,
220+
_generate_salt=None
220221
):
221222
if configuration is None:
222223
if conf_path == keyword_auto:
@@ -306,7 +307,7 @@ def _main(configuration, args,
306307

307308
if user_dict['password']:
308309
if hash_password:
309-
user_dict['password_hash'] = make_hash(user_dict['password'])
310+
user_dict['password_hash'] = make_hash(user_dict['password'], _generate_salt=_generate_salt)
310311
user_dict['password'] = ''
311312
else:
312313
salt = configuration.site_password_salt

mig/shared/pwcrypto.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,17 @@ def best_crypt_salt(configuration):
114114
return salt_data
115115

116116

117-
def make_hash(password):
117+
def _random_salt():
118+
return b64encode(urandom(SALT_LENGTH))
119+
120+
121+
def make_hash(password, _generate_salt=None):
118122
"""Generate a random salt and return a new hash for the password."""
119-
salt = b64encode(urandom(SALT_LENGTH))
123+
124+
if _generate_salt is None:
125+
_generate_salt = _random_salt
126+
127+
salt = _generate_salt()
120128
derived = b64encode(hashlib.pbkdf2_hmac(HASH_FUNCTION,
121129
force_utf8(password), salt,
122130
COST_FACTOR, KEY_LENGTH))

tests/support/__init__.py

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
from unittest import TestCase, main as testmain
4242

4343
from tests.support.configsupp import FakeConfiguration
44+
from tests.support.picklesupp import ensure_path_within_output_dir, \
45+
is_path_within
4446
from tests.support.suppconst import MIG_BASE, TEST_BASE, TEST_FIXTURE_DIR, \
4547
TEST_DATA_DIR, TEST_OUTPUT_DIR, ENVHELP_OUTPUT_DIR
4648

@@ -296,16 +298,6 @@ def pretty_display_path(absolute_path):
296298
return relative_path
297299

298300

299-
def is_path_within(path, start=None, _msg=None):
300-
"""Check if path is within start directory"""
301-
try:
302-
assert os.path.isabs(path), _msg
303-
relative = os.path.relpath(path, start=start)
304-
except:
305-
return False
306-
return not relative.startswith('..')
307-
308-
309301
def ensure_dirs_exist(absolute_dir):
310302
"""A simple helper to create absolute_dir and any parents if missing"""
311303
try:
@@ -399,22 +391,7 @@ def temppath(relative_path, test_case, ensure_dir=False, skip_clean=False):
399391
"""
400392
assert isinstance(test_case, MigTestCase)
401393

402-
if os.path.isabs(relative_path):
403-
# the only permitted paths are those within the output directory set
404-
# aside for execution of the test suite: this will be enforced below
405-
# so effectively submit the supplied path for scrutiny
406-
tmp_path = relative_path
407-
else:
408-
tmp_path = os.path.join(TEST_OUTPUT_DIR, relative_path)
409-
410-
# failsafe path checking that supplied paths are rooted within valid paths
411-
is_tmp_path_within_safe_dir = False
412-
for start in (ENVHELP_OUTPUT_DIR):
413-
is_tmp_path_within_safe_dir = is_path_within(tmp_path, start=start)
414-
if is_tmp_path_within_safe_dir:
415-
break
416-
if not is_tmp_path_within_safe_dir:
417-
raise AssertionError("ABORT: corrupt test path=%s" % (tmp_path,))
394+
tmp_path = ensure_path_within_output_dir(relative_path)
418395

419396
if ensure_dir:
420397
try:

tests/support/_path.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import os
2+
3+
from tests.support.suppconst import TEST_OUTPUT_DIR, ENVHELP_OUTPUT_DIR
4+
5+
6+
def is_path_within(path, start=None, _msg=None):
7+
"""Check if path is within start directory"""
8+
try:
9+
assert os.path.isabs(path), _msg
10+
relative = os.path.relpath(path, start=start)
11+
except:
12+
return False
13+
return not relative.startswith('..')
14+
15+
16+
def ensure_path_within_output_dir(relative_path):
17+
if os.path.isabs(relative_path):
18+
# the only permitted paths are those within the output directory set
19+
# aside for execution of the test suite: this will be enforced below
20+
# so effectively submit the supplied path for scrutiny
21+
tmp_path = relative_path
22+
else:
23+
tmp_path = os.path.join(TEST_OUTPUT_DIR, relative_path)
24+
25+
# failsafe path checking that supplied paths are rooted within valid paths
26+
is_tmp_path_within_safe_dir = False
27+
for start in (ENVHELP_OUTPUT_DIR):
28+
is_tmp_path_within_safe_dir = is_path_within(tmp_path, start=start)
29+
if is_tmp_path_within_safe_dir:
30+
break
31+
if not is_tmp_path_within_safe_dir:
32+
raise AssertionError("ABORT: corrupt test path=%s" % (tmp_path,))
33+
34+
return tmp_path

tests/support/picklesupp.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import pickle
2+
3+
from tests.support._path import ensure_path_within_output_dir, \
4+
is_path_within
5+
6+
7+
class PickleAssertMixin:
8+
def assertPickledFile(self, pickle_file):
9+
ensure_path_within_output_dir(pickle_file)
10+
11+
with open(pickle_file, 'rb') as picklefile:
12+
return pickle.load(picklefile)

tests/test_mig_server_createuser.py

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,13 @@
3333
import sys
3434

3535
from tests.support import MIG_BASE, TEST_OUTPUT_DIR, MigTestCase, testmain
36+
from tests.support.picklesupp import PickleAssertMixin
3637

3738
from mig.server.createuser import _main as createuser
3839
from mig.shared.useradm import _USERADM_CONFIG_DIR_KEYS
3940

4041

41-
class TestBooleans(MigTestCase):
42+
class TestMigServerCreateuser(MigTestCase, PickleAssertMixin):
4243
def before_each(self):
4344
configuration = self.configuration
4445
test_state_path = configuration.state_path
@@ -51,17 +52,18 @@ def before_each(self):
5152
pass
5253

5354
self.expected_user_db_home = configuration.user_db_home[0:-1]
55+
self.expected_user_db_file = os.path.join(self.expected_user_db_home, 'MiG-users.db')
5456

5557
def _provide_configuration(self):
5658
return 'testconfig'
5759

58-
def test_user_db_is_created_and_user_is_added(self):
60+
def test_user_db_is_created_when_absent(self):
5961
args = [
6062
"Test User",
6163
"Test Org",
6264
"NA",
6365
"DK",
64-
"dummy-user",
66+
"user@example.com",
6567
"This is the create comment",
6668
"password"
6769
]
@@ -79,5 +81,54 @@ def test_user_db_is_created_and_user_is_added(self):
7981
self.assertEqual(path_kind, 'file')
8082

8183

84+
def test_user_entry_is_recorded(self):
85+
expected_user_id = '/C=DK/ST=NA/L=NA/O=Test Org/OU=NA/CN=Test User/emailAddress=user@example.com'
86+
args = [
87+
"Test User",
88+
"Test Org",
89+
"NA",
90+
"DK",
91+
"user@example.com",
92+
"This is the create comment",
93+
"password"
94+
]
95+
print("") # acount for output generated by the logic
96+
97+
def _generate_salt():
98+
return b'CCCC12344321CCCC'
99+
createuser(self.configuration, args, default_renew=True,
100+
_generate_salt=_generate_salt)
101+
102+
pickled = self.assertPickledFile(self.expected_user_db_file)
103+
104+
self.assertIn(expected_user_id, pickled)
105+
actual_user_object = dict(pickled[expected_user_id])
106+
107+
# TODO: remove resetting the handful of keys here done because changes
108+
# to make them assertion frienfly values will increase the size
109+
# of the diff which, at time of commit, are best minimised.
110+
actual_user_object['created'] = 9999999999.9999999
111+
actual_user_object['expire'] = 1234567890
112+
actual_user_object['unique_id'] = '__UNIQUE_ID__'
113+
114+
self.assertEqual(actual_user_object, {
115+
'comment': "This is the create comment",
116+
'country': 'DK',
117+
'created': 9999999999.9999999,
118+
'distinguished_name': expected_user_id,
119+
'email': "user@example.com",
120+
'expire': 1234567890,
121+
'full_name': 'Test User',
122+
'locality': '',
123+
'openid_names': [],
124+
'organization': 'Test Org',
125+
'organizational_unit': '',
126+
"password": "",
127+
"password_hash": "PBKDF2$sha256$10000$b'CCCC12344321CCCC'$b'bph8p/avUq42IYeOdJoJuUqrJ7Q32eaT'",
128+
'state': 'NA',
129+
'unique_id': '__UNIQUE_ID__'
130+
})
131+
132+
82133
if __name__ == '__main__':
83134
testmain()

0 commit comments

Comments
 (0)