ticket48363_test.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. import os
  2. import sys
  3. import time
  4. import ldap
  5. import logging
  6. import pytest
  7. from lib389 import DirSrv, Entry, tools, tasks
  8. from lib389.tools import DirSrvTools
  9. from lib389._constants import *
  10. from lib389.properties import *
  11. from lib389.tasks import *
  12. from lib389.utils import *
  13. logging.getLogger(__name__).setLevel(logging.DEBUG)
  14. log = logging.getLogger(__name__)
  15. TEST_USER = 'uid=test,%s' % DEFAULT_SUFFIX
  16. # Well, it's better than "password" or "password1"
  17. TEST_PASS = 'banana cream pie'
  18. class TopologyStandalone(object):
  19. def __init__(self, standalone):
  20. standalone.open()
  21. self.standalone = standalone
  22. @pytest.fixture(scope="module")
  23. def topology(request):
  24. # Creating standalone instance ...
  25. standalone = DirSrv(verbose=False)
  26. args_instance[SER_HOST] = HOST_STANDALONE
  27. args_instance[SER_PORT] = PORT_STANDALONE
  28. args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
  29. args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX
  30. args_standalone = args_instance.copy()
  31. standalone.allocate(args_standalone)
  32. instance_standalone = standalone.exists()
  33. if instance_standalone:
  34. standalone.delete()
  35. standalone.create()
  36. standalone.open()
  37. # Delete each instance in the end
  38. def fin():
  39. standalone.delete()
  40. request.addfinalizer(fin)
  41. # Clear out the tmp dir
  42. standalone.clearTmpDir(__file__)
  43. return TopologyStandalone(standalone)
  44. def test_ticket48363(topology):
  45. """
  46. Test the implementation of rfc3673, '+' for all operational attributes.
  47. Please see: https://tools.ietf.org/html/rfc3673
  48. """
  49. # Test the implementation of the supportFeatures
  50. # Section 2:
  51. # Servers supporting this feature SHOULD publish the Object Identifier
  52. # 1.3.6.1.4.1.4203.1.5.1 as a value of the 'supportedFeatures'
  53. # [RFC3674] attribute in the root DSE.
  54. results = topology.standalone.search_s('', ldap.SCOPE_BASE, 'objectClass=*', ['supportedFeatures'] )[0]
  55. if results.hasAttr('supportedfeatures') is False:
  56. assert False
  57. if results.hasValue('supportedfeatures', '1.3.6.1.4.1.4203.1.5.1') is False:
  58. assert False
  59. # Section 2:
  60. # The presence of the attribute description "+" (ASCII 43) in the list
  61. # of attributes in a Search Request [RFC2251] SHALL signify a request
  62. # for the return of all operational attributes.
  63. # Test the two backends, rootdse, and a real ldbm backend
  64. # Root DSE
  65. results = topology.standalone.search_s('', ldap.SCOPE_BASE, 'objectClass=*', ['+'] )[0]
  66. # There are a number of obvious ones in rootdse. These are:
  67. rootdse_op_attrs = [
  68. 'supportedExtension',
  69. 'supportedControl',
  70. 'supportedFeatures',
  71. 'supportedSASLMechanisms',
  72. 'supportedLDAPVersion',
  73. 'vendorName',
  74. 'vendorVersion',
  75. ]
  76. for opattr in rootdse_op_attrs:
  77. if results.hasAttr(opattr) is False:
  78. assert False
  79. # LDBM backend
  80. # We are going to examine the root of the suffix, as it's a good easy target
  81. dc_op_attrs = [
  82. 'nsuniqueid',
  83. 'entrydn',
  84. 'entryid',
  85. 'aci',
  86. ]
  87. dc_user_attrs = [
  88. 'objectClass',
  89. 'dc',
  90. ]
  91. # We should show that the following work:
  92. # '+'
  93. results = topology.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_BASE, 'objectClass=*', ['+'] )[0]
  94. for opattr in dc_op_attrs:
  95. if results.hasAttr(opattr) is False:
  96. assert False
  97. for userattr in dc_user_attrs:
  98. if results.hasAttr(userattr) is False:
  99. assert True
  100. # '+' '*'
  101. results = topology.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_BASE, 'objectClass=*', ['+', '*'] )[0]
  102. for opattr in dc_op_attrs:
  103. if results.hasAttr(opattr) is False:
  104. assert False
  105. for userattr in dc_user_attrs:
  106. if results.hasAttr(userattr) is False:
  107. assert False
  108. # Section 2:
  109. # Client implementors should also note
  110. # that certain operational attributes may be returned only if requested
  111. # by name even when "+" is present.
  112. # We do not currently have any types that are excluded.
  113. # However, we should ensure that a search for "+ namedType" returns
  114. # both all operational and the namedType
  115. # '+' dc
  116. results = topology.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_BASE, 'objectClass=*', ['+', 'dc'] )[0]
  117. for opattr in dc_op_attrs:
  118. if results.hasAttr(opattr) is False:
  119. assert False
  120. if results.hasAttr('dc') is False:
  121. assert False
  122. if results.hasAttr('objectclass') is False:
  123. assert True
  124. # '*' nsUniqueId
  125. results = topology.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_BASE, 'objectClass=*', ['*', 'nsuniqueid'] )[0]
  126. for userattr in dc_user_attrs:
  127. if results.hasAttr(userattr) is False:
  128. assert False
  129. if results.hasAttr('nsuniqueid') is False:
  130. assert False
  131. if results.hasAttr('entrydn') is False:
  132. assert True
  133. # Section 2:
  134. # As with all search requests, client implementors should note that
  135. # results may not include all requested attributes due to access
  136. # controls or other restrictions.
  137. # Test that with a user with limit read aci, that these are enforced on
  138. # the + request.
  139. # Create the user
  140. uentry = Entry(TEST_USER)
  141. uentry.setValues('objectclass', 'top', 'extensibleobject')
  142. uentry.setValues('uid', 'test')
  143. uentry.setValues('userPassword', TEST_PASS)
  144. topology.standalone.add_s(uentry)
  145. # Give them a limited read aci: We may need to purge other acis
  146. anonaci = '(targetattr!="userPassword")(version 3.0; acl "Enable anonymous access"; allow (read, search, compare) userdn="ldap:///anyone";)'
  147. topology.standalone.modify_s(DEFAULT_SUFFIX, [(ldap.MOD_DELETE, 'aci', anonaci)])
  148. # Now we need to create an aci that allows anon/all read to only a few attrs
  149. # Lets make one real, and one operational.
  150. anonaci = '(targetattr="objectclass || dc || nsuniqueid")(version 3.0; acl "Enable anonymous access"; allow (read, search, compare) userdn="ldap:///anyone";)'
  151. topology.standalone.modify_s(DEFAULT_SUFFIX, [(ldap.MOD_ADD, 'aci', anonaci)])
  152. # bind as them, and test.
  153. topology.standalone.simple_bind_s(TEST_USER, TEST_PASS)
  154. results = topology.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_BASE, 'objectClass=*', ['*', '+'] )[0]
  155. if results.hasAttr('dc') is False:
  156. assert False
  157. if results.hasAttr('nsuniqueid') is False:
  158. assert False
  159. if results.hasAttr('entrydn') is False:
  160. assert True
  161. log.info('Test complete')
  162. if __name__ == '__main__':
  163. # Run isolated
  164. # -s for DEBUG mode
  165. CURRENT_FILE = os.path.realpath(__file__)
  166. pytest.main("-s %s" % CURRENT_FILE)