This is an automated email from the git hooks/post-receive script.
mreynolds pushed a commit to branch 389-ds-base-1.4.0
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.4.0 by this push:
new ba02f5a Ticket 50155 - password history check has no way to just check the
current password
ba02f5a is described below
commit ba02f5a6f14595550c16883bb9279132dddb3bc1
Author: Mark Reynolds <mreynolds(a)redhat.com>
AuthorDate: Tue Jan 15 18:06:37 2019 +0000
Ticket 50155 - password history check has no way to just check the current password
Description: Currently if you set passwordinhistory 1, it checks the last
recorded password and the current password. To get it to just
check the current password we need to allow "0" in
passwordinhistory.
Then only check the current password, and not the entry's
passwordHistory attributes (if any).
Also added new "rebind" function to Accounts class to
"rebind"
on the current connection.
https://pagure.io/389-ds-base/issue/50155
Reviewed by: firstyear & spichugi (Thanks!!)
---
.../tests/suites/password/pwp_history_test.py | 209 ++++++++++-----------
ldap/servers/slapd/libglobs.c | 8 +-
ldap/servers/slapd/pw.c | 7 +-
src/lib389/lib389/idm/account.py | 7 +
4 files changed, 120 insertions(+), 111 deletions(-)
diff --git a/dirsrvtests/tests/suites/password/pwp_history_test.py
b/dirsrvtests/tests/suites/password/pwp_history_test.py
index 459f9b5..5972e82 100644
--- a/dirsrvtests/tests/suites/password/pwp_history_test.py
+++ b/dirsrvtests/tests/suites/password/pwp_history_test.py
@@ -7,10 +7,11 @@
# --- END COPYRIGHT BLOCK ---
#
import pytest
+import time
from lib389.tasks import *
from lib389.utils import *
from lib389.topologies import topology_st
-
+from lib389.idm.user import UserAccounts, TEST_USER_PROPERTIES
from lib389._constants import DN_DM, DEFAULT_SUFFIX, PASSWORD
logging.getLogger(__name__).setLevel(logging.DEBUG)
@@ -35,6 +36,10 @@ def test_basic(topology_st):
6. Attempt to change the password to previous passwords
7. Reset password by Directory Manager (admin reset)
8. Try and change the password to the previous password before the reset
+ 9. Test passwordInHistory set to "0" rejects only the current password
+ 10. Test passwordInHistory set to "2" rejects previous passwords
+
+
:expectedresults:
1. Password history policy should be configured successfully
2. User should be added successfully
@@ -47,10 +52,10 @@ def test_basic(topology_st):
7. Password should be successfully reset
8. Password change should be correctly rejected
with Constrant Violation error
+ 9. Success
+ 10. Success
"""
- USER_DN = 'uid=testuser,' + DEFAULT_SUFFIX
-
#
# Configure password history policy and add a test user
#
@@ -58,37 +63,25 @@ def test_basic(topology_st):
topology_st.standalone.config.replace_many(('passwordHistory',
'on'),
('passwordInHistory',
'3'),
('passwordChange',
'on'),
- ('passwordStorageScheme',
'CLEAR'))
+ ('passwordStorageScheme',
'CLEAR'),
+
('nsslapd-auditlog-logging-enabled', 'on'))
log.info('Configured password policy.')
except ldap.LDAPError as e:
log.fatal('Failed to configure password policy: ' + str(e))
assert False
time.sleep(1)
- try:
- topology_st.standalone.add_s(Entry((USER_DN, {
- 'objectclass': ['top', 'extensibleObject'],
- 'sn': 'user',
- 'cn': 'test user',
- 'uid': 'testuser',
- 'userpassword': 'password'})))
- except ldap.LDAPError as e:
- log.fatal('Failed to add test user' + USER_DN + ': error ' +
str(e))
- assert False
+ users = UserAccounts(topology_st.standalone, DEFAULT_SUFFIX)
+ user = users.create(properties=TEST_USER_PROPERTIES)
+ user.set('userpassword', 'password')
+ user.rebind('password')
#
# Test that password history is enforced.
#
- try:
- topology_st.standalone.simple_bind_s(USER_DN, 'password')
- except ldap.LDAPError as e:
- log.fatal('Failed to bind as user: ' + str(e))
- assert False
-
# Attempt to change password to the same password
try:
- topology_st.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
- 'userpassword',
b'password')])
+ user.set('userpassword', 'password')
log.info('Incorrectly able to to set password to existing password.')
assert False
except ldap.CONSTRAINT_VIOLATION:
@@ -100,110 +93,109 @@ def test_basic(topology_st):
#
# Keep changing password until we fill the password history (3)
#
+ user.set('userpassword', 'password1')
+ user.rebind('password1')
+ user.set('userpassword', 'password2')
+ user.rebind('password2')
+ user.set('userpassword', 'password3')
+ user.rebind('password3')
+ user.set('userpassword', 'password4')
+ user.rebind('password4')
+ time.sleep(1)
- # password1
- try:
- topology_st.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
- 'userpassword',
b'password1')])
- except ldap.LDAPError as e:
- log.fatal('Failed to change password: ' + str(e))
- assert False
- try:
- topology_st.standalone.simple_bind_s(USER_DN, 'password1')
- except ldap.LDAPError as e:
- log.fatal('Failed to bind as user using "password1": ' +
str(e))
+ #
+ # Check that we only have 3 passwords stored in history
+ #
+ pwds = user.get_attr_vals('passwordHistory')
+ if len(pwds) != 3:
+ log.fatal('Incorrect number of passwords stored in history: %d' %
+ len(pwds))
+ log.error('password history: ' + str(pwds))
assert False
- time.sleep(1)
+ else:
+ log.info('Correct number of passwords found in history.')
- # password2
+ #
+ # Attempt to change the password to previous passwords
+ #
try:
- topology_st.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
- 'userpassword',
b'password2')])
- except ldap.LDAPError as e:
- log.fatal('Failed to change password: ' + str(e))
+ user.set('userpassword', 'password1')
+ log.fatal('Incorrectly able to to set password to previous password1.')
+ log.error('password history: ' +
str(user.get_attr_vals('passwordhistory')))
assert False
- try:
- topology_st.standalone.simple_bind_s(USER_DN, 'password2')
+ except ldap.CONSTRAINT_VIOLATION:
+ log.info('Password change correctly rejected')
except ldap.LDAPError as e:
- log.fatal('Failed to bind as user using "password2": ' +
str(e))
+ log.fatal('Failed to attempt to change password: ' + str(e))
assert False
- time.sleep(1)
-
- # password3
try:
- topology_st.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
- 'userpassword',
b'password3')])
- except ldap.LDAPError as e:
- log.fatal('Failed to change password: ' + str(e))
+ user.set('userpassword', 'password2')
+ log.fatal('Incorrectly able to to set password to previous password2.')
+ log.error('password history: ' +
str(user.get_attr_vals('passwordhistory')))
assert False
- try:
- topology_st.standalone.simple_bind_s(USER_DN, 'password3')
+ except ldap.CONSTRAINT_VIOLATION:
+ log.info('Password change correctly rejected')
except ldap.LDAPError as e:
- log.fatal('Failed to bind as user using "password3": ' +
str(e))
+ log.fatal('Failed to attempt to change password: ' + str(e))
assert False
- time.sleep(1)
-
- # password4
try:
- topology_st.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
- 'userpassword',
b'password4')])
- except ldap.LDAPError as e:
- log.fatal('Failed to change password: ' + str(e))
+ user.set('userpassword', 'password3')
+ log.fatal('Incorrectly able to to set password to previous password3.')
+ log.error('password history: ' +
str(user.get_attr_vals('passwordhistory')))
assert False
- try:
- topology_st.standalone.simple_bind_s(USER_DN, 'password4')
+ except ldap.CONSTRAINT_VIOLATION:
+ log.info('Password change correctly rejected')
except ldap.LDAPError as e:
- log.fatal('Failed to bind as user using "password4": ' +
str(e))
+ log.fatal('Failed to attempt to change password: ' + str(e))
assert False
- time.sleep(1)
#
- # Check that we only have 3 passwords stored in history
+ # Reset password by Directory Manager(admin reset)
#
try:
- entry = topology_st.standalone.search_s(USER_DN, ldap.SCOPE_BASE,
- 'objectclass=*',
- ['passwordHistory'])
- pwds = entry[0].getValues('passwordHistory')
- if len(pwds) != 3:
- log.fatal('Incorrect number of passwords stored in histry: %d' %
- len(pwds))
- assert False
- else:
- log.info('Correct number of passwords found in history.')
+ topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
except ldap.LDAPError as e:
- log.fatal('Failed to get user entry: ' + str(e))
+ log.fatal('Failed to bind as rootDN: ' + str(e))
assert False
+ user.set('userpassword', 'password-reset')
+ time.sleep(1)
- #
- # Attempt to change the password to previous passwords
- #
+ # Try and change the password to the previous password before the reset
try:
- topology_st.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
- 'userpassword',
b'password1')])
- log.info('Incorrectly able to to set password to previous password1.')
+ user.rebind('password-reset')
+ user.set('userpassword', 'password4')
+ log.fatal('Incorrectly able to to set password to previous password4.')
+ log.error('password history: ' +
str(user.get_attr_vals('passwordhistory')))
assert False
except ldap.CONSTRAINT_VIOLATION:
log.info('Password change correctly rejected')
except ldap.LDAPError as e:
log.fatal('Failed to attempt to change password: ' + str(e))
assert False
- time.sleep(1)
+ #
+ # Test passwordInHistory to 0
+ #
try:
- topology_st.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
- 'userpassword',
b'password2')])
- log.info('Incorrectly able to to set password to previous password2.')
+ topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
+ except ldap.LDAPError as e:
+ log.fatal('Failed to bind as rootDN: ' + str(e))
assert False
- except ldap.CONSTRAINT_VIOLATION:
- log.info('Password change correctly rejected')
+
+ try:
+ topology_st.standalone.config.replace('passwordInHistory', '0')
+ log.info('Configured passwordInHistory to 0.')
except ldap.LDAPError as e:
- log.fatal('Failed to attempt to change password: ' + str(e))
+ log.fatal('Failed to configure password policy (passwordInHistory to 0):
' + str(e))
assert False
+
+ # Verify the older passwords in the entry (passwordhistory) are ignored
+ user.rebind('password-reset')
+ user.set('userpassword', 'password4')
try:
- topology_st.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
- 'userpassword',
b'password3')])
- log.info('Incorrectly able to to set password to previous password3.')
+ user.set('userpassword', 'password4')
+ log.fatal('Incorrectly able to to set password to current password4.')
+ log.error('password history: ' +
str(user.get_attr_vals('passwordhistory')))
assert False
except ldap.CONSTRAINT_VIOLATION:
log.info('Password change correctly rejected')
@@ -211,8 +203,12 @@ def test_basic(topology_st):
log.fatal('Failed to attempt to change password: ' + str(e))
assert False
+ # Need to make one successful update so history list is reset
+ user.set('userpassword', 'password5')
+
#
- # Reset password by Directory Manager(admin reset)
+ # Set the history count back to a positive value and make sure things still work
+ # as expected
#
try:
topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
@@ -221,33 +217,34 @@ def test_basic(topology_st):
assert False
try:
- topology_st.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
- 'userpassword',
- b'password-reset')])
+ topology_st.standalone.config.replace('passwordInHistory', '2')
+ log.info('Configured passwordInHistory to 2.')
except ldap.LDAPError as e:
- log.fatal('Failed to attempt to reset password: ' + str(e))
+ log.fatal('Failed to configure password policy (passwordInHistory to 2):
' + str(e))
assert False
time.sleep(1)
- # Try and change the password to the previous password before the reset
try:
- topology_st.standalone.simple_bind_s(USER_DN, 'password-reset')
+ user.rebind('password5')
+ user.set('userpassword', 'password5')
+ log.fatal('Incorrectly able to to set password to current password5.')
+ log.error('password history: ' +
str(user.get_attr_vals('passwordhistory')))
+ assert False
+ except ldap.CONSTRAINT_VIOLATION:
+ log.info('Password change correctly rejected')
except ldap.LDAPError as e:
- log.fatal('Failed to bind as user: ' + str(e))
+ log.fatal('Failed to attempt to change password: ' + str(e))
assert False
- time.sleep(1)
+ # Test that old password that was in history is not being checked
try:
- topology_st.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
- 'userpassword',
b'password4')])
- log.info('Incorrectly able to to set password to previous password4.')
- assert False
- except ldap.CONSTRAINT_VIOLATION:
- log.info('Password change correctly rejected')
+ user.set('userpassword', 'password1')
except ldap.LDAPError as e:
log.fatal('Failed to attempt to change password: ' + str(e))
+ log.error('password history: ' +
str(user.get_attr_vals('passwordhistory')))
assert False
+ # Done
log.info('Test suite PASSED.')
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
index a31a340..67a48b3 100644
--- a/ldap/servers/slapd/libglobs.c
+++ b/ldap/servers/slapd/libglobs.c
@@ -3407,8 +3407,8 @@ config_set_pw_maxfailure(const char *attrname, char *value, char
*errorbuf, int
int
config_set_pw_inhistory(const char *attrname, char *value, char *errorbuf, int apply)
{
- int retVal = LDAP_SUCCESS;
- long history = 0;
+ int32_t retVal = LDAP_SUCCESS;
+ int64_t history = 0;
char *endp = NULL;
slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
@@ -3420,9 +3420,9 @@ config_set_pw_inhistory(const char *attrname, char *value, char
*errorbuf, int a
errno = 0;
history = strtol(value, &endp, 10);
- if (*endp != '\0' || errno == ERANGE || history < 1 || history > 24) {
+ if (*endp != '\0' || errno == ERANGE || history < 0 || history > 24) {
slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
- "password history length \"%s\" is invalid.
The password history must range from 1 to 24", value);
+ "password history length \"%s\" is invalid.
The password history must range from 0 to 24", value);
retVal = LDAP_OPERATIONS_ERROR;
return retVal;
}
diff --git a/ldap/servers/slapd/pw.c b/ldap/servers/slapd/pw.c
index 7462a4f..5e7788a 100644
--- a/ldap/servers/slapd/pw.c
+++ b/ldap/servers/slapd/pw.c
@@ -1255,7 +1255,7 @@ check_pw_syntax_ext(Slapi_PBlock *pb, const Slapi_DN *sdn,
Slapi_Value **vals, c
if (pwpolicy->pw_history == 1) {
Slapi_Value **va = NULL;
attr = attrlist_find(e->e_attrs, "passwordHistory");
- if (attr && !valueset_isempty(&attr->a_present_values)) {
+ if (pwpolicy->pw_inhistory && attr &&
!valueset_isempty(&attr->a_present_values)) {
/* Resetting password history array if necessary. */
if (0 == update_pw_history(pb, sdn, NULL)) {
/* There was an update in the password history. Retry... */
@@ -1418,6 +1418,11 @@ update_pw_history(Slapi_PBlock *pb, const Slapi_DN *sdn, char
*old_pw)
pwpolicy = new_passwdPolicy(pb, dn);
+ if (pwpolicy->pw_inhistory == 0){
+ /* We are only enforcing the current password, just return */
+ return res;
+ }
+
/* retrieve the entry */
e = get_entry(pb, dn);
if (e == NULL) {
diff --git a/src/lib389/lib389/idm/account.py b/src/lib389/lib389/idm/account.py
index d25a585..a709473 100644
--- a/src/lib389/lib389/idm/account.py
+++ b/src/lib389/lib389/idm/account.py
@@ -54,6 +54,13 @@ class Account(DSLdapObject):
inst_clone.open(*args, **kwargs)
return inst_clone
+ def rebind(self, password):
+ """Rebind on the same connection
+ :param password: An entry password
+ :type password: str
+ """
+ self._instance.simple_bind_s(self.dn, password)
+
def sasl_bind(self, *args, **kwargs):
"""Open a new connection and bind with the entry via SASL.
You can pass arguments that will be pass to clone.
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.