ticket47981_test.py 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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 ldap.sasl
  14. import logging
  15. import pytest
  16. from lib389 import DirSrv, Entry, tools, tasks
  17. from lib389.tools import DirSrvTools
  18. from lib389._constants import *
  19. from lib389.properties import *
  20. from lib389.tasks import *
  21. log = logging.getLogger(__name__)
  22. installation_prefix = None
  23. BRANCH = 'ou=people,' + DEFAULT_SUFFIX
  24. USER_DN = 'uid=user1,%s' % (BRANCH)
  25. BRANCH_CONTAINER = 'cn=nsPwPolicyContainer,ou=people,dc=example,dc=com'
  26. BRANCH_COS_DEF = 'cn=nsPwPolicy_CoS,ou=people,dc=example,dc=com'
  27. BRANCH_PWP = 'cn=cn\\3DnsPwPolicyEntry\\2Cou\\3DPeople\\2Cdc\\3Dexample\\2Cdc\\3Dcom,' + \
  28. 'cn=nsPwPolicyContainer,ou=People,dc=example,dc=com'
  29. BRANCH_COS_TMPL = 'cn=cn\\3DnsPwTemplateEntry\\2Cou\\3DPeople\\2Cdc\\3Dexample\\2Cdc\\3Dcom,' + \
  30. 'cn=nsPwPolicyContainer,ou=People,dc=example,dc=com'
  31. SECOND_SUFFIX = 'o=netscaperoot'
  32. BE_NAME = 'netscaperoot'
  33. class TopologyStandalone(object):
  34. def __init__(self, standalone):
  35. standalone.open()
  36. self.standalone = standalone
  37. @pytest.fixture(scope="module")
  38. def topology(request):
  39. '''
  40. This fixture is used to standalone topology for the 'module'.
  41. '''
  42. global installation_prefix
  43. if installation_prefix:
  44. args_instance[SER_DEPLOYED_DIR] = installation_prefix
  45. standalone = DirSrv(verbose=False)
  46. # Args for the standalone instance
  47. args_instance[SER_HOST] = HOST_STANDALONE
  48. args_instance[SER_PORT] = PORT_STANDALONE
  49. args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
  50. args_standalone = args_instance.copy()
  51. standalone.allocate(args_standalone)
  52. # Get the status of the instance and restart it if it exists
  53. instance_standalone = standalone.exists()
  54. # Remove the instance
  55. if instance_standalone:
  56. standalone.delete()
  57. # Create the instance
  58. standalone.create()
  59. # Used to retrieve configuration information (dbdir, confdir...)
  60. standalone.open()
  61. def fin():
  62. standalone.delete()
  63. request.addfinalizer(fin)
  64. # Here we have standalone instance up and running
  65. return TopologyStandalone(standalone)
  66. def addSubtreePwPolicy(inst):
  67. #
  68. # Add subtree policy to the people branch
  69. #
  70. try:
  71. inst.add_s(Entry((BRANCH_CONTAINER, {
  72. 'objectclass': 'top nsContainer'.split(),
  73. 'cn': 'nsPwPolicyContainer'
  74. })))
  75. except ldap.LDAPError as e:
  76. log.error('Failed to add subtree container for ou=people: error ' + e.message['desc'])
  77. assert False
  78. # Add the password policy subentry
  79. try:
  80. inst.add_s(Entry((BRANCH_PWP, {
  81. 'objectclass': 'top ldapsubentry passwordpolicy'.split(),
  82. 'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
  83. 'passwordMustChange': 'off',
  84. 'passwordExp': 'off',
  85. 'passwordHistory': 'off',
  86. 'passwordMinAge': '0',
  87. 'passwordChange': 'off',
  88. 'passwordStorageScheme': 'ssha'
  89. })))
  90. except ldap.LDAPError as e:
  91. log.error('Failed to add passwordpolicy: error ' + e.message['desc'])
  92. assert False
  93. # Add the COS template
  94. try:
  95. inst.add_s(Entry((BRANCH_COS_TMPL, {
  96. 'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
  97. 'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
  98. 'cosPriority': '1',
  99. 'cn': 'cn=nsPwTemplateEntry,ou=people,dc=example,dc=com',
  100. 'pwdpolicysubentry': BRANCH_PWP
  101. })))
  102. except ldap.LDAPError as e:
  103. log.error('Failed to add COS template: error ' + e.message['desc'])
  104. assert False
  105. # Add the COS definition
  106. try:
  107. inst.add_s(Entry((BRANCH_COS_DEF, {
  108. 'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
  109. 'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
  110. 'costemplatedn': BRANCH_COS_TMPL,
  111. 'cosAttribute': 'pwdpolicysubentry default operational-default'
  112. })))
  113. except ldap.LDAPError as e:
  114. log.error('Failed to add COS def: error ' + e.message['desc'])
  115. assert False
  116. time.sleep(0.5)
  117. def delSubtreePwPolicy(inst):
  118. try:
  119. inst.delete_s(BRANCH_COS_DEF)
  120. except ldap.LDAPError as e:
  121. log.error('Failed to delete COS def: error ' + e.message['desc'])
  122. assert False
  123. try:
  124. inst.delete_s(BRANCH_COS_TMPL)
  125. except ldap.LDAPError as e:
  126. log.error('Failed to delete COS template: error ' + e.message['desc'])
  127. assert False
  128. try:
  129. inst.delete_s(BRANCH_PWP)
  130. except ldap.LDAPError as e:
  131. log.error('Failed to delete COS password policy: error ' + e.message['desc'])
  132. assert False
  133. try:
  134. inst.delete_s(BRANCH_CONTAINER)
  135. except ldap.LDAPError as e:
  136. log.error('Failed to delete COS container: error ' + e.message['desc'])
  137. assert False
  138. time.sleep(0.5)
  139. def test_ticket47981(topology):
  140. """
  141. If there are multiple suffixes, and the last suffix checked does not contain any COS entries,
  142. while other suffixes do, then the vattr cache is not invalidated as it should be. Then any
  143. cached entries will still contain the old COS attributes/values.
  144. """
  145. log.info('Testing Ticket 47981 - Test that COS def changes are correctly reflected in affected users')
  146. #
  147. # Create a second backend that does not have any COS entries
  148. #
  149. log.info('Adding second suffix that will not contain any COS entries...\n')
  150. topology.standalone.backend.create(SECOND_SUFFIX, {BACKEND_NAME: BE_NAME})
  151. topology.standalone.mappingtree.create(SECOND_SUFFIX, bename=BE_NAME)
  152. try:
  153. topology.standalone.add_s(Entry((SECOND_SUFFIX, {
  154. 'objectclass': 'top organization'.split(),
  155. 'o': BE_NAME})))
  156. except ldap.ALREADY_EXISTS:
  157. pass
  158. except ldap.LDAPError as e:
  159. log.error('Failed to create suffix entry: error ' + e.message['desc'])
  160. assert False
  161. #
  162. # Add People branch, it might already exist
  163. #
  164. log.info('Add our test entries to the default suffix, and proceed with the test...')
  165. try:
  166. topology.standalone.add_s(Entry((BRANCH, {
  167. 'objectclass': 'top extensibleObject'.split(),
  168. 'ou': 'level4'
  169. })))
  170. except ldap.ALREADY_EXISTS:
  171. pass
  172. except ldap.LDAPError as e:
  173. log.error('Failed to add ou=people: error ' + e.message['desc'])
  174. assert False
  175. #
  176. # Add a user to the branch
  177. #
  178. try:
  179. topology.standalone.add_s(Entry((USER_DN, {
  180. 'objectclass': 'top extensibleObject'.split(),
  181. 'uid': 'user1'
  182. })))
  183. except ldap.LDAPError as e:
  184. log.error('Failed to add user1: error ' + e.message['desc'])
  185. assert False
  186. #
  187. # Enable password policy and add the subtree policy
  188. #
  189. try:
  190. topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-pwpolicy-local', 'on')])
  191. except ldap.LDAPError as e:
  192. log.error('Failed to set pwpolicy-local: error ' + e.message['desc'])
  193. assert False
  194. addSubtreePwPolicy(topology.standalone)
  195. #
  196. # Now check the user has its expected passwordPolicy subentry
  197. #
  198. try:
  199. entries = topology.standalone.search_s(USER_DN,
  200. ldap.SCOPE_BASE,
  201. '(objectclass=top)',
  202. ['pwdpolicysubentry', 'dn'])
  203. if not entries[0].hasAttr('pwdpolicysubentry'):
  204. log.fatal('User does not have expected pwdpolicysubentry!')
  205. assert False
  206. except ldap.LDAPError as e:
  207. log.fatal('Unable to search for entry %s: error %s' % (USER_DN, e.message['desc']))
  208. assert False
  209. #
  210. # Delete the password policy and make sure it is removed from the same user
  211. #
  212. delSubtreePwPolicy(topology.standalone)
  213. try:
  214. entries = topology.standalone.search_s(USER_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
  215. if entries[0].hasAttr('pwdpolicysubentry'):
  216. log.fatal('User unexpectedly does have the pwdpolicysubentry!')
  217. assert False
  218. except ldap.LDAPError as e:
  219. log.fatal('Unable to search for entry %s: error %s' % (USER_DN, e.message['desc']))
  220. assert False
  221. #
  222. # Add the subtree policvy back and see if the user now has it
  223. #
  224. addSubtreePwPolicy(topology.standalone)
  225. try:
  226. entries = topology.standalone.search_s(USER_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
  227. if not entries[0].hasAttr('pwdpolicysubentry'):
  228. log.fatal('User does not have expected pwdpolicysubentry!')
  229. assert False
  230. except ldap.LDAPError as e:
  231. log.fatal('Unable to search for entry %s: error %s' % (USER_DN, e.message['desc']))
  232. assert False
  233. if __name__ == '__main__':
  234. # Run isolated
  235. # -s for DEBUG mode
  236. CURRENT_FILE = os.path.realpath(__file__)
  237. pytest.main("-s %s" % CURRENT_FILE)