dirsrvtests/tests/suites/password/pwdPolicy_warning_test.py | 559 ++++++++++++
dirsrvtests/tests/tickets/ticket48369_test.py | 124 --
2 files changed, 559 insertions(+), 124 deletions(-)
New commits:
commit 4cbde48a73db91a49ccacf95a6ffcd5134c57cbe
Author: Simon Pichugin <spichugi(a)redhat.com>
Date: Tue Aug 30 10:13:50 2016 +0200
Ticket 48369 - Add CI test suite
Description: Add test suite to the Password test suite and remove old
test case from the Tickets dir.
Author: Punit Kundal <pkundal(a)redhat.com>
Refactored by: Simon Pichugin <spichugi(a)redhat.com>
Reviewed by: mreynolds (Thanks!)
diff --git a/dirsrvtests/tests/suites/password/pwdPolicy_warning_test.py b/dirsrvtests/tests/suites/password/pwdPolicy_warning_test.py
new file mode 100644
index 0000000..d064783
--- /dev/null
+++ b/dirsrvtests/tests/suites/password/pwdPolicy_warning_test.py
@@ -0,0 +1,559 @@
+import os
+import sys
+import time
+import ldap
+import logging
+import pytest
+import subprocess
+from lib389 import DirSrv, Entry, tools, tasks
+from ldap.controls.ppolicy import PasswordPolicyControl
+from lib389.tools import DirSrvTools
+from lib389._constants import *
+from lib389.properties import *
+from lib389.tasks import *
+from lib389.utils import *
+
+DEBUGGING = False
+CONFIG_ATTR = 'passwordSendExpiringTime'
+USER_DN = 'uid=tuser,{:s}'.format(DEFAULT_SUFFIX)
+USER_PASSWD = 'secret123'
+
+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
+
+
+(a)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)
+
+ # Clear out the tmp dir
+ standalone.clearTmpDir(__file__)
+
+ return TopologyStandalone(standalone)
+
+
+(a)pytest.fixture
+def global_policy(topology, request):
+ """Sets the required global
+ password policy attributes under
+ cn=config entry
+ """
+
+ attrs = {'passwordExp': '',
+ 'passwordMaxAge': '',
+ 'passwordWarning': '',
+ CONFIG_ATTR: ''}
+ try:
+ log.info('Get the default values')
+ entry = topology.standalone.getEntry(DN_CONFIG, ldap.SCOPE_BASE,
+ '(objectClass=*)', attrs.keys())
+
+ for key in attrs.keys():
+ attrs[key] = entry.getValue(key)
+
+ log.info('Set the new values')
+ topology.standalone.modify_s(DN_CONFIG, [
+ (ldap.MOD_REPLACE, 'passwordExp', 'on'),
+ (ldap.MOD_REPLACE, 'passwordMaxAge', '172800'),
+ (ldap.MOD_REPLACE, 'passwordWarning', '86400'),
+ (ldap.MOD_REPLACE, CONFIG_ATTR, 'on')])
+
+ except ldap.LDAPError as ex:
+ log.error("Failed to set global password policy, error:{:s}"\
+ .format(ex.message['desc']))
+ raise ex
+
+ def fin():
+ """Resets the defaults"""
+
+ try:
+ log.info('Reset the defaults')
+ for key in attrs.keys():
+ topology.standalone.modify_s(DN_CONFIG, [
+ (ldap.MOD_REPLACE, key, attrs[key])])
+ except ldap.LDAPError as ex:
+ log.error("Failed to set defaults, error:{:s}".format(ex.message['desc']))
+ raise ex
+ request.addfinalizer(fin)
+
+ # A short sleep is required after the modifying password policy or cn=config
+ time.sleep(0.5)
+
+
+(a)pytest.fixture
+def global_policy_default(topology, request):
+ """Sets the required global password policy
+ attributes for testing the default behavior
+ of password expiry warning time
+ """
+
+ attrs = {'passwordExp': '',
+ 'passwordMaxAge': '',
+ 'passwordWarning': '',
+ CONFIG_ATTR : ''}
+ try:
+ log.info('Get the default values')
+ entry = topology.standalone.getEntry(DN_CONFIG, ldap.SCOPE_BASE,
+ '(objectClass=*)', attrs.keys())
+ for key in attrs.keys():
+ attrs[key] = entry.getValue(key)
+
+ log.info('Set the new values')
+ topology.standalone.modify_s(DN_CONFIG, [
+ (ldap.MOD_REPLACE, 'passwordExp', 'on'),
+ (ldap.MOD_REPLACE, 'passwordMaxAge', '86400'),
+ (ldap.MOD_REPLACE, 'passwordWarning', '86400'),
+ (ldap.MOD_REPLACE, CONFIG_ATTR, 'off')])
+ except ldap.LDAPError as ex:
+ log.error("Failed to set global password policy, error:{:s}"\
+ .format(ex.message['desc']))
+ raise ex
+
+ def fin():
+ """Resets the defaults"""
+
+ log.info('Reset the defaults')
+ try:
+ for key in attrs.keys():
+ topology.standalone.modify_s(DN_CONFIG, [
+ (ldap.MOD_REPLACE, key, attrs[key])
+ ])
+ except ldap.LDAPError as ex:
+ log.error("Failed to reset defaults, error:{:s}"\
+ .format(ex.message['desc']))
+ raise ex
+ request.addfinalizer(fin)
+
+ # A short sleep is required after modifying password policy or cn=config
+ time.sleep(0.5)
+
+
+(a)pytest.fixture
+def add_user(topology, request):
+ """Adds a user for binding"""
+
+ user_data = {'objectClass': 'top person inetOrgPerson'.split(),
+ 'uid': 'tuser',
+ 'cn': 'test user',
+ 'sn': 'user',
+ 'userPassword': USER_PASSWD}
+
+ log.info('Add the user')
+ try:
+ topology.standalone.add_s(Entry((USER_DN, user_data)))
+ except ldap.LDAPError as ex:
+ log.error("Failed to add user, error:{:s}".format(ex.message['desc']))
+ raise ex
+
+ def fin():
+ """Removes the user entry"""
+
+ log.info('Remove the user entry')
+ try:
+ topology.standalone.delete_s(USER_DN)
+ except ldap.LDAPError as ex:
+ log.error("Failed to remove user, error:{:s}"\
+ .format(ex.message['desc']))
+ raise ex
+ request.addfinalizer(fin)
+
+
+(a)pytest.fixture
+def local_policy(topology, add_user):
+ """Sets fine grained policy for user entry"""
+
+ log.info("Setting fine grained policy for user ({:s})".format(USER_DN))
+ try:
+ subprocess.call(['/usr/sbin/ns-newpwpolicy.pl', '-D', DN_DM,
+ '-w', PASSWORD, '-h', HOST_STANDALONE,
+ '-p', str(PORT_STANDALONE), '-U', USER_DN,
+ '-Z', SERVERID_STANDALONE])
+ except subprocess.CalledProcessError as ex:
+ log.error("Failed to set fine grained policy, error:{:s}"\
+ .format(str(ex)))
+ raise ex
+
+ # A short sleep is required after modifying password policy
+ time.sleep(0.5)
+
+
+def get_password_warning(topology):
+ """Gets the password expiry warning time for the user"""
+
+ res_type = res_data = res_msgid = res_ctrls = None
+ result_id = ''
+
+ log.info('Bind with the user and request the password expiry warning time')
+ try:
+ result_id = topology.standalone.simple_bind(USER_DN, USER_PASSWD,
+ serverctrls = [PasswordPolicyControl()])
+ res_type, res_data, res_msgid, res_ctrls =\
+ topology.standalone.result3(result_id)
+
+ # This exception will be thrown when the user's password has expired
+ except ldap.INVALID_CREDENTIALS as ex:
+ raise ex
+ except ldap.LDAPError as ex:
+ log.error("Failed to get password expiry warning time, error:{:s}"\
+ .format(ex.message['desc']))
+ raise ex
+
+ # Return the control
+ return res_ctrls
+
+
+def set_conf_attr(topology, attr, val):
+ """Sets the value of a given attribute under cn=config"""
+
+ log.info("Setting {:s} to {:s}".format(attr, val))
+ try:
+ topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, attr, val)])
+ except ldap.LDAPError as ex:
+ log.error("Failed to set {:s} to {:s} error:{:s}"\
+ .format(attr, val, ex.message['desc']))
+ raise ex
+
+ # A short sleep is required after modifying cn=config
+ time.sleep(0.5)
+
+
+def get_conf_attr(topology, attr):
+ """Gets the value of a given
+ attribute under cn=config entry
+ """
+
+ try:
+ entry = topology.standalone.getEntry(DN_CONFIG, ldap.SCOPE_BASE,
+ '(objectClass=*)', [attr])
+ val = entry.getValue(attr)
+ except ldap.LDAPError as ex:
+ log.error("Failed to get the value of {:s}, error:{:s}"\
+ .format(attr, ex.message['desc']))
+ raise ex
+
+ # Return the value if no exeception is raised
+ return val
+
+
+(a)pytest.mark.parametrize("value", (' ' , 'junk123', 'on', 'off'))
+def test_different_values(topology, value):
+ """Try to set passwordSendExpiringTime attribute
+ to various values both valid and invalid
+
+ :Feature: Password Expiry Warning Time
+
+ :Setup: Standalone DS instance
+
+ :Steps: 1. Try to set valid and invalid values
+ for passwordSendExpiringTime attribute
+ under cn=config entry
+ 2. Run the search command to check the
+ value of passwordSendExpiringTime attribute
+
+ :Assert: 1. Invalid values should be rejected with
+ an OPERATIONS_ERROR
+ 2. Valid values should be accepted and saved
+ """
+
+ log.info('Get the default value')
+ defval = get_conf_attr(topology, CONFIG_ATTR)
+
+ if value not in ('on', 'off'):
+ log.info('An invalid value is being tested')
+ with pytest.raises(ldap.OPERATIONS_ERROR):
+ set_conf_attr(topology, CONFIG_ATTR, value)
+
+ log.info('Now check the value is unchanged')
+ assert get_conf_attr(topology, CONFIG_ATTR) == defval
+
+ log.info("Invalid value {:s} was rejected correctly".format(value))
+ else:
+ log.info('A valid value is being tested')
+ set_conf_attr(topology, CONFIG_ATTR, value)
+
+ log.info('Now check that the value has been changed')
+ assert get_conf_attr(topology, CONFIG_ATTR) == value
+
+ log.info("{:s} is now set to {:s}".format(CONFIG_ATTR, value))
+
+ log.info('Set passwordSendExpiringTime back to the default value')
+ set_conf_attr(topology, CONFIG_ATTR, defval)
+
+
+def test_expiry_time(topology, global_policy, add_user):
+ """Test whether the password expiry warning
+ time for a user is returned appropriately
+
+ :Feature: Pasword Expiry Warning Time
+
+ :Setup: Standalone DS instance with,
+ 1. Global password policy configured as below:
+ passwordExp: on
+ passwordMaxAge: 172800
+ passwordWarning: 86400
+ passwordSendExpiringTime: on
+ 2. User entry for binding
+
+ :Steps: 1. Bind as the user
+ 2. Request the control for the user
+
+ :Assert: The password expiry warning time for the user should be
+ returned
+ """
+
+ res_ctrls = None
+ try:
+ log.info('Get the password expiry warning time')
+ log.info("Binding with ({:s}) and requesting the password expiry warning time"\
+ .format(USER_DN))
+ res_ctrls = get_password_warning(topology)
+
+ log.info('Check whether the time is returned')
+ assert res_ctrls
+
+ log.info("user's password will expire in {:d} seconds"\
+ .format(res_ctrls[0].timeBeforeExpiration))
+ finally:
+ log.info("Rebinding as DM")
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+
+
+(a)pytest.mark.parametrize("attr,val",[(CONFIG_ATTR, 'off'),
+ ('passwordWarning', '3600')])
+def test_password_warning(topology, global_policy, add_user, attr, val):
+ """Test password expiry warning time by
+ setting passwordSendExpiringTime to off
+ and setting passwordWarning to a short value
+
+ :Feature: Password Expiry Warning Time
+
+ :Setup: Standalone DS instance with,
+ 1. Global password policy configures as below:
+ passwordExp: on
+ passwordMaxAge: 172800
+ passwordWarning: 86400
+ passwordSendExpiringTime: on
+ 2. User entry for binding
+
+ :Steps: 1. Set passwordSendExpiringTime attribute to off
+ 2. Bind as the user
+ 3. Request the control for the user
+
+ :Assert: Password expiry warning time should not be returned
+
+ :Steps: 1. Set passwordWarning to a small value
+ (for eg: 3600 seconds)
+ 2. Bind with the user and request the password expiry warning
+ time
+
+ :Assert: Password expiry warning time should be returned
+ """
+
+ try:
+ log.info('Set configuration parameter')
+ set_conf_attr(topology, attr, val)
+
+ log.info("Binding with ({:s}) and requesting password expiry warning time"\
+ .format(USER_DN))
+ res_ctrls = get_password_warning(topology)
+
+ log.info('Check the state of the control')
+ if not res_ctrls:
+ log.info("Password Expiry warning time is not returned as {:s} is set to {:s}"\
+ .format(attr, val))
+ else:
+ log.info("({:s}) password will expire in {:d} seconds"\
+ .format(USER_DN, res_ctrls[0].timeBeforeExpiration))
+ finally:
+ log.info("Rebinding as DM")
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+
+
+def test_with_different_password_states(topology, global_policy, add_user):
+ """Test the control with different password states
+
+ :Feature: Password Expiry Warning Time
+
+ :Setup: Standalone DS instance with,
+ 1. Global password policy configured as below:
+ passwordExp: on
+ passwordMaxAge: 172800
+ passwordWarning: 86400
+ passwordSendExpiringTime: on
+ 2. User entry for binding to the server
+
+ :Steps: 1. Expire user's password by setting the system
+ date past the valid period for the password
+ 2. Try to bind to the server with the user entry
+ 3. Set the system date to the current day
+ 4. Try to bind with the user entry and request
+ the control
+
+ :Assert: 1. In the first try, the bind should fail with an
+ INVALID_CREDENTIALS error
+ 2. In the second try, the bind should be successful
+ and the password expiry warning time should be
+ returned
+ """
+
+ res_ctrls = None
+ try:
+ log.info("Expiring user's password by moving the"\
+ " system date past the valid period")
+ subprocess.check_call(['/usr/bin/date', '-s', 'next month'])
+
+ log.info('Wait for the server to pick up new date')
+ time.sleep(5)
+
+ log.info("Attempting to bind with user {:s} and retrive the password"\
+ " expiry warning time".format(USER_DN))
+ with pytest.raises(ldap.INVALID_CREDENTIALS) as ex:
+ res_ctrls = get_password_warning(topology)
+
+ log.info("Bind Failed, error: {:s}".format(str(ex)))
+
+ log.info("Resetting the system date")
+ subprocess.check_call(['/usr/bin/date', '-s', 'last month'])
+
+ log.info('Wait for the server to pick up new date')
+ time.sleep(5)
+
+ log.info("Rebinding with {:s} and retrieving the password"\
+ " expiry warning time".format(USER_DN))
+ res_ctrls = get_password_warning(topology)
+
+ log.info('Check that the control is returned')
+ assert res_ctrls
+
+ log.info("user's password will expire in {:d} seconds"\
+ .format(res_ctrls[0].timeBeforeExpiration))
+ finally:
+ log.info("Rebinding as DM")
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+
+
+def test_default_behavior(topology, global_policy_default, add_user):
+ """Test the default behavior of password
+ expiry warning time
+
+ :Feature: Password Expiry Warning Time
+
+ :Setup: Standalone DS instance with,
+ 1. Global password policy configured as follows,
+ passwordExp: on
+ passwordMaxAge: 86400
+ passwordWarning: 86400
+ passwordSendExpiringTime: off
+ 2. User entry for binding to the server
+
+ :Steps: 1. Bind as the user
+ 2. Request the control for the user
+
+ :Assert: Password expiry warning time should be returned by the
+ server by the server since passwordMaxAge and
+ passwordWarning are set to the same value
+ """
+
+ res_ctrls = None
+ try:
+ log.info("Binding with {:s} and requesting the password expiry warning time"\
+ .format(USER_DN))
+ res_ctrls = get_password_warning(topology)
+
+ log.info('Check that control is returned even'
+ 'if passwordSendExpiringTime is set to off')
+ assert res_ctrls
+
+ log.info("user's password will expire in {:d} seconds"\
+ .format(res_ctrls[0].timeBeforeExpiration))
+ finally:
+ log.info("Rebinding as DM")
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+
+
+def test_with_local_policy(topology, global_policy, local_policy):
+ """Test the attribute with fine grained policy
+ set for the user
+
+ :Feature: Password Expiry Warning Time
+
+ :Setup: Standalone DS instance with,
+ 1. Global password policy configured as below,
+ passwordExp: on
+ passwordMaxAge: 172800
+ passwordWarning: 86400
+ passwordSendExpiringTime: on
+ 2. User entry for binding to the server
+ 3. Configure fine grained password policy for the user
+ as below:
+ ns-newpwpolicy.pl -D 'cn=Directory Manager' -w secret123
+ -h localhost -p 389 -U 'uid=tuser,dc=example,dc=com'
+
+ :Steps: 1. Bind as the user
+ 2. Request the control for the user
+
+ :Assert: Password expiry warning time should not be returned for the
+ user
+ """
+
+ res_ctrls = None
+ try:
+ log.info("Attempting to get password expiry warning time for"\
+ " user {:s}".format(USER_DN))
+ res_ctrls = get_password_warning(topology)
+
+ log.info('Check that the control is not returned')
+ assert not res_ctrls
+
+ log.info("Password expiry warning time is not returned")
+ finally:
+ log.info("Rebinding as DM")
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+
+
+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/tickets/ticket48369_test.py b/dirsrvtests/tests/tickets/ticket48369_test.py
deleted file mode 100644
index 37f4272..0000000
--- a/dirsrvtests/tests/tickets/ticket48369_test.py
+++ /dev/null
@@ -1,124 +0,0 @@
-import os
-import time
-import ldap
-import logging
-import pytest
-from lib389 import DirSrv, Entry
-from lib389._constants import *
-from lib389.properties import *
-from lib389.tasks import *
-from lib389.utils import *
-from ldap.controls.ppolicy import PasswordPolicyControl
-
-
-logging.getLogger(__name__).setLevel(logging.DEBUG)
-log = logging.getLogger(__name__)
-
-installation1_prefix = None
-
-
-class TopologyStandalone(object):
- def __init__(self, standalone):
- standalone.open()
- self.standalone = standalone
-
-
-(a)pytest.fixture(scope="module")
-def topology(request):
- global installation1_prefix
- if installation1_prefix:
- args_instance[SER_DEPLOYED_DIR] = installation1_prefix
-
- # Creating standalone instance ...
- 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()
-
- # Delete each instance in the end
- def fin():
- standalone.delete()
-
- request.addfinalizer(fin)
-
- # Clear out the tmp dir
- standalone.clearTmpDir(__file__)
-
- return TopologyStandalone(standalone)
-
-
-def test_ticket48369(topology):
- """
- Test RFE 48369 - return password policy controls by default without needing
- to be requested.
- """
-
- DN = 'uid=test,' + DEFAULT_SUFFIX
-
- #
- # Setup password policy
- #
- try:
- topology.standalone.modify_s('cn=config', [(ldap.MOD_REPLACE,
- 'passwordExp',
- 'on'),
- (ldap.MOD_REPLACE,
- 'passwordMaxAge',
- '864000'),
- (ldap.MOD_REPLACE,
- 'passwordSendExpiringTime',
- 'on')])
- except ldap.LDAPError as e:
- log.fatal('Failed to set config: %s' % str(e))
- assert False
-
- #
- # Add entry
- #
- try:
- topology.standalone.add_s(Entry((DN,
- {'objectclass': 'top extensibleObject'.split(),
- 'uid': 'test',
- 'userpassword': 'password'})))
- except ldap.LDAPError as e:
- log.fatal('Failed to add user entry: %s' % str(e))
- assert False
- time.sleep(1)
-
- #
- # Bind as the new user, and request the control
- #
- try:
- msgid = topology.standalone.simple_bind(DN, "password",
- serverctrls=[PasswordPolicyControl()])
- res_type, res_data, res_msgid, res_ctrls = \
- topology.standalone.result3(msgid)
- except ldap.LDAPError as e:
- log.fatal('Failed to bind: %s: Error %s' % (ctl_resp, str(e)))
- assert False
-
- if res_ctrls[0].controlType == PasswordPolicyControl.controlType:
- ppolicy_ctrl = res_ctrls[0]
- else:
- log.fatal('Control not found')
- assert False
-
- log.info('Time until expiration (%s)' %
- repr(ppolicy_ctrl.timeBeforeExpiration))
-
- log.info('Test complete')
-
-
-if __name__ == '__main__':
- # Run isolated
- # -s for DEBUG mode
- CURRENT_FILE = os.path.realpath(__file__)
- pytest.main("-s %s" % CURRENT_FILE)