encryption_cl5_test.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. # --- BEGIN COPYRIGHT BLOCK ---
  2. # Copyright (C) 2017 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. import pdb
  12. from lib389.utils import ensure_bytes, ds_supports_new_changelog
  13. from lib389.replica import ReplicationManager
  14. from lib389.dseldif import DSEldif
  15. from lib389.idm.user import UserAccounts, TEST_USER_PROPERTIES
  16. from lib389.topologies import topology_m2
  17. from lib389._constants import *
  18. pytestmark = pytest.mark.tier1
  19. ATTRIBUTE = 'unhashed#user#password'
  20. DEBUGGING = os.getenv("DEBUGGING", default=False)
  21. if DEBUGGING:
  22. logging.getLogger(__name__).setLevel(logging.DEBUG)
  23. else:
  24. logging.getLogger(__name__).setLevel(logging.INFO)
  25. log = logging.getLogger(__name__)
  26. @pytest.fixture(scope="module")
  27. def topology_with_tls(topology_m2):
  28. """Enable TLS on all masters"""
  29. [i.enable_tls() for i in topology_m2]
  30. repl = ReplicationManager(DEFAULT_SUFFIX)
  31. repl.test_replication(topology_m2.ms['master1'], topology_m2.ms['master2'])
  32. return topology_m2
  33. def _enable_changelog_encryption(inst, encrypt_algorithm):
  34. """Configure changelog encryption for master"""
  35. dse_ldif = DSEldif(inst)
  36. log.info('Configuring changelog encryption:{} for: {}'.format(inst.serverid, encrypt_algorithm))
  37. inst.stop()
  38. if ds_supports_new_changelog():
  39. changelog = 'cn=changelog,{}'.format(DN_USERROOT_LDBM)
  40. else:
  41. changelog = DN_CHANGELOG
  42. dse_ldif.replace(changelog, 'nsslapd-encryptionalgorithm', encrypt_algorithm)
  43. if dse_ldif.get(changelog, 'nsSymmetricKey'):
  44. dse_ldif.delete(changelog, 'nsSymmetricKey')
  45. inst.start()
  46. def _check_unhashed_userpw_encrypted(inst, change_type, user_dn, user_pw, is_encrypted):
  47. """Check if unhashed#user#password attribute value is encrypted or not"""
  48. if ds_supports_new_changelog():
  49. dbscanOut = inst.dbscan(DEFAULT_BENAME, 'changelog')
  50. else:
  51. changelog_dbdir = os.path.join(os.path.dirname(inst.dbdir), DEFAULT_CHANGELOG_DB)
  52. for dbfile in os.listdir(changelog_dbdir):
  53. if dbfile.endswith('.db'):
  54. changelog_dbfile = os.path.join(changelog_dbdir, dbfile)
  55. log.info('Changelog dbfile file exist: {}'.format(changelog_dbfile))
  56. log.info('Running dbscan -f to check {} attr'.format(ATTRIBUTE))
  57. dbscanOut = inst.dbscan(DEFAULT_CHANGELOG_DB, changelog_dbfile)
  58. count = 0
  59. for entry in dbscanOut.split(b'dbid: '):
  60. if ensure_bytes('operation: {}'.format(change_type)) in entry and\
  61. ensure_bytes(ATTRIBUTE) in entry and ensure_bytes(user_dn.lower()) in entry.lower():
  62. count += 1
  63. user_pw_attr = ensure_bytes('{}: {}'.format(ATTRIBUTE, user_pw))
  64. if is_encrypted:
  65. assert user_pw_attr not in entry, 'Changelog entry contains clear text password'
  66. else:
  67. assert user_pw_attr in entry, 'Changelog entry does not contain clear text password'
  68. assert count, 'Operation type and DN of the entry not matched in changelog'
  69. @pytest.mark.parametrize("encryption", ["AES", "3DES"])
  70. def test_algorithm_unhashed(topology_with_tls, encryption):
  71. """Check encryption algowithm AES and 3DES.
  72. And check unhashed#user#password attribute for encryption.
  73. :id: b7a37bf8-4b2e-4dbd-9891-70117d67558c
  74. :parametrized: yes
  75. :setup: Replication with two masters and SSL configured.
  76. :steps: 1. Enable changelog encrytion on master1 (try AES and 3DES).
  77. 2. Add a user to master1/master2
  78. 3. Run dbscan -f on m1 to check unhashed#user#password
  79. attribute is encrypted.
  80. 4. Run dbscan -f on m2 to check unhashed#user#password
  81. attribute is in cleartext.
  82. 5. Modify password in master2/master1
  83. 6. Run dbscan -f on m1 to check unhashed#user#password
  84. attribute is encrypted.
  85. 7. Run dbscan -f on m2 to check unhashed#user#password
  86. attribute is in cleartext.
  87. :expectedresults:
  88. 1. It should pass
  89. 2. It should pass
  90. 3. It should pass
  91. 4. It should pass
  92. 5. It should pass
  93. 6. It should pass
  94. 7. It should pass
  95. """
  96. m1 = topology_with_tls.ms['master1']
  97. m2 = topology_with_tls.ms['master2']
  98. m1.config.set('nsslapd-unhashed-pw-switch', 'on')
  99. m2.config.set('nsslapd-unhashed-pw-switch', 'on')
  100. test_passw = 'm2Test199'
  101. _enable_changelog_encryption(m1, encryption)
  102. for inst1, inst2 in ((m1, m2), (m2, m1)):
  103. # need to create a user specific to the encryption
  104. # else the two runs will hit the same user
  105. user_props={
  106. 'uid': 'testuser_%s' % encryption,
  107. 'cn' : 'testuser_%s' % encryption,
  108. 'sn' : 'user',
  109. 'uidNumber' : '1000',
  110. 'gidNumber' : '1000',
  111. 'homeDirectory' : '/home/testuser_%s' % encryption
  112. }
  113. user_props["userPassword"] = PASSWORD
  114. users = UserAccounts(inst1, DEFAULT_SUFFIX)
  115. tuser = users.create(properties=user_props)
  116. _check_unhashed_userpw_encrypted(m1, 'add', tuser.dn, PASSWORD, True)
  117. _check_unhashed_userpw_encrypted(m2, 'add', tuser.dn, PASSWORD, False)
  118. users = UserAccounts(inst2, DEFAULT_SUFFIX)
  119. tuser = users.get(tuser.rdn)
  120. tuser.set('userPassword', test_passw)
  121. _check_unhashed_userpw_encrypted(m1, 'modify', tuser.dn, test_passw, True)
  122. _check_unhashed_userpw_encrypted(m2, 'modify', tuser.dn, test_passw, False)
  123. tuser.delete()
  124. if __name__ == '__main__':
  125. # Run isolated
  126. # -s for DEBUG mode
  127. CURRENT_FILE = os.path.realpath(__file__)
  128. pytest.main("-s {}".format(CURRENT_FILE))