attr_encryption_test.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. # --- BEGIN COPYRIGHT BLOCK ---
  2. # Copyright (C) 2020 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 logging
  10. import pytest
  11. from lib389.tasks import *
  12. from lib389.topologies import topology_st as topo
  13. from lib389.utils import *
  14. from lib389._constants import DEFAULT_SUFFIX
  15. from lib389.idm.user import UserAccounts, TEST_USER_PROPERTIES
  16. from lib389.backend import Backends
  17. from lib389.idm.domain import Domain
  18. from lib389.encrypted_attributes import EncryptedAttrs
  19. pytestmark = pytest.mark.tier1
  20. USER_DN = 'uid=test_user,%s' % DEFAULT_SUFFIX
  21. logging.getLogger(__name__).setLevel(logging.INFO)
  22. log = logging.getLogger(__name__)
  23. @pytest.fixture(scope="module")
  24. def enable_user_attr_encryption(topo, request):
  25. """ Enables attribute encryption for various attributes
  26. Adds a test user with encrypted attributes
  27. """
  28. log.info("Enable TLS for attribute encryption")
  29. topo.standalone.enable_tls()
  30. log.info("Enables attribute encryption")
  31. backends = Backends(topo.standalone)
  32. backend = backends.list()[0]
  33. encrypt_attrs = EncryptedAttrs(topo.standalone, basedn='cn=encrypted attributes,{}'.format(backend.dn))
  34. log.info("Enables attribute encryption for employeeNumber and telephoneNumber")
  35. emp_num_encrypt = encrypt_attrs.create(properties={'cn': 'employeeNumber', 'nsEncryptionAlgorithm': 'AES'})
  36. telephone_encrypt = encrypt_attrs.create(properties={'cn': 'telephoneNumber', 'nsEncryptionAlgorithm': '3DES'})
  37. log.info("Add a test user with encrypted attributes")
  38. users = UserAccounts(topo.standalone, DEFAULT_SUFFIX)
  39. test_user = users.create(properties=TEST_USER_PROPERTIES)
  40. test_user.replace('employeeNumber', '1000')
  41. test_user.replace('telephoneNumber', '1234567890')
  42. def fin():
  43. log.info("Remove attribute encryption for various attributes")
  44. emp_num_encrypt.delete()
  45. telephone_encrypt.delete()
  46. request.addfinalizer(fin)
  47. return test_user
  48. def test_basic(topo, enable_user_attr_encryption):
  49. """Tests encrypted attributes with a test user entry
  50. :id: d767d5c8-b934-4b14-9774-bd13480d81b3
  51. :setup: Standalone instance
  52. Enable AES encryption config on employeenumber
  53. Enable 3DES encryption config on telephoneNumber
  54. Add a test user with with encrypted attributes
  55. :steps:
  56. 1. Restart the server
  57. 2. Check employeenumber encryption enabled
  58. 3. Check telephoneNumber encryption enabled
  59. 4. Check that encrypted attribute is present for user i.e. telephoneNumber
  60. :expectedresults:
  61. 1. This should be successful
  62. 2. This should be successful
  63. 3. This should be successful
  64. 4. This should be successful
  65. """
  66. log.info("Restart the server")
  67. topo.standalone.restart()
  68. backends = Backends(topo.standalone)
  69. backend = backends.list()[0]
  70. encrypt_attrs = backend.get_encrypted_attrs()
  71. log.info("Extracting values of cn from the list of objects in encrypt_attrs")
  72. log.info("And appending the cn values in a list")
  73. enc_attrs_cns = []
  74. for enc_attr in encrypt_attrs:
  75. enc_attrs_cns.append(enc_attr.rdn)
  76. log.info("Check employeenumber encryption is enabled")
  77. assert "employeeNumber" in enc_attrs_cns
  78. log.info("Check telephoneNumber encryption is enabled")
  79. assert "telephoneNumber" in enc_attrs_cns
  80. log.info("Check that encrypted attribute is present for user i.e. telephoneNumber")
  81. assert enable_user_attr_encryption.present('telephoneNumber')
  82. def test_export_import_ciphertext(topo, enable_user_attr_encryption):
  83. """Configure attribute encryption, store some data, check that we can export the ciphertext
  84. :id: b433e215-2926-48a5-818f-c21abc40fc2d
  85. :setup: Standalone instance
  86. Enable AES encryption config on employeenumber
  87. Enable 3DES encryption config on telephoneNumber
  88. Add a test user with encrypted attributes
  89. :steps:
  90. 1. Export data as ciphertext
  91. 2. Check that the attribute is present in the exported file
  92. 3. Check that the encrypted value of attribute is not present in the exported file
  93. 4. Delete the test user entry with encrypted data
  94. 5. Import the previously exported data as ciphertext
  95. 6. Check attribute telephoneNumber should be imported
  96. :expectedresults:
  97. 1. This should be successful
  98. 2. This should be successful
  99. 3. This should be successful
  100. 4. This should be successful
  101. 5. This should be successful
  102. 6. This should be successful
  103. """
  104. log.info("Export data as ciphertext")
  105. export_ldif = os.path.join(topo.standalone.ds_paths.ldif_dir, "export_ciphertext.ldif")
  106. # Offline export
  107. topo.standalone.stop()
  108. if not topo.standalone.db2ldif(bename=DEFAULT_BENAME, suffixes=(DEFAULT_SUFFIX,),
  109. excludeSuffixes=None, encrypt=False, repl_data=None, outputfile=export_ldif):
  110. log.fatal('Failed to run offline db2ldif')
  111. assert False
  112. topo.standalone.start()
  113. log.info("Check that the attribute is present in the exported file")
  114. log.info("Check that the encrypted value of attribute is not present in the exported file")
  115. with open(export_ldif, 'r') as ldif_file:
  116. ldif = ldif_file.read()
  117. assert 'telephoneNumber' in ldif
  118. assert 'telephoneNumber: 1234567890' not in ldif
  119. log.info("Delete the test user entry with encrypted data")
  120. enable_user_attr_encryption.delete()
  121. log.info("Import data as ciphertext, which was exported previously")
  122. import_ldif = os.path.join(topo.standalone.ds_paths.ldif_dir, "export_ciphertext.ldif")
  123. # Offline export
  124. topo.standalone.stop()
  125. if not topo.standalone.ldif2db(bename=DEFAULT_BENAME, suffixes=(DEFAULT_SUFFIX,),
  126. excludeSuffixes=None, encrypt=False, import_file=import_ldif):
  127. log.fatal('Failed to run offline ldif2db')
  128. assert False
  129. topo.standalone.start()
  130. log.info("Check that the data with encrypted attribute is imported properly")
  131. users = UserAccounts(topo.standalone, DEFAULT_SUFFIX)
  132. user = users.get('testuser')
  133. assert user.present("telephoneNumber")
  134. def test_export_import_plaintext(topo, enable_user_attr_encryption):
  135. """Configure attribute encryption, store some data, check that we can export the plain text
  136. :id: b171e215-0456-48a5-245f-c21abc40fc2d
  137. :setup: Standalone instance
  138. Enable AES encryption config on employeenumber
  139. Enable 3DES encryption config on telephoneNumber
  140. Add a test user with encrypted attributes
  141. :steps:
  142. 1. Export data as plain text
  143. 2. Check that the attribute is present in the exported file
  144. 3. Check that the encrypted value of attribute is also present in the exported file
  145. 4. Delete the test user entry with encrypted data
  146. 5. Import data as plaintext
  147. 6. Check attribute value of telephoneNumber
  148. :expectedresults:
  149. 1. This should be successful
  150. 2. This should be successful
  151. 3. This should be successful
  152. 4. This should be successful
  153. 5. This should be successful
  154. 6. This should be successful
  155. """
  156. log.info("Export data as plain text")
  157. export_ldif = os.path.join(topo.standalone.ds_paths.ldif_dir, "export_plaintext.ldif")
  158. # Offline export
  159. topo.standalone.stop()
  160. if not topo.standalone.db2ldif(bename=DEFAULT_BENAME, suffixes=(DEFAULT_SUFFIX,),
  161. excludeSuffixes=None, encrypt=True, repl_data=None, outputfile=export_ldif):
  162. log.fatal('Failed to run offline db2ldif')
  163. assert False
  164. topo.standalone.start()
  165. log.info("Check that the attribute is present in the exported file")
  166. log.info("Check that the plain text value of the encrypted attribute is present in the exported file")
  167. with open(export_ldif, 'r') as ldif_file:
  168. assert 'telephoneNumber: 1234567890' in ldif_file.read()
  169. log.info("Delete the test user entry with encrypted data")
  170. enable_user_attr_encryption.delete()
  171. log.info("Import data as plain text, which was exported previously")
  172. import_ldif = os.path.join(topo.standalone.ds_paths.ldif_dir, "export_plaintext.ldif")
  173. # Offline export
  174. topo.standalone.stop()
  175. if not topo.standalone.ldif2db(bename=DEFAULT_BENAME, suffixes=(DEFAULT_SUFFIX,),
  176. excludeSuffixes=None, encrypt=True, import_file=import_ldif):
  177. log.fatal('Failed to run offline ldif2db')
  178. assert False
  179. topo.standalone.start()
  180. log.info("Check that the attribute is imported properly")
  181. users = UserAccounts(topo.standalone, DEFAULT_SUFFIX)
  182. user = users.get('testuser')
  183. assert user.present("telephoneNumber")
  184. def test_attr_encryption_unindexed(topo, enable_user_attr_encryption):
  185. """Configure attribute encryption for an un-indexed attribute, check that we can export encrypted data
  186. :id: d3ef38e1-bb5a-44d8-a3a4-4a25a57e3454
  187. :setup: Standalone instance
  188. Enable AES encryption config on employeenumber
  189. Enable 3DES encryption config on telephoneNumber
  190. Add a test user with encrypted attributes
  191. :steps:
  192. 1. Export data as cipher text
  193. 2. Check that the unindexed attribute employeenumber is present in exported ldif file
  194. 3. Check that the unindexed attribute employeenumber value is not present in exported ldif file
  195. :expectedresults:
  196. 1. This should be successful
  197. 2. This should be successful
  198. 3. This should be successful
  199. """
  200. log.info("Export data as cipher text")
  201. export_ldif = os.path.join(topo.standalone.ds_paths.ldif_dir, "emp_num_ciphertext.ldif")
  202. # Offline export
  203. topo.standalone.stop()
  204. if not topo.standalone.db2ldif(bename=DEFAULT_BENAME, suffixes=(DEFAULT_SUFFIX,),
  205. excludeSuffixes=None, encrypt=False, repl_data=None, outputfile=export_ldif):
  206. log.fatal('Failed to run offline db2ldif')
  207. assert False
  208. topo.standalone.start()
  209. log.info("Check that the attribute is present in the exported file")
  210. log.info("Check that the encrypted value of attribute is not present in the exported file")
  211. with open(export_ldif, 'r') as ldif_file:
  212. ldif = ldif_file.read()
  213. assert 'employeeNumber' in ldif
  214. assert 'employeeNumber: 1000' not in ldif
  215. def test_attr_encryption_multiple_backends(topo, enable_user_attr_encryption):
  216. """Tests Configuration of attribute encryption for multiple backends
  217. Where both the backends have attribute encryption
  218. :id: 9ece3e6c-96b7-4dd5-b092-d76dda23472d
  219. :setup: Standalone instance
  220. SSL Enabled
  221. :steps:
  222. 1. Add two test backends
  223. 2. Configure attribute encryption for telephoneNumber in one test backend
  224. 3. Configure attribute encryption for employeenumber in another test backend
  225. 4. Add a test user in both backends with encrypted attributes
  226. 5. Export data as ciphertext from both backends
  227. 6. Check that telephoneNumber is encrypted in the ldif file of db1
  228. 7. Check that employeeNumber is encrypted in the ldif file of db2
  229. 8. Delete both test backends
  230. :expectedresults:
  231. 1. This should be successful
  232. 2. This should be successful
  233. 3. This should be successful
  234. 4. This should be successful
  235. 5. This should be successful
  236. 6. This should be successful
  237. 7. This should be successful
  238. 8. This should be successful
  239. """
  240. log.info("Add two test backends")
  241. test_suffix1 = 'dc=test1,dc=com'
  242. test_db1 = 'test_db1'
  243. test_suffix2 = 'dc=test2,dc=com'
  244. test_db2 = 'test_db2'
  245. # Create backends
  246. backends = Backends(topo.standalone)
  247. backend = backends.list()[0]
  248. test_backend1 = backends.create(properties={'cn': test_db1,
  249. 'nsslapd-suffix': test_suffix1})
  250. test_backend2 = backends.create(properties={'cn': test_db2,
  251. 'nsslapd-suffix': test_suffix2})
  252. # Create the top of the tree
  253. suffix1 = Domain(topo.standalone, test_suffix1)
  254. test1 = suffix1.create(properties={'dc': 'test1'})
  255. suffix2 = Domain(topo.standalone, test_suffix2)
  256. test2 = suffix2.create(properties={'dc': 'test2'})
  257. log.info("Enables attribute encryption for telephoneNumber in test_backend1")
  258. backend1_encrypt_attrs = EncryptedAttrs(topo.standalone, basedn='cn=encrypted attributes,{}'.format(test_backend1.dn))
  259. b1_encrypt = backend1_encrypt_attrs.create(properties={'cn': 'telephoneNumber',
  260. 'nsEncryptionAlgorithm': 'AES'})
  261. log.info("Enables attribute encryption for employeeNumber in test_backend2")
  262. backend2_encrypt_attrs = EncryptedAttrs(topo.standalone, basedn='cn=encrypted attributes,{}'.format(test_backend2.dn))
  263. b2_encrypt = backend2_encrypt_attrs.create(properties={'cn': 'employeeNumber',
  264. 'nsEncryptionAlgorithm': 'AES'})
  265. log.info("Add a test user with encrypted attributes in both backends")
  266. users = UserAccounts(topo.standalone, test1.dn, None)
  267. test_user = users.create(properties=TEST_USER_PROPERTIES)
  268. test_user.replace('telephoneNumber', '1234567890')
  269. users = UserAccounts(topo.standalone, test2.dn, None)
  270. test_user = users.create(properties=TEST_USER_PROPERTIES)
  271. test_user.replace('employeeNumber', '1000')
  272. log.info("Export data as ciphertext from both backends")
  273. export_db1 = os.path.join(topo.standalone.ds_paths.ldif_dir, "export_db1.ldif")
  274. export_db2 = os.path.join(topo.standalone.ds_paths.ldif_dir, "export_db2.ldif")
  275. # Offline export
  276. topo.standalone.stop()
  277. if not topo.standalone.db2ldif(bename=test_db1, suffixes=(test_suffix1,),
  278. excludeSuffixes=None, encrypt=False, repl_data=None, outputfile=export_db1):
  279. log.fatal('Failed to run offline db2ldif')
  280. assert False
  281. if not topo.standalone.db2ldif(bename=test_db2, suffixes=(test_suffix2,),
  282. excludeSuffixes=None, encrypt=False, repl_data=None, outputfile=export_db2):
  283. log.fatal('Failed to run offline db2ldif')
  284. assert False
  285. topo.standalone.start()
  286. log.info("Check that the attribute is present in the exported file in db1")
  287. log.info("Check that the encrypted value of attribute is not present in the exported file in db1")
  288. with open(export_db1, 'r') as ldif_file:
  289. ldif = ldif_file.read()
  290. assert 'telephoneNumber' in ldif
  291. assert 'telephoneNumber: 1234567890' not in ldif
  292. log.info("Check that the attribute is present in the exported file in db2")
  293. log.info("Check that the encrypted value of attribute is not present in the exported file in db2")
  294. with open(export_db2, 'r') as ldif_file:
  295. ldif = ldif_file.read()
  296. assert 'employeeNumber' in ldif
  297. assert 'employeeNumber: 1000' not in ldif
  298. log.info("Delete test backends")
  299. test_backend1.delete()
  300. test_backend2.delete()
  301. def test_attr_encryption_backends(topo, enable_user_attr_encryption):
  302. """Tests Configuration of attribute encryption for single backend
  303. where more backends are present
  304. :id: f3ef40e1-17d6-44d8-a3a4-4a25a57e9064
  305. :setup: Standalone instance
  306. SSL Enabled
  307. :steps:
  308. 1. Add two test backends
  309. 2. Configure attribute encryption for telephoneNumber in one test backend
  310. 3. Add a test user in both backends with telephoneNumber
  311. 4. Export ldif from both test backends
  312. 5. Check that telephoneNumber is encrypted in the ldif file of db1
  313. 6. Check that telephoneNumber is not encrypted in the ldif file of db2
  314. 7. Delete both test backends
  315. :expectedresults:
  316. 1. This should be successful
  317. 2. This should be successful
  318. 3. This should be successful
  319. 4. This should be successful
  320. 5. This should be successful
  321. 6. This should be successful
  322. 7. This should be successful
  323. """
  324. log.info("Add two test backends")
  325. test_suffix1 = 'dc=test1,dc=com'
  326. test_db1 = 'test_db1'
  327. test_suffix2 = 'dc=test2,dc=com'
  328. test_db2 = 'test_db2'
  329. # Create backends
  330. backends = Backends(topo.standalone)
  331. test_backend1 = backends.create(properties={'cn': test_db1,
  332. 'nsslapd-suffix': test_suffix1})
  333. test_backend2 = backends.create(properties={'cn': test_db2,
  334. 'nsslapd-suffix': test_suffix2})
  335. # Create the top of the tree
  336. suffix1 = Domain(topo.standalone, test_suffix1)
  337. test1 = suffix1.create(properties={'dc': 'test1'})
  338. suffix2 = Domain(topo.standalone, test_suffix2)
  339. test2 = suffix2.create(properties={'dc': 'test2'})
  340. log.info("Enables attribute encryption for telephoneNumber in test_backend1")
  341. backend1_encrypt_attrs = EncryptedAttrs(topo.standalone, basedn='cn=encrypted attributes,{}'.format(test_backend1.dn))
  342. b1_encrypt = backend1_encrypt_attrs.create(properties={'cn': 'telephoneNumber',
  343. 'nsEncryptionAlgorithm': 'AES'})
  344. log.info("Add a test user with telephoneNumber in both backends")
  345. users = UserAccounts(topo.standalone, test1.dn, None)
  346. test_user = users.create(properties=TEST_USER_PROPERTIES)
  347. test_user.replace('telephoneNumber', '1234567890')
  348. users = UserAccounts(topo.standalone, test2.dn, None)
  349. test_user = users.create(properties=TEST_USER_PROPERTIES)
  350. test_user.replace('telephoneNumber', '1234567890')
  351. log.info("Export data as ciphertext from both backends")
  352. export_db1 = os.path.join(topo.standalone.ds_paths.ldif_dir, "export_db1.ldif")
  353. export_db2 = os.path.join(topo.standalone.ds_paths.ldif_dir, "export_db2.ldif")
  354. # Offline export
  355. topo.standalone.stop()
  356. if not topo.standalone.db2ldif(bename=test_db1, suffixes=(test_suffix1,),
  357. excludeSuffixes=None, encrypt=False, repl_data=None, outputfile=export_db1):
  358. log.fatal('Failed to run offline db2ldif')
  359. assert False
  360. if not topo.standalone.db2ldif(bename=test_db2, suffixes=(test_suffix2,),
  361. excludeSuffixes=None, encrypt=False, repl_data=None, outputfile=export_db2):
  362. log.fatal('Failed to run offline db2ldif')
  363. assert False
  364. topo.standalone.start()
  365. log.info("Check that the attribute is present in the exported file in db1")
  366. log.info("Check that the encrypted value of attribute is not present in the exported file in db1")
  367. with open(export_db1, 'r') as ldif_file:
  368. ldif = ldif_file.read()
  369. assert 'telephoneNumber' in ldif
  370. assert 'telephoneNumber: 1234567890' not in ldif
  371. log.info("Check that the attribute is present in the exported file in db2")
  372. log.info("Check that the value of attribute is also present in the exported file in db2")
  373. with open(export_db2, 'r') as ldif_file:
  374. ldif = ldif_file.read()
  375. assert 'telephoneNumber' in ldif
  376. assert 'telephoneNumber: 1234567890' in ldif
  377. log.info("Delete test backends")
  378. test_backend1.delete()
  379. test_backend2.delete()
  380. if __name__ == '__main__':
  381. # Run isolated
  382. # -s for DEBUG mode
  383. CURRENT_FILE = os.path.realpath(__file__)
  384. pytest.main("-s %s" % CURRENT_FILE)