From 986930d491d64ce32b91ed70d452074f2963fc55 Mon Sep 17 00:00:00 2001 From: Simon Pichugin Date: Wed, 24 Aug 2016 10:08:29 +0200 Subject: [PATCH 42/45] Ticket 48967 - Add CI test and refactor test suite Description: Add a test case to password policy test suite. Refactor structure of password test suite so it would become more logical. https://fedorahosted.org/389/ticket/48967 Reviewed by: nhosoi (Thank you, Noriko!) (cherry picked from commit 6abd5f49d8e32732a97794e68f642045f16f23e3) --- .../suites/password/pwdPolicy_attribute_test.py | 339 +++++++++++++++++++++ .../tests/suites/password/pwdPolicy_syntax_test.py | 151 +++++++++ .../tests/suites/password/pwdPolicy_test.py | 151 --------- .../tests/suites/password/pwd_change_policytest.py | 240 --------------- 4 files changed, 490 insertions(+), 391 deletions(-) create mode 100644 dirsrvtests/tests/suites/password/pwdPolicy_attribute_test.py create mode 100644 dirsrvtests/tests/suites/password/pwdPolicy_syntax_test.py delete mode 100644 dirsrvtests/tests/suites/password/pwdPolicy_test.py delete mode 100644 dirsrvtests/tests/suites/password/pwd_change_policytest.py diff --git a/dirsrvtests/tests/suites/password/pwdPolicy_attribute_test.py b/dirsrvtests/tests/suites/password/pwdPolicy_attribute_test.py new file mode 100644 index 0000000..d3be7e2 --- /dev/null +++ b/dirsrvtests/tests/suites/password/pwdPolicy_attribute_test.py @@ -0,0 +1,339 @@ +import os +import sys +import time +import subprocess +import ldap +import logging +import pytest +from lib389 import DirSrv, Entry, tools, tasks +from lib389.tools import DirSrvTools +from lib389._constants import * +from lib389.properties import * +from lib389.tasks import * +from lib389.utils import * + +DEBUGGING = False +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' + +if DEBUGGING: + logging.getLogger(__name__).setLevel(logging.DEBUG) +else: + logging.getLogger(__name__).setLevel(logging.INFO) + +log = logging.getLogger(__name__) + + +class TopologyStandalone(object): + """The DS Topology Class""" + def __init__(self, standalone): + """Init""" + standalone.open() + self.standalone = standalone + + +@pytest.fixture(scope="module") +def topology(request): + """Create DS Deployment""" + + # Creating standalone instance ... + if DEBUGGING: + standalone = DirSrv(verbose=True) + else: + standalone = DirSrv(verbose=False) + args_instance[SER_HOST] = HOST_STANDALONE + args_instance[SER_PORT] = PORT_STANDALONE + args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE + args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX + args_standalone = args_instance.copy() + standalone.allocate(args_standalone) + instance_standalone = standalone.exists() + if instance_standalone: + standalone.delete() + standalone.create() + standalone.open() + + def fin(): + """If we are debugging just stop the instances, otherwise remove + them + """ + if DEBUGGING: + standalone.stop() + else: + standalone.delete() + + request.addfinalizer(fin) + + + return TopologyStandalone(standalone) + + +@pytest.fixture(scope="module") +def test_user(topology, request): + """User for binding operation""" + + log.info('Adding user {}'.format(TEST_USER_DN)) + try: + topology.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.standalone.delete_s(TEST_USER_DN) + request.addfinalizer(fin) + + +@pytest.fixture(scope="module") +def password_policy(topology, test_user): + """Set up password policy for subtree and user""" + + log.info('Enable fine-grained policy') + try: + topology.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(['ns-newpwpolicy.pl', '-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.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(['ns-newpwpolicy.pl', '-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.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, 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.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.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 + + try: + log.info('Bind as user and modify userPassword') + topology.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD) + if exception: + with pytest.raises(exception): + topology.standalone.modify_s(TEST_USER_DN, [(ldap.MOD_REPLACE, + 'userPassword', + 'new_pass')]) + else: + topology.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.standalone.simple_bind_s(DN_DM, PASSWORD) + topology.standalone.modify_s(TEST_USER_DN, [(ldap.MOD_REPLACE, + 'userPassword', + TEST_USER_PWD)]) + + +def test_pwd_min_age(topology, 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.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.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.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 + + try: + log.info('Bind as user and modify userPassword') + topology.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD) + topology.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 + + + log.info('Bind as user and modify userPassword straight away after previous change') + topology.standalone.simple_bind_s(TEST_USER_DN, 'new_pass') + with pytest.raises(ldap.CONSTRAINT_VIOLATION): + topology.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.standalone.simple_bind_s(TEST_USER_DN, 'new_pass') + topology.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.standalone.simple_bind_s(DN_DM, PASSWORD) + topology.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) diff --git a/dirsrvtests/tests/suites/password/pwdPolicy_syntax_test.py b/dirsrvtests/tests/suites/password/pwdPolicy_syntax_test.py new file mode 100644 index 0000000..653d033 --- /dev/null +++ b/dirsrvtests/tests/suites/password/pwdPolicy_syntax_test.py @@ -0,0 +1,151 @@ +# --- BEGIN COPYRIGHT BLOCK --- +# Copyright (C) 2015 Red Hat, Inc. +# All rights reserved. +# +# License: GPL (version 3 or any later version). +# See LICENSE for details. +# --- END COPYRIGHT BLOCK --- +# +import os +import sys +import time +import ldap +import logging +import pytest +from lib389 import DirSrv, Entry, tools, tasks +from lib389.tools import DirSrvTools +from lib389._constants import * +from lib389.properties import * +from lib389.tasks import * + +logging.getLogger(__name__).setLevel(logging.DEBUG) +log = logging.getLogger(__name__) + +from lib389.config import RSA, Encryption, Config + +DEBUGGING = False + +USER_DN = 'uid=user,ou=People,%s' % DEFAULT_SUFFIX + +if DEBUGGING: + logging.getLogger(__name__).setLevel(logging.DEBUG) +else: + logging.getLogger(__name__).setLevel(logging.INFO) + + +log = logging.getLogger(__name__) + + +class TopologyStandalone(object): + """The DS Topology Class""" + def __init__(self, standalone): + """Init""" + standalone.open() + self.standalone = standalone + + +@pytest.fixture(scope="module") +def topology(request): + """Create DS Deployment""" + + # Creating standalone instance ... + if DEBUGGING: + standalone = DirSrv(verbose=True) + else: + standalone = DirSrv(verbose=False) + args_instance[SER_HOST] = HOST_STANDALONE + args_instance[SER_PORT] = PORT_STANDALONE + args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE + args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX + args_standalone = args_instance.copy() + standalone.allocate(args_standalone) + instance_standalone = standalone.exists() + if instance_standalone: + standalone.delete() + standalone.create() + standalone.open() + + # Deploy certs + # This is a trick. The nss db that ships with DS is broken + for f in ('key3.db', 'cert8.db', 'key4.db', 'cert9.db', 'secmod.db', 'pkcs11.txt'): + try: + os.remove("%s/%s" % (topology.standalone.confdir, f )) + except: + pass + + assert(standalone.nss_ssl.reinit() is True) + assert(standalone.nss_ssl.create_rsa_ca() is True) + assert(standalone.nss_ssl.create_rsa_key_and_cert() is True) + + # Say that we accept the cert + # Connect again! + + # Enable the SSL options + standalone.rsa.create() + standalone.rsa.set('nsSSLPersonalitySSL', 'Server-Cert') + standalone.rsa.set('nsSSLToken', 'internal (software)') + standalone.rsa.set('nsSSLActivation', 'on') + + standalone.config.set('nsslapd-secureport', PORT_STANDALONE2) + standalone.config.set('nsslapd-security', 'on') + + standalone.restart() + + + def fin(): + """If we are debugging just stop the instances, otherwise remove + them + """ + if DEBUGGING: + standalone.stop() + else: + standalone.delete() + + request.addfinalizer(fin) + + # Clear out the tmp dir + standalone.clearTmpDir(__file__) + + return TopologyStandalone(standalone) + +def _create_user(inst): + inst.add_s(Entry(( + USER_DN, { + 'objectClass': 'top account simplesecurityobject'.split(), + 'uid': 'user', + 'userpassword': 'password' + }))) + + +def test_pwdPolicy_constraint(topology): + ''' + Password policy test: Ensure that on a password change, the policy is + enforced correctly. + ''' + + # Create a user + _create_user(topology.standalone) + # Set the password policy globally + topology.standalone.config.set('passwordMinLength', '10') + topology.standalone.config.set('passwordMinDigits', '2') + topology.standalone.config.set('passwordCheckSyntax', 'on') + topology.standalone.config.set('nsslapd-pwpolicy-local', 'off') + # Now open a new ldap connection with TLS + userconn = ldap.initialize("ldap://%s:%s" % (HOST_STANDALONE, PORT_STANDALONE)) + userconn.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap. OPT_X_TLS_NEVER ) + userconn.start_tls_s() + userconn.simple_bind_s(USER_DN, 'password') + # This should have an exception! + try: + userconn.passwd_s(USER_DN, 'password', 'password1') + assert(False) + except ldap.CONSTRAINT_VIOLATION: + assert(True) + # Change the password to something invalid! + + +if __name__ == '__main__': + # Run isolated + # -s for DEBUG mode + CURRENT_FILE = os.path.realpath(__file__) + pytest.main("-s %s" % CURRENT_FILE) diff --git a/dirsrvtests/tests/suites/password/pwdPolicy_test.py b/dirsrvtests/tests/suites/password/pwdPolicy_test.py deleted file mode 100644 index 653d033..0000000 --- a/dirsrvtests/tests/suites/password/pwdPolicy_test.py +++ /dev/null @@ -1,151 +0,0 @@ -# --- BEGIN COPYRIGHT BLOCK --- -# Copyright (C) 2015 Red Hat, Inc. -# All rights reserved. -# -# License: GPL (version 3 or any later version). -# See LICENSE for details. -# --- END COPYRIGHT BLOCK --- -# -import os -import sys -import time -import ldap -import logging -import pytest -from lib389 import DirSrv, Entry, tools, tasks -from lib389.tools import DirSrvTools -from lib389._constants import * -from lib389.properties import * -from lib389.tasks import * - -logging.getLogger(__name__).setLevel(logging.DEBUG) -log = logging.getLogger(__name__) - -from lib389.config import RSA, Encryption, Config - -DEBUGGING = False - -USER_DN = 'uid=user,ou=People,%s' % DEFAULT_SUFFIX - -if DEBUGGING: - logging.getLogger(__name__).setLevel(logging.DEBUG) -else: - logging.getLogger(__name__).setLevel(logging.INFO) - - -log = logging.getLogger(__name__) - - -class TopologyStandalone(object): - """The DS Topology Class""" - def __init__(self, standalone): - """Init""" - standalone.open() - self.standalone = standalone - - -@pytest.fixture(scope="module") -def topology(request): - """Create DS Deployment""" - - # Creating standalone instance ... - if DEBUGGING: - standalone = DirSrv(verbose=True) - else: - standalone = DirSrv(verbose=False) - args_instance[SER_HOST] = HOST_STANDALONE - args_instance[SER_PORT] = PORT_STANDALONE - args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE - args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX - args_standalone = args_instance.copy() - standalone.allocate(args_standalone) - instance_standalone = standalone.exists() - if instance_standalone: - standalone.delete() - standalone.create() - standalone.open() - - # Deploy certs - # This is a trick. The nss db that ships with DS is broken - for f in ('key3.db', 'cert8.db', 'key4.db', 'cert9.db', 'secmod.db', 'pkcs11.txt'): - try: - os.remove("%s/%s" % (topology.standalone.confdir, f )) - except: - pass - - assert(standalone.nss_ssl.reinit() is True) - assert(standalone.nss_ssl.create_rsa_ca() is True) - assert(standalone.nss_ssl.create_rsa_key_and_cert() is True) - - # Say that we accept the cert - # Connect again! - - # Enable the SSL options - standalone.rsa.create() - standalone.rsa.set('nsSSLPersonalitySSL', 'Server-Cert') - standalone.rsa.set('nsSSLToken', 'internal (software)') - standalone.rsa.set('nsSSLActivation', 'on') - - standalone.config.set('nsslapd-secureport', PORT_STANDALONE2) - standalone.config.set('nsslapd-security', 'on') - - standalone.restart() - - - def fin(): - """If we are debugging just stop the instances, otherwise remove - them - """ - if DEBUGGING: - standalone.stop() - else: - standalone.delete() - - request.addfinalizer(fin) - - # Clear out the tmp dir - standalone.clearTmpDir(__file__) - - return TopologyStandalone(standalone) - -def _create_user(inst): - inst.add_s(Entry(( - USER_DN, { - 'objectClass': 'top account simplesecurityobject'.split(), - 'uid': 'user', - 'userpassword': 'password' - }))) - - -def test_pwdPolicy_constraint(topology): - ''' - Password policy test: Ensure that on a password change, the policy is - enforced correctly. - ''' - - # Create a user - _create_user(topology.standalone) - # Set the password policy globally - topology.standalone.config.set('passwordMinLength', '10') - topology.standalone.config.set('passwordMinDigits', '2') - topology.standalone.config.set('passwordCheckSyntax', 'on') - topology.standalone.config.set('nsslapd-pwpolicy-local', 'off') - # Now open a new ldap connection with TLS - userconn = ldap.initialize("ldap://%s:%s" % (HOST_STANDALONE, PORT_STANDALONE)) - userconn.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap. OPT_X_TLS_NEVER ) - userconn.start_tls_s() - userconn.simple_bind_s(USER_DN, 'password') - # This should have an exception! - try: - userconn.passwd_s(USER_DN, 'password', 'password1') - assert(False) - except ldap.CONSTRAINT_VIOLATION: - assert(True) - # Change the password to something invalid! - - -if __name__ == '__main__': - # Run isolated - # -s for DEBUG mode - CURRENT_FILE = os.path.realpath(__file__) - pytest.main("-s %s" % CURRENT_FILE) diff --git a/dirsrvtests/tests/suites/password/pwd_change_policytest.py b/dirsrvtests/tests/suites/password/pwd_change_policytest.py deleted file mode 100644 index 1d48c65..0000000 --- a/dirsrvtests/tests/suites/password/pwd_change_policytest.py +++ /dev/null @@ -1,240 +0,0 @@ -import os -import sys -import time -import subprocess -import ldap -import logging -import pytest -from lib389 import DirSrv, Entry, tools, tasks -from lib389.tools import DirSrvTools -from lib389._constants import * -from lib389.properties import * -from lib389.tasks import * -from lib389.utils import * - -DEBUGGING = False -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' - -if DEBUGGING: - logging.getLogger(__name__).setLevel(logging.DEBUG) -else: - logging.getLogger(__name__).setLevel(logging.INFO) - -log = logging.getLogger(__name__) - - -class TopologyStandalone(object): - """The DS Topology Class""" - def __init__(self, standalone): - """Init""" - standalone.open() - self.standalone = standalone - - -@pytest.fixture(scope="module") -def topology(request): - """Create DS Deployment""" - - # Creating standalone instance ... - if DEBUGGING: - standalone = DirSrv(verbose=True) - else: - standalone = DirSrv(verbose=False) - args_instance[SER_HOST] = HOST_STANDALONE - args_instance[SER_PORT] = PORT_STANDALONE - args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE - args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX - args_standalone = args_instance.copy() - standalone.allocate(args_standalone) - instance_standalone = standalone.exists() - if instance_standalone: - standalone.delete() - standalone.create() - standalone.open() - - def fin(): - """If we are debugging just stop the instances, otherwise remove - them - """ - if DEBUGGING: - standalone.stop() - else: - standalone.delete() - - request.addfinalizer(fin) - - - return TopologyStandalone(standalone) - - -@pytest.fixture(scope="module") -def test_user(topology, request): - """User for binding operation""" - - log.info('Adding user {}'.format(TEST_USER_DN)) - try: - topology.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.standalone.delete_s(TEST_USER_DN) - request.addfinalizer(fin) - - -@pytest.fixture(scope="module") -def password_policy(topology, test_user): - """Set up password policy for subtree and user""" - - log.info('Enable fine-grained policy') - try: - topology.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(['ns-newpwpolicy.pl', '-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.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(['ns-newpwpolicy.pl', '-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.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', - [('off', 'on', None), ('on', 'on', None), - ('on', 'off', ldap.UNWILLING_TO_PERFORM), - ('off', 'off', ldap.UNWILLING_TO_PERFORM)]) -def test_change_pwd(topology, 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.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.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 - - try: - log.info('Bind as user and modify userPassword') - topology.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD) - if exception: - with pytest.raises(exception): - topology.standalone.modify_s(TEST_USER_DN, [(ldap.MOD_REPLACE, - 'userPassword', - 'new_pass')]) - else: - topology.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.standalone.simple_bind_s(DN_DM, PASSWORD) - topology.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) -- 2.4.11