# --- BEGIN COPYRIGHT BLOCK --- # Copyright (C) 2016 Red Hat, Inc. # All rights reserved. # # License: GPL (version 3 or any later version). # See LICENSE for details. # --- END COPYRIGHT BLOCK --- # import pytest from lib389.tasks import * from lib389.utils import * from lib389.topologies import topology_st OU_PEOPLE = 'ou=people,{}'.format(DEFAULT_SUFFIX) TEST_USER_NAME = 'simplepaged_test' TEST_USER_DN = 'uid={},{}'.format(TEST_USER_NAME, OU_PEOPLE) TEST_USER_PWD = 'simplepaged_test' PW_POLICY_CONT_USER = 'cn="cn=nsPwPolicyEntry,uid=simplepaged_test,' \ 'ou=people,dc=example,dc=com",' \ 'cn=nsPwPolicyContainer,ou=people,dc=example,dc=com' PW_POLICY_CONT_PEOPLE = 'cn="cn=nsPwPolicyEntry,' \ 'ou=people,dc=example,dc=com",' \ 'cn=nsPwPolicyContainer,ou=people,dc=example,dc=com' logging.getLogger(__name__).setLevel(logging.INFO) log = logging.getLogger(__name__) @pytest.fixture(scope="module") def test_user(topology_st, request): """User for binding operation""" log.info('Adding user {}'.format(TEST_USER_DN)) try: topology_st.standalone.add_s(Entry((TEST_USER_DN, { 'objectclass': 'top person'.split(), 'objectclass': 'organizationalPerson', 'objectclass': 'inetorgperson', 'cn': TEST_USER_NAME, 'sn': TEST_USER_NAME, 'userpassword': TEST_USER_PWD, 'mail': '%s@redhat.com' % TEST_USER_NAME, 'uid': TEST_USER_NAME }))) except ldap.LDAPError as e: log.error('Failed to add user (%s): error (%s)' % (TEST_USER_DN, e.message['desc'])) raise e def fin(): log.info('Deleting user {}'.format(TEST_USER_DN)) topology_st.standalone.delete_s(TEST_USER_DN) request.addfinalizer(fin) @pytest.fixture(scope="module") def password_policy(topology_st, test_user): """Set up password policy for subtree and user""" log.info('Enable fine-grained policy') try: topology_st.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-pwpolicy-local', 'on')]) except ldap.LDAPError as e: log.error('Failed to set fine-grained policy: error {}'.format( e.message['desc'])) raise e log.info('Create password policy for subtree {}'.format(OU_PEOPLE)) try: subprocess.call(['%s/ns-newpwpolicy.pl' % topology_st.standalone.get_sbin_dir(), '-D', DN_DM, '-w', PASSWORD, '-p', str(PORT_STANDALONE), '-h', HOST_STANDALONE, '-S', OU_PEOPLE, '-Z', SERVERID_STANDALONE]) except subprocess.CalledProcessError as e: log.error('Failed to create pw policy policy for {}: error {}'.format( OU_PEOPLE, e.message['desc'])) raise e log.info('Add pwdpolicysubentry attribute to {}'.format(OU_PEOPLE)) try: topology_st.standalone.modify_s(OU_PEOPLE, [(ldap.MOD_REPLACE, 'pwdpolicysubentry', PW_POLICY_CONT_PEOPLE)]) except ldap.LDAPError as e: log.error('Failed to pwdpolicysubentry pw policy ' \ 'policy for {}: error {}'.format(OU_PEOPLE, e.message['desc'])) raise e log.info('Create password policy for subtree {}'.format(TEST_USER_DN)) try: subprocess.call(['%s/ns-newpwpolicy.pl' % topology_st.standalone.get_sbin_dir(), '-D', DN_DM, '-w', PASSWORD, '-p', str(PORT_STANDALONE), '-h', HOST_STANDALONE, '-U', TEST_USER_DN, '-Z', SERVERID_STANDALONE]) except subprocess.CalledProcessError as e: log.error('Failed to create pw policy policy for {}: error {}'.format( TEST_USER_DN, e.message['desc'])) raise e log.info('Add pwdpolicysubentry attribute to {}'.format(TEST_USER_DN)) try: topology_st.standalone.modify_s(TEST_USER_DN, [(ldap.MOD_REPLACE, 'pwdpolicysubentry', PW_POLICY_CONT_USER)]) except ldap.LDAPError as e: log.error('Failed to pwdpolicysubentry pw policy ' \ 'policy for {}: error {}'.format(TEST_USER_DN, e.message['desc'])) raise e @pytest.mark.parametrize('subtree_pwchange,user_pwchange,exception', [('on', 'off', ldap.UNWILLING_TO_PERFORM), ('off', 'off', ldap.UNWILLING_TO_PERFORM), ('off', 'on', None), ('on', 'on', None)]) def test_change_pwd(topology_st, test_user, password_policy, subtree_pwchange, user_pwchange, exception): """Verify that 'passwordChange' attr works as expected User should have a priority over a subtree. :Feature: Password policy :Setup: Standalone instance, test user, password policy entries for a user and a subtree :Steps: 1. Set passwordChange on the user and the subtree to various combinations 2. Bind as test user 3. Try to change password :Assert: Subtree/User passwordChange - result off/on, on/on - success on/off, off/off - UNWILLING_TO_PERFORM """ log.info('Set passwordChange to "{}" - {}'.format(subtree_pwchange, PW_POLICY_CONT_PEOPLE)) try: topology_st.standalone.modify_s(PW_POLICY_CONT_PEOPLE, [(ldap.MOD_REPLACE, 'passwordChange', subtree_pwchange)]) except ldap.LDAPError as e: log.error('Failed to set passwordChange ' \ 'policy for {}: error {}'.format(PW_POLICY_CONT_PEOPLE, e.message['desc'])) raise e log.info('Set passwordChange to "{}" - {}'.format(user_pwchange, PW_POLICY_CONT_USER)) try: topology_st.standalone.modify_s(PW_POLICY_CONT_USER, [(ldap.MOD_REPLACE, 'passwordChange', user_pwchange)]) except ldap.LDAPError as e: log.error('Failed to set passwordChange ' \ 'policy for {}: error {}'.format(PW_POLICY_CONT_USER, e.message['desc'])) raise e time.sleep(1) try: log.info('Bind as user and modify userPassword') topology_st.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD) if exception: with pytest.raises(exception): topology_st.standalone.modify_s(TEST_USER_DN, [(ldap.MOD_REPLACE, 'userPassword', 'new_pass')]) else: topology_st.standalone.modify_s(TEST_USER_DN, [(ldap.MOD_REPLACE, 'userPassword', 'new_pass')]) except ldap.LDAPError as e: log.error('Failed to change userpassword for {}: error {}'.format( TEST_USER_DN, e.message['info'])) raise e finally: log.info('Bind as DM') topology_st.standalone.simple_bind_s(DN_DM, PASSWORD) topology_st.standalone.modify_s(TEST_USER_DN, [(ldap.MOD_REPLACE, 'userPassword', TEST_USER_PWD)]) def test_pwd_min_age(topology_st, test_user, password_policy): """If we set passwordMinAge to some value, for example to 10, then it should not allow the user to change the password within 10 seconds after his previous change. :Feature: Password policy :Setup: Standalone instance, test user, password policy entries for a user and a subtree :Steps: 1. Set passwordMinAge to 10 on the user pwpolicy entry 2. Set passwordMinAge to 10 on the subtree pwpolicy entry 3. Set passwordMinAge to 10 on the cn=config entry 4. Bind as test user 5. Try to change password two times in a row 6. Wait 12 seconds 7. Try to change password :Assert: User should be not allowed to change the password right after previous change - CONSTRAINT_VIOLATION User should be not allowed to change the password after 12 seconds passed """ num_seconds = '10' log.info('Set passwordminage to "{}" - {}'.format(num_seconds, PW_POLICY_CONT_PEOPLE)) try: topology_st.standalone.modify_s(PW_POLICY_CONT_PEOPLE, [(ldap.MOD_REPLACE, 'passwordminage', num_seconds)]) except ldap.LDAPError as e: log.error('Failed to set passwordminage ' \ 'policy for {}: error {}'.format(PW_POLICY_CONT_PEOPLE, e.message['desc'])) raise e log.info('Set passwordminage to "{}" - {}'.format(num_seconds, PW_POLICY_CONT_USER)) try: topology_st.standalone.modify_s(PW_POLICY_CONT_USER, [(ldap.MOD_REPLACE, 'passwordminage', num_seconds)]) except ldap.LDAPError as e: log.error('Failed to set passwordminage ' \ 'policy for {}: error {}'.format(PW_POLICY_CONT_USER, e.message['desc'])) raise e log.info('Set passwordminage to "{}" - {}'.format(num_seconds, DN_CONFIG)) try: topology_st.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'passwordminage', num_seconds)]) except ldap.LDAPError as e: log.error('Failed to set passwordminage ' \ 'policy for {}: error {}'.format(DN_CONFIG, e.message['desc'])) raise e time.sleep(1) try: log.info('Bind as user and modify userPassword') topology_st.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD) topology_st.standalone.modify_s(TEST_USER_DN, [(ldap.MOD_REPLACE, 'userPassword', 'new_pass')]) except ldap.LDAPError as e: log.error('Failed to change userpassword for {}: error {}'.format( TEST_USER_DN, e.message['info'])) raise e time.sleep(1) log.info('Bind as user and modify userPassword straight away after previous change') topology_st.standalone.simple_bind_s(TEST_USER_DN, 'new_pass') with pytest.raises(ldap.CONSTRAINT_VIOLATION): topology_st.standalone.modify_s(TEST_USER_DN, [(ldap.MOD_REPLACE, 'userPassword', 'new_new_pass')]) log.info('Wait {} second'.format(int(num_seconds) + 2)) time.sleep(int(num_seconds) + 2) try: log.info('Bind as user and modify userPassword') topology_st.standalone.simple_bind_s(TEST_USER_DN, 'new_pass') topology_st.standalone.modify_s(TEST_USER_DN, [(ldap.MOD_REPLACE, 'userPassword', TEST_USER_PWD)]) except ldap.LDAPError as e: log.error('Failed to change userpassword for {}: error {}'.format( TEST_USER_DN, e.message['info'])) raise e finally: log.info('Bind as DM') topology_st.standalone.simple_bind_s(DN_DM, PASSWORD) topology_st.standalone.modify_s(TEST_USER_DN, [(ldap.MOD_REPLACE, 'userPassword', TEST_USER_PWD)]) if __name__ == '__main__': # Run isolated # -s for DEBUG mode CURRENT_FILE = os.path.realpath(__file__) pytest.main("-s %s" % CURRENT_FILE)