|
|
@@ -0,0 +1,143 @@
|
|
|
+import os
|
|
|
+import sys
|
|
|
+import time
|
|
|
+import ldap
|
|
|
+import logging
|
|
|
+import pytest
|
|
|
+from lib389 import DirSrv, Entry, tools, tasks
|
|
|
+from lib389.tools import DirSrvTools
|
|
|
+from lib389._constants import *
|
|
|
+from lib389.properties import *
|
|
|
+from lib389.tasks import *
|
|
|
+from lib389.utils import *
|
|
|
+
|
|
|
+DEBUGGING = True
|
|
|
+USER_DN = 'uid=user,ou=People,%s' % DEFAULT_SUFFIX
|
|
|
+
|
|
|
+if DEBUGGING:
|
|
|
+ logging.getLogger(__name__).setLevel(logging.DEBUG)
|
|
|
+else:
|
|
|
+ logging.getLogger(__name__).setLevel(logging.INFO)
|
|
|
+
|
|
|
+
|
|
|
+log = logging.getLogger(__name__)
|
|
|
+
|
|
|
+
|
|
|
+class TopologyStandalone(object):
|
|
|
+ """The DS Topology Class"""
|
|
|
+ def __init__(self, standalone):
|
|
|
+ """Init"""
|
|
|
+ standalone.open()
|
|
|
+ self.standalone = standalone
|
|
|
+
|
|
|
+
|
|
|
[email protected](scope="module")
|
|
|
+def topology(request):
|
|
|
+ """Create DS Deployment"""
|
|
|
+
|
|
|
+ # Creating standalone instance ...
|
|
|
+ if DEBUGGING:
|
|
|
+ standalone = DirSrv(verbose=True)
|
|
|
+ else:
|
|
|
+ standalone = DirSrv(verbose=False)
|
|
|
+ args_instance[SER_HOST] = HOST_STANDALONE
|
|
|
+ args_instance[SER_PORT] = PORT_STANDALONE
|
|
|
+ args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
|
|
|
+ args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX
|
|
|
+ args_standalone = args_instance.copy()
|
|
|
+ standalone.allocate(args_standalone)
|
|
|
+ instance_standalone = standalone.exists()
|
|
|
+ if instance_standalone:
|
|
|
+ standalone.delete()
|
|
|
+ standalone.create()
|
|
|
+ standalone.open()
|
|
|
+
|
|
|
+ def fin():
|
|
|
+ """If we are debugging just stop the instances, otherwise remove
|
|
|
+ them
|
|
|
+ """
|
|
|
+ if DEBUGGING:
|
|
|
+ standalone.stop()
|
|
|
+ else:
|
|
|
+ standalone.delete()
|
|
|
+
|
|
|
+ request.addfinalizer(fin)
|
|
|
+
|
|
|
+ # Clear out the tmp dir
|
|
|
+ standalone.clearTmpDir(__file__)
|
|
|
+
|
|
|
+ return TopologyStandalone(standalone)
|
|
|
+
|
|
|
+def _test_bind(inst, password):
|
|
|
+ result = True
|
|
|
+ userconn = ldap.initialize("ldap://%s:%s" % (HOST_STANDALONE, PORT_STANDALONE))
|
|
|
+ try:
|
|
|
+ userconn.simple_bind_s(USER_DN, password)
|
|
|
+ userconn.unbind_s()
|
|
|
+ except ldap.INVALID_CREDENTIALS:
|
|
|
+ result = False
|
|
|
+ return result
|
|
|
+
|
|
|
+def _test_algo(inst, algo_name):
|
|
|
+ inst.config.set('passwordStorageScheme', algo_name)
|
|
|
+
|
|
|
+ if DEBUGGING:
|
|
|
+ print('Testing %s', algo_name)
|
|
|
+
|
|
|
+ # Create the user with a password
|
|
|
+ inst.add_s(Entry((
|
|
|
+ USER_DN, {
|
|
|
+ 'objectClass': 'top account simplesecurityobject'.split(),
|
|
|
+ 'uid': 'user',
|
|
|
+ 'userpassword': 'Secret123'
|
|
|
+ })))
|
|
|
+
|
|
|
+ # Make sure when we read the userPassword field, it is the correct ALGO
|
|
|
+ pw_field = inst.search_s(USER_DN, ldap.SCOPE_BASE, '(objectClass=*)', ['userPassword'] )[0]
|
|
|
+
|
|
|
+ if DEBUGGING:
|
|
|
+ print(pw_field.getValue('userPassword'))
|
|
|
+
|
|
|
+ if algo_name != 'CLEAR':
|
|
|
+ assert(algo_name.lower() in pw_field.getValue('userPassword').lower())
|
|
|
+ # Now make sure a bind works
|
|
|
+ assert(_test_bind(inst, 'Secret123'))
|
|
|
+ # Bind with a wrong shorter password, should fail
|
|
|
+ assert(not _test_bind(inst, 'Wrong'))
|
|
|
+ # Bind with a wrong longer password, should fail
|
|
|
+ assert(not _test_bind(inst, 'This is even more wrong'))
|
|
|
+ # Bind with a wrong exact length password.
|
|
|
+ assert(not _test_bind(inst, 'Alsowrong'))
|
|
|
+ # Bind with a subset password, should fail
|
|
|
+ assert(not _test_bind(inst, 'Secret'))
|
|
|
+ if algo_name != 'CRYPT':
|
|
|
+ # Bind with a subset password that is 1 char shorter, to detect off by 1 in clear
|
|
|
+ assert(not _test_bind(inst, 'Secret12'))
|
|
|
+ # Bind with a superset password, should fail
|
|
|
+ assert(not _test_bind(inst, 'Secret123456'))
|
|
|
+ # Delete the user
|
|
|
+ inst.delete_s(USER_DN)
|
|
|
+ # done!
|
|
|
+
|
|
|
+def test_pwd_algo_test(topology):
|
|
|
+ """
|
|
|
+ Assert that all of our password algorithms correctly PASS and FAIL varying
|
|
|
+ password conditions.
|
|
|
+
|
|
|
+ """
|
|
|
+ if DEBUGGING:
|
|
|
+ # Add debugging steps(if any)...
|
|
|
+ pass
|
|
|
+
|
|
|
+ for algo in ('CLEAR', 'CRYPT', 'MD5', 'SHA', 'SHA256', 'SHA384', 'SHA512', 'SMD5', 'SSHA', 'SSHA256', 'SSHA384', 'SSHA512'):
|
|
|
+ _test_algo(topology.standalone, algo)
|
|
|
+
|
|
|
+ log.info('Test PASSED')
|
|
|
+
|
|
|
+
|
|
|
+if __name__ == '__main__':
|
|
|
+ # Run isolated
|
|
|
+ # -s for DEBUG mode
|
|
|
+ CURRENT_FILE = os.path.realpath(__file__)
|
|
|
+ pytest.main("-s %s" % CURRENT_FILE)
|
|
|
+
|