pwdAdmin_test.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. # --- BEGIN COPYRIGHT BLOCK ---
  2. # Copyright (C) 2015 Red Hat, Inc.
  3. # All rights reserved.
  4. #
  5. # License: GPL (version 3 or any later version).
  6. # See LICENSE for details.
  7. # --- END COPYRIGHT BLOCK ---
  8. #
  9. import os
  10. import sys
  11. import time
  12. import ldap
  13. import logging
  14. import pytest
  15. from lib389 import DirSrv, Entry, tools, tasks
  16. from lib389.tools import DirSrvTools
  17. from lib389._constants import *
  18. from lib389.properties import *
  19. from lib389.tasks import *
  20. from lib389.utils import *
  21. logging.getLogger(__name__).setLevel(logging.DEBUG)
  22. log = logging.getLogger(__name__)
  23. installation1_prefix = None
  24. CONFIG_DN = 'cn=config'
  25. ADMIN_NAME = 'passwd_admin'
  26. ADMIN_DN = 'cn=%s,%s' % (ADMIN_NAME, SUFFIX)
  27. ADMIN2_NAME = 'passwd_admin2'
  28. ADMIN2_DN = 'cn=%s,%s' % (ADMIN2_NAME, SUFFIX)
  29. ADMIN_PWD = 'adminPassword_1'
  30. ADMIN_GROUP_DN = 'cn=password admin group,%s' % (SUFFIX)
  31. ENTRY_NAME = 'Joe Schmo'
  32. ENTRY_DN = 'cn=%s,%s' % (ENTRY_NAME, SUFFIX)
  33. INVALID_PWDS = ('2_Short', 'No_Number', 'N0Special', '{SSHA}bBy8UdtPZwu8uZna9QOYG3Pr41RpIRVDl8wddw==')
  34. class TopologyStandalone(object):
  35. def __init__(self, standalone):
  36. standalone.open()
  37. self.standalone = standalone
  38. @pytest.fixture(scope="module")
  39. def topology(request):
  40. global installation1_prefix
  41. if installation1_prefix:
  42. args_instance[SER_DEPLOYED_DIR] = installation1_prefix
  43. # Creating standalone instance ...
  44. standalone = DirSrv(verbose=False)
  45. args_instance[SER_HOST] = HOST_STANDALONE
  46. args_instance[SER_PORT] = PORT_STANDALONE
  47. args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
  48. args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX
  49. args_standalone = args_instance.copy()
  50. standalone.allocate(args_standalone)
  51. instance_standalone = standalone.exists()
  52. if instance_standalone:
  53. standalone.delete()
  54. standalone.create()
  55. standalone.open()
  56. # Clear out the tmp dir
  57. standalone.clearTmpDir(__file__)
  58. return TopologyStandalone(standalone)
  59. def test_pwdAdmin_init(topology):
  60. '''
  61. Create our future Password Admin entry, set the password policy, and test
  62. that its working
  63. '''
  64. log.info('test_pwdAdmin_init: Creating Password Administator entries...')
  65. # Add Password Admin 1
  66. try:
  67. topology.standalone.add_s(Entry((ADMIN_DN, {'objectclass': "top extensibleObject".split(),
  68. 'cn': ADMIN_NAME,
  69. 'userpassword': ADMIN_PWD})))
  70. except ldap.LDAPError as e:
  71. log.fatal('test_pwdAdmin_init: Failed to add test user' + ADMIN_DN + ': error ' + e.message['desc'])
  72. assert False
  73. # Add Password Admin 2
  74. try:
  75. topology.standalone.add_s(Entry((ADMIN2_DN, {'objectclass': "top extensibleObject".split(),
  76. 'cn': ADMIN2_NAME,
  77. 'userpassword': ADMIN_PWD})))
  78. except ldap.LDAPError as e:
  79. log.fatal('test_pwdAdmin_init: Failed to add test user ' + ADMIN2_DN + ': error ' + e.message['desc'])
  80. assert False
  81. # Add Password Admin Group
  82. try:
  83. topology.standalone.add_s(Entry((ADMIN_GROUP_DN, {'objectclass': "top groupOfUNiqueNames".split(),
  84. 'cn': 'password admin group',
  85. 'uniquemember': ADMIN_DN,
  86. 'uniquemember': ADMIN2_DN})))
  87. except ldap.LDAPError as e:
  88. log.fatal('test_pwdAdmin_init: Failed to add group' + ADMIN_GROUP_DN + ': error ' + e.message['desc'])
  89. assert False
  90. # Configure password policy
  91. log.info('test_pwdAdmin_init: Configuring password policy...')
  92. try:
  93. topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'nsslapd-pwpolicy-local', 'on'),
  94. (ldap.MOD_REPLACE, 'passwordCheckSyntax', 'on'),
  95. (ldap.MOD_REPLACE, 'passwordMinCategories', '1'),
  96. (ldap.MOD_REPLACE, 'passwordMinTokenLength', '1'),
  97. (ldap.MOD_REPLACE, 'passwordExp', 'on'),
  98. (ldap.MOD_REPLACE, 'passwordMinDigits', '1'),
  99. (ldap.MOD_REPLACE, 'passwordMinSpecials', '1')])
  100. except ldap.LDAPError as e:
  101. log.fatal('test_pwdAdmin_init: Failed configure password policy: ' +
  102. e.message['desc'])
  103. assert False
  104. #
  105. # Add an aci to allow everyone all access (just makes things easier)
  106. #
  107. log.info('Add aci to allow password admin to add/update entries...')
  108. ACI_TARGET = "(target = \"ldap:///%s\")" % SUFFIX
  109. ACI_TARGETATTR = "(targetattr = *)"
  110. ACI_ALLOW = "(version 3.0; acl \"Password Admin Access\"; allow (all) "
  111. ACI_SUBJECT = "(userdn = \"ldap:///anyone\");)"
  112. ACI_BODY = ACI_TARGET + ACI_TARGETATTR + ACI_ALLOW + ACI_SUBJECT
  113. mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)]
  114. try:
  115. topology.standalone.modify_s(SUFFIX, mod)
  116. except ldap.LDAPError as e:
  117. log.fatal('test_pwdAdmin_init: Failed to add aci for password admin: ' +
  118. e.message['desc'])
  119. assert False
  120. #
  121. # Bind as the future Password Admin
  122. #
  123. log.info('test_pwdAdmin_init: Bind as the Password Administator (before activating)...')
  124. try:
  125. topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
  126. except ldap.LDAPError as e:
  127. log.fatal('test_pwdAdmin_init: Failed to bind as the Password Admin: ' +
  128. e.message['desc'])
  129. assert False
  130. #
  131. # Setup our test entry, and test password policy is working
  132. #
  133. entry = Entry(ENTRY_DN)
  134. entry.setValues('objectclass', 'top', 'person')
  135. entry.setValues('sn', ENTRY_NAME)
  136. entry.setValues('cn', ENTRY_NAME)
  137. #
  138. # Start by attempting to add an entry with an invalid password
  139. #
  140. log.info('test_pwdAdmin_init: Attempt to add entries with invalid passwords, these adds should fail...')
  141. for passwd in INVALID_PWDS:
  142. failed_as_expected = False
  143. entry.setValues('userpassword', passwd)
  144. log.info('test_pwdAdmin_init: Create a regular user entry %s with password (%s)...' %
  145. (ENTRY_DN, passwd))
  146. try:
  147. topology.standalone.add_s(entry)
  148. except ldap.LDAPError as e:
  149. # We failed as expected
  150. failed_as_expected = True
  151. log.info('test_pwdAdmin_init: Add failed as expected: password (%s) result (%s)'
  152. % (passwd, e.message['desc']))
  153. if not failed_as_expected:
  154. log.fatal('test_pwdAdmin_init: We were incorrectly able to add an entry ' +
  155. 'with an invalid password (%s)' % (passwd))
  156. assert False
  157. def test_pwdAdmin(topology):
  158. '''
  159. Test that password administrators/root DN can
  160. bypass password syntax/policy.
  161. We need to test how passwords are modified in
  162. existing entries, and when adding new entries.
  163. Create the Password Admin entry, but do not set
  164. it as an admin yet. Use the entry to verify invalid
  165. passwords are caught. Then activate the password
  166. admin and make sure it can bypass password policy.
  167. '''
  168. #
  169. # Now activate a password administator, bind as root dn to do the config
  170. # update, then rebind as the password admin
  171. #
  172. log.info('test_pwdAdmin: Activate the Password Administator...')
  173. #
  174. # Setup our test entry, and test password policy is working
  175. #
  176. entry = Entry(ENTRY_DN)
  177. entry.setValues('objectclass', 'top', 'person')
  178. entry.setValues('sn', ENTRY_NAME)
  179. entry.setValues('cn', ENTRY_NAME)
  180. # Bind as Root DN
  181. try:
  182. topology.standalone.simple_bind_s(DN_DM, PASSWORD)
  183. except ldap.LDAPError as e:
  184. log.fatal('test_pwdAdmin: Root DN failed to authenticate: ' +
  185. e.message['desc'])
  186. assert False
  187. # Set the password admin
  188. try:
  189. topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'passwordAdminDN', ADMIN_DN)])
  190. except ldap.LDAPError as e:
  191. log.fatal('test_pwdAdmin: Failed to add password admin to config: ' +
  192. e.message['desc'])
  193. assert False
  194. # Bind as Password Admin
  195. try:
  196. topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
  197. except ldap.LDAPError as e:
  198. log.fatal('test_pwdAdmin: Failed to bind as the Password Admin: ' +
  199. e.message['desc'])
  200. assert False
  201. #
  202. # Start adding entries with invalid passwords, delete the entry after each pass.
  203. #
  204. for passwd in INVALID_PWDS:
  205. entry.setValues('userpassword', passwd)
  206. log.info('test_pwdAdmin: Create a regular user entry %s with password (%s)...' %
  207. (ENTRY_DN, passwd))
  208. try:
  209. topology.standalone.add_s(entry)
  210. except ldap.LDAPError as e:
  211. log.fatal('test_pwdAdmin: Failed to add entry with password (%s) result (%s)'
  212. % (passwd, e.message['desc']))
  213. assert False
  214. log.info('test_pwdAdmin: Successfully added entry (%s)' % ENTRY_DN)
  215. # Delete entry for the next pass
  216. try:
  217. topology.standalone.delete_s(ENTRY_DN)
  218. except ldap.LDAPError as e:
  219. log.fatal('test_pwdAdmin: Failed to delete entry: %s' %
  220. (e.message['desc']))
  221. assert False
  222. #
  223. # Add the entry for the next round of testing (modify password)
  224. #
  225. entry.setValues('userpassword', ADMIN_PWD)
  226. try:
  227. topology.standalone.add_s(entry)
  228. except ldap.LDAPError as e:
  229. log.fatal('test_pwdAdmin: Failed to add entry with valid password (%s) result (%s)' %
  230. (passwd, e.message['desc']))
  231. assert False
  232. #
  233. # Deactivate the password admin and make sure invalid password updates fail
  234. #
  235. log.info('test_pwdAdmin: Deactivate Password Administator and ' +
  236. 'try invalid password updates...')
  237. # Bind as root DN
  238. try:
  239. topology.standalone.simple_bind_s(DN_DM, PASSWORD)
  240. except ldap.LDAPError as e:
  241. log.fatal('test_pwdAdmin: Root DN failed to authenticate: ' +
  242. e.message['desc'])
  243. assert False
  244. # Remove password admin
  245. try:
  246. topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_DELETE, 'passwordAdminDN', None)])
  247. except ldap.LDAPError as e:
  248. log.fatal('test_pwdAdmin: Failed to remove password admin from config: ' +
  249. e.message['desc'])
  250. assert False
  251. # Bind as Password Admin (who is no longer an admin)
  252. try:
  253. topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
  254. except ldap.LDAPError as e:
  255. log.fatal('test_pwdAdmin: Failed to bind as the Password Admin: ' +
  256. e.message['desc'])
  257. assert False
  258. #
  259. # Make invalid password updates that should fail
  260. #
  261. for passwd in INVALID_PWDS:
  262. failed_as_expected = False
  263. entry.setValues('userpassword', passwd)
  264. try:
  265. topology.standalone.modify_s(ENTRY_DN, [(ldap.MOD_REPLACE, 'userpassword', passwd)])
  266. except ldap.LDAPError as e:
  267. # We failed as expected
  268. failed_as_expected = True
  269. log.info('test_pwdAdmin: Password update failed as expected: password (%s) result (%s)'
  270. % (passwd, e.message['desc']))
  271. if not failed_as_expected:
  272. log.fatal('test_pwdAdmin: We were incorrectly able to add an invalid password (%s)'
  273. % (passwd))
  274. assert False
  275. #
  276. # Now activate a password administator
  277. #
  278. log.info('test_pwdAdmin: Activate Password Administator and try updates again...')
  279. # Bind as root DN to make the update
  280. try:
  281. topology.standalone.simple_bind_s(DN_DM, PASSWORD)
  282. except ldap.LDAPError as e:
  283. log.fatal('test_pwdAdmin: Root DN failed to authenticate: ' + e.message['desc'])
  284. assert False
  285. # Update config - set the password admin
  286. try:
  287. topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'passwordAdminDN', ADMIN_DN)])
  288. except ldap.LDAPError as e:
  289. log.fatal('test_pwdAdmin: Failed to add password admin to config: ' +
  290. e.message['desc'])
  291. assert False
  292. # Bind as Password Admin
  293. try:
  294. topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
  295. except ldap.LDAPError as e:
  296. log.fatal('test_pwdAdmin: Failed to bind as the Password Admin: ' +
  297. e.message['desc'])
  298. assert False
  299. #
  300. # Make the same password updates, but this time they should succeed
  301. #
  302. for passwd in INVALID_PWDS:
  303. try:
  304. topology.standalone.modify_s(ENTRY_DN, [(ldap.MOD_REPLACE, 'userpassword', passwd)])
  305. except ldap.LDAPError as e:
  306. log.fatal('test_pwdAdmin: Password update failed unexpectedly: password (%s) result (%s)'
  307. % (passwd, e.message['desc']))
  308. assert False
  309. log.info('test_pwdAdmin: Password update succeeded (%s)' % passwd)
  310. #
  311. # Test Password Admin Group
  312. #
  313. log.info('test_pwdAdmin: Testing password admin group...')
  314. # Bind as root DN to make the update
  315. try:
  316. topology.standalone.simple_bind_s(DN_DM, PASSWORD)
  317. except ldap.LDAPError as e:
  318. log.fatal('test_pwdAdmin: Root DN failed to authenticate: ' + e.message['desc'])
  319. assert False
  320. # Update config - set the password admin group
  321. try:
  322. topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'passwordAdminDN', ADMIN_GROUP_DN)])
  323. except ldap.LDAPError as e:
  324. log.fatal('test_pwdAdmin: Failed to add password admin to config: ' +
  325. e.message['desc'])
  326. assert False
  327. # Bind as admin2
  328. try:
  329. topology.standalone.simple_bind_s(ADMIN2_DN, ADMIN_PWD)
  330. except ldap.LDAPError as e:
  331. log.fatal('test_pwdAdmin: Failed to bind as the Password Admin2: ' +
  332. e.message['desc'])
  333. assert False
  334. # Make some invalid password updates, but they should succeed
  335. for passwd in INVALID_PWDS:
  336. try:
  337. topology.standalone.modify_s(ENTRY_DN, [(ldap.MOD_REPLACE, 'userpassword', passwd)])
  338. except ldap.LDAPError as e:
  339. log.fatal('test_pwdAdmin: Password update failed unexpectedly: password (%s) result (%s)'
  340. % (passwd, e.message['desc']))
  341. assert False
  342. log.info('test_pwdAdmin: Password update succeeded (%s)' % passwd)
  343. # Cleanup - bind as Root DN for the other tests
  344. try:
  345. topology.standalone.simple_bind_s(DN_DM, PASSWORD)
  346. except ldap.LDAPError as e:
  347. log.fatal('test_pwdAdmin: Root DN failed to authenticate: ' + e.message['desc'])
  348. assert False
  349. def test_pwdAdmin_config_validation(topology):
  350. '''
  351. Test config validation:
  352. - Test adding multiple passwordAdminDN attributes
  353. - Test adding invalid values(non-DN's)
  354. '''
  355. # Add mulitple attributes - one already eists so just try and add as second one
  356. try:
  357. topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_ADD, 'passwordAdminDN', ENTRY_DN)])
  358. log.fatal('test_pwdAdmin_config_validation: Incorrectly was able to add two config attributes')
  359. assert False
  360. except ldap.LDAPError as e:
  361. log.info('test_pwdAdmin_config_validation: Failed as expected: ' +
  362. e.message['desc'])
  363. # Attempt to set invalid DN
  364. try:
  365. topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_ADD, 'passwordAdminDN', 'ZZZZZ')])
  366. log.fatal('test_pwdAdmin_config_validation: Incorrectly was able to add invalid DN')
  367. assert False
  368. except ldap.LDAPError as e:
  369. log.info('test_pwdAdmin_config_validation: Failed as expected: ' +
  370. e.message['desc'])
  371. def test_pwdAdmin_final(topology):
  372. topology.standalone.delete()
  373. log.info('pwdAdmin test suite PASSED')
  374. def run_isolated():
  375. global installation1_prefix
  376. installation1_prefix = None
  377. topo = topology(True)
  378. test_pwdAdmin_init(topo)
  379. test_pwdAdmin(topo)
  380. test_pwdAdmin_config_validation(topo)
  381. test_pwdAdmin_final(topo)
  382. if __name__ == '__main__':
  383. run_isolated()