pwdAdmin_test.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  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. def fin():
  57. standalone.delete()
  58. request.addfinalizer(fin)
  59. return TopologyStandalone(standalone)
  60. def test_pwdAdmin_init(topology):
  61. '''
  62. Create our future Password Admin entry, set the password policy, and test
  63. that its working
  64. '''
  65. log.info('test_pwdAdmin_init: Creating Password Administator entries...')
  66. # Add Password Admin 1
  67. try:
  68. topology.standalone.add_s(Entry((ADMIN_DN, {'objectclass': "top extensibleObject".split(),
  69. 'cn': ADMIN_NAME,
  70. 'userpassword': ADMIN_PWD})))
  71. except ldap.LDAPError as e:
  72. log.fatal('test_pwdAdmin_init: Failed to add test user' + ADMIN_DN + ': error ' + e.message['desc'])
  73. assert False
  74. # Add Password Admin 2
  75. try:
  76. topology.standalone.add_s(Entry((ADMIN2_DN, {'objectclass': "top extensibleObject".split(),
  77. 'cn': ADMIN2_NAME,
  78. 'userpassword': ADMIN_PWD})))
  79. except ldap.LDAPError as e:
  80. log.fatal('test_pwdAdmin_init: Failed to add test user ' + ADMIN2_DN + ': error ' + e.message['desc'])
  81. assert False
  82. # Add Password Admin Group
  83. try:
  84. topology.standalone.add_s(Entry((ADMIN_GROUP_DN, {'objectclass': "top groupOfUNiqueNames".split(),
  85. 'cn': 'password admin group',
  86. 'uniquemember': ADMIN_DN,
  87. 'uniquemember': ADMIN2_DN})))
  88. except ldap.LDAPError as e:
  89. log.fatal('test_pwdAdmin_init: Failed to add group' + ADMIN_GROUP_DN + ': error ' + e.message['desc'])
  90. assert False
  91. # Configure password policy
  92. log.info('test_pwdAdmin_init: Configuring password policy...')
  93. try:
  94. topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'nsslapd-pwpolicy-local', 'on'),
  95. (ldap.MOD_REPLACE, 'passwordCheckSyntax', 'on'),
  96. (ldap.MOD_REPLACE, 'passwordMinCategories', '1'),
  97. (ldap.MOD_REPLACE, 'passwordMinTokenLength', '1'),
  98. (ldap.MOD_REPLACE, 'passwordExp', 'on'),
  99. (ldap.MOD_REPLACE, 'passwordMinDigits', '1'),
  100. (ldap.MOD_REPLACE, 'passwordMinSpecials', '1')])
  101. except ldap.LDAPError as e:
  102. log.fatal('test_pwdAdmin_init: Failed configure password policy: ' +
  103. e.message['desc'])
  104. assert False
  105. #
  106. # Add an aci to allow everyone all access (just makes things easier)
  107. #
  108. log.info('Add aci to allow password admin to add/update entries...')
  109. ACI_TARGET = "(target = \"ldap:///%s\")" % SUFFIX
  110. ACI_TARGETATTR = "(targetattr = *)"
  111. ACI_ALLOW = "(version 3.0; acl \"Password Admin Access\"; allow (all) "
  112. ACI_SUBJECT = "(userdn = \"ldap:///anyone\");)"
  113. ACI_BODY = ACI_TARGET + ACI_TARGETATTR + ACI_ALLOW + ACI_SUBJECT
  114. mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)]
  115. try:
  116. topology.standalone.modify_s(SUFFIX, mod)
  117. except ldap.LDAPError as e:
  118. log.fatal('test_pwdAdmin_init: Failed to add aci for password admin: ' +
  119. e.message['desc'])
  120. assert False
  121. #
  122. # Bind as the future Password Admin
  123. #
  124. log.info('test_pwdAdmin_init: Bind as the Password Administator (before activating)...')
  125. try:
  126. topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
  127. except ldap.LDAPError as e:
  128. log.fatal('test_pwdAdmin_init: Failed to bind as the Password Admin: ' +
  129. e.message['desc'])
  130. assert False
  131. #
  132. # Setup our test entry, and test password policy is working
  133. #
  134. entry = Entry(ENTRY_DN)
  135. entry.setValues('objectclass', 'top', 'person')
  136. entry.setValues('sn', ENTRY_NAME)
  137. entry.setValues('cn', ENTRY_NAME)
  138. #
  139. # Start by attempting to add an entry with an invalid password
  140. #
  141. log.info('test_pwdAdmin_init: Attempt to add entries with invalid passwords, these adds should fail...')
  142. for passwd in INVALID_PWDS:
  143. failed_as_expected = False
  144. entry.setValues('userpassword', passwd)
  145. log.info('test_pwdAdmin_init: Create a regular user entry %s with password (%s)...' %
  146. (ENTRY_DN, passwd))
  147. try:
  148. topology.standalone.add_s(entry)
  149. except ldap.LDAPError as e:
  150. # We failed as expected
  151. failed_as_expected = True
  152. log.info('test_pwdAdmin_init: Add failed as expected: password (%s) result (%s)'
  153. % (passwd, e.message['desc']))
  154. if not failed_as_expected:
  155. log.fatal('test_pwdAdmin_init: We were incorrectly able to add an entry ' +
  156. 'with an invalid password (%s)' % (passwd))
  157. assert False
  158. def test_pwdAdmin(topology):
  159. '''
  160. Test that password administrators/root DN can
  161. bypass password syntax/policy.
  162. We need to test how passwords are modified in
  163. existing entries, and when adding new entries.
  164. Create the Password Admin entry, but do not set
  165. it as an admin yet. Use the entry to verify invalid
  166. passwords are caught. Then activate the password
  167. admin and make sure it can bypass password policy.
  168. '''
  169. #
  170. # Now activate a password administator, bind as root dn to do the config
  171. # update, then rebind as the password admin
  172. #
  173. log.info('test_pwdAdmin: Activate the Password Administator...')
  174. #
  175. # Setup our test entry, and test password policy is working
  176. #
  177. entry = Entry(ENTRY_DN)
  178. entry.setValues('objectclass', 'top', 'person')
  179. entry.setValues('sn', ENTRY_NAME)
  180. entry.setValues('cn', ENTRY_NAME)
  181. # Bind as Root DN
  182. try:
  183. topology.standalone.simple_bind_s(DN_DM, PASSWORD)
  184. except ldap.LDAPError as e:
  185. log.fatal('test_pwdAdmin: Root DN failed to authenticate: ' +
  186. e.message['desc'])
  187. assert False
  188. # Set the password admin
  189. try:
  190. topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'passwordAdminDN', ADMIN_DN)])
  191. except ldap.LDAPError as e:
  192. log.fatal('test_pwdAdmin: Failed to add password admin to config: ' +
  193. e.message['desc'])
  194. assert False
  195. # Bind as Password Admin
  196. try:
  197. topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
  198. except ldap.LDAPError as e:
  199. log.fatal('test_pwdAdmin: Failed to bind as the Password Admin: ' +
  200. e.message['desc'])
  201. assert False
  202. #
  203. # Start adding entries with invalid passwords, delete the entry after each pass.
  204. #
  205. for passwd in INVALID_PWDS:
  206. entry.setValues('userpassword', passwd)
  207. log.info('test_pwdAdmin: Create a regular user entry %s with password (%s)...' %
  208. (ENTRY_DN, passwd))
  209. try:
  210. topology.standalone.add_s(entry)
  211. except ldap.LDAPError as e:
  212. log.fatal('test_pwdAdmin: Failed to add entry with password (%s) result (%s)'
  213. % (passwd, e.message['desc']))
  214. assert False
  215. log.info('test_pwdAdmin: Successfully added entry (%s)' % ENTRY_DN)
  216. # Delete entry for the next pass
  217. try:
  218. topology.standalone.delete_s(ENTRY_DN)
  219. except ldap.LDAPError as e:
  220. log.fatal('test_pwdAdmin: Failed to delete entry: %s' %
  221. (e.message['desc']))
  222. assert False
  223. #
  224. # Add the entry for the next round of testing (modify password)
  225. #
  226. entry.setValues('userpassword', ADMIN_PWD)
  227. try:
  228. topology.standalone.add_s(entry)
  229. except ldap.LDAPError as e:
  230. log.fatal('test_pwdAdmin: Failed to add entry with valid password (%s) result (%s)' %
  231. (passwd, e.message['desc']))
  232. assert False
  233. #
  234. # Deactivate the password admin and make sure invalid password updates fail
  235. #
  236. log.info('test_pwdAdmin: Deactivate Password Administator and ' +
  237. 'try invalid password updates...')
  238. # Bind as root DN
  239. try:
  240. topology.standalone.simple_bind_s(DN_DM, PASSWORD)
  241. except ldap.LDAPError as e:
  242. log.fatal('test_pwdAdmin: Root DN failed to authenticate: ' +
  243. e.message['desc'])
  244. assert False
  245. # Remove password admin
  246. try:
  247. topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_DELETE, 'passwordAdminDN', None)])
  248. except ldap.LDAPError as e:
  249. log.fatal('test_pwdAdmin: Failed to remove password admin from config: ' +
  250. e.message['desc'])
  251. assert False
  252. # Bind as Password Admin (who is no longer an admin)
  253. try:
  254. topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
  255. except ldap.LDAPError as e:
  256. log.fatal('test_pwdAdmin: Failed to bind as the Password Admin: ' +
  257. e.message['desc'])
  258. assert False
  259. #
  260. # Make invalid password updates that should fail
  261. #
  262. for passwd in INVALID_PWDS:
  263. failed_as_expected = False
  264. entry.setValues('userpassword', passwd)
  265. try:
  266. topology.standalone.modify_s(ENTRY_DN, [(ldap.MOD_REPLACE, 'userpassword', passwd)])
  267. except ldap.LDAPError as e:
  268. # We failed as expected
  269. failed_as_expected = True
  270. log.info('test_pwdAdmin: Password update failed as expected: password (%s) result (%s)'
  271. % (passwd, e.message['desc']))
  272. if not failed_as_expected:
  273. log.fatal('test_pwdAdmin: We were incorrectly able to add an invalid password (%s)'
  274. % (passwd))
  275. assert False
  276. #
  277. # Now activate a password administator
  278. #
  279. log.info('test_pwdAdmin: Activate Password Administator and try updates again...')
  280. # Bind as root DN to make the update
  281. try:
  282. topology.standalone.simple_bind_s(DN_DM, PASSWORD)
  283. except ldap.LDAPError as e:
  284. log.fatal('test_pwdAdmin: Root DN failed to authenticate: ' + e.message['desc'])
  285. assert False
  286. # Update config - set the password admin
  287. try:
  288. topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'passwordAdminDN', ADMIN_DN)])
  289. except ldap.LDAPError as e:
  290. log.fatal('test_pwdAdmin: Failed to add password admin to config: ' +
  291. e.message['desc'])
  292. assert False
  293. # Bind as Password Admin
  294. try:
  295. topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
  296. except ldap.LDAPError as e:
  297. log.fatal('test_pwdAdmin: Failed to bind as the Password Admin: ' +
  298. e.message['desc'])
  299. assert False
  300. #
  301. # Make the same password updates, but this time they should succeed
  302. #
  303. for passwd in INVALID_PWDS:
  304. try:
  305. topology.standalone.modify_s(ENTRY_DN, [(ldap.MOD_REPLACE, 'userpassword', passwd)])
  306. except ldap.LDAPError as e:
  307. log.fatal('test_pwdAdmin: Password update failed unexpectedly: password (%s) result (%s)'
  308. % (passwd, e.message['desc']))
  309. assert False
  310. log.info('test_pwdAdmin: Password update succeeded (%s)' % passwd)
  311. #
  312. # Test Password Admin Group
  313. #
  314. log.info('test_pwdAdmin: Testing password admin group...')
  315. # Bind as root DN to make the update
  316. try:
  317. topology.standalone.simple_bind_s(DN_DM, PASSWORD)
  318. except ldap.LDAPError as e:
  319. log.fatal('test_pwdAdmin: Root DN failed to authenticate: ' + e.message['desc'])
  320. assert False
  321. # Update config - set the password admin group
  322. try:
  323. topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'passwordAdminDN', ADMIN_GROUP_DN)])
  324. except ldap.LDAPError as e:
  325. log.fatal('test_pwdAdmin: Failed to add password admin to config: ' +
  326. e.message['desc'])
  327. assert False
  328. # Bind as admin2
  329. try:
  330. topology.standalone.simple_bind_s(ADMIN2_DN, ADMIN_PWD)
  331. except ldap.LDAPError as e:
  332. log.fatal('test_pwdAdmin: Failed to bind as the Password Admin2: ' +
  333. e.message['desc'])
  334. assert False
  335. # Make some invalid password updates, but they should succeed
  336. for passwd in INVALID_PWDS:
  337. try:
  338. topology.standalone.modify_s(ENTRY_DN, [(ldap.MOD_REPLACE, 'userpassword', passwd)])
  339. except ldap.LDAPError as e:
  340. log.fatal('test_pwdAdmin: Password update failed unexpectedly: password (%s) result (%s)'
  341. % (passwd, e.message['desc']))
  342. assert False
  343. log.info('test_pwdAdmin: Password update succeeded (%s)' % passwd)
  344. # Cleanup - bind as Root DN for the other tests
  345. try:
  346. topology.standalone.simple_bind_s(DN_DM, PASSWORD)
  347. except ldap.LDAPError as e:
  348. log.fatal('test_pwdAdmin: Root DN failed to authenticate: ' + e.message['desc'])
  349. assert False
  350. def test_pwdAdmin_config_validation(topology):
  351. '''
  352. Test config validation:
  353. - Test adding multiple passwordAdminDN attributes
  354. - Test adding invalid values(non-DN's)
  355. '''
  356. # Add mulitple attributes - one already eists so just try and add as second one
  357. try:
  358. topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_ADD, 'passwordAdminDN', ENTRY_DN)])
  359. log.fatal('test_pwdAdmin_config_validation: Incorrectly was able to add two config attributes')
  360. assert False
  361. except ldap.LDAPError as e:
  362. log.info('test_pwdAdmin_config_validation: Failed as expected: ' +
  363. e.message['desc'])
  364. # Attempt to set invalid DN
  365. try:
  366. topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_ADD, 'passwordAdminDN', 'ZZZZZ')])
  367. log.fatal('test_pwdAdmin_config_validation: Incorrectly was able to add invalid DN')
  368. assert False
  369. except ldap.LDAPError as e:
  370. log.info('test_pwdAdmin_config_validation: Failed as expected: ' +
  371. e.message['desc'])
  372. def run_isolated():
  373. global installation1_prefix
  374. installation1_prefix = None
  375. topo = topology(True)
  376. test_pwdAdmin_init(topo)
  377. test_pwdAdmin(topo)
  378. test_pwdAdmin_config_validation(topo)
  379. if __name__ == '__main__':
  380. run_isolated()