#50916 Issue 50912 - RFE - add password policy attribute pwdReset
Closed a year ago by spichugi. Opened 2 years ago by mreynolds.
mreynolds/389-ds-base issue50912  into  master

@@ -11,7 +11,7 @@ 

  from lib389.utils import *

  from lib389.topologies import topology_st

  from lib389.pwpolicy import PwPolicyManager

- from lib389.idm.user import UserAccounts, TEST_USER_PROPERTIES

+ from lib389.idm.user import UserAccount, UserAccounts, TEST_USER_PROPERTIES

  from lib389.idm.organizationalunit import OrganizationalUnits

  from lib389._constants import (DEFAULT_SUFFIX, DN_DM, PASSWORD)

  
@@ -70,6 +70,51 @@ 

      pwp.create_user_policy(TEST_USER_DN, policy_props)

  

  

+ @pytest.mark.skipif(ds_is_older('1.4.3.3'), reason="Not implemented")

+ def test_pwd_reset(topology_st, create_user):

+     """Test new password policy attribute "pwdReset"

+ 

+     :id: 03db357b-4800-411e-a36e-28a534293004

+     :setup: Standalone instance

+     :steps:

+         1. Enable passwordMustChange

+         2. Reset user's password

+         3. Check that the pwdReset attribute is set to TRUE

+         4. Bind as the user and change its password

+         5. Check that pwdReset is now set to FALSE

+         6. Reset password policy configuration

+     :expected results:

+         1. Success

+         2. Success

+         3. Success

+         4. Success

+         5. Success

+         6. Success

+     """

+ 

+     # Set password policy config

+     topology_st.standalone.config.replace('passwordMustChange', 'on')

+     time.sleep(.5)

+ 

+     # Reset user's password

+     our_user = UserAccount(topology_st.standalone, TEST_USER_DN)

+     our_user.replace('userpassword', PASSWORD)

+ 

+     # Check that pwdReset is TRUE

+     assert our_user.get_attr_val_utf8('pwdReset') == 'TRUE'

+ 

+     # Bind as user and change its own password

+     our_user.rebind(PASSWORD)

+     our_user.replace('userpassword', PASSWORD)

+ 

+     # Check that pwdReset is FALSE

+     topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)

+     assert our_user.get_attr_val_utf8('pwdReset') == 'FALSE'

+ 

+     # Reset password policy config

+     topology_st.standalone.config.replace('passwordMustChange', 'off')

+ 

+ 

  @pytest.mark.parametrize('subtree_pwchange,user_pwchange,exception',

                           [('on', 'off', ldap.UNWILLING_TO_PERFORM),

                            ('off', 'off', ldap.UNWILLING_TO_PERFORM),
@@ -114,7 +159,6 @@ 

      user_policy.set('passwordChange', user_pwchange)

      user_policy.set('passwordExp', 'on')

  

-     print("MARK attach gdb")

      time.sleep(1)

  

      try:

file modified
+2 -1
@@ -76,6 +76,7 @@ 

  attributeTypes: ( 2.16.840.1.113730.3.1.2350 NAME ( 'passwordDictPath' 'pwdDictPath' ) DESC '389 Directory Server password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN '389 Directory Server' )

  attributeTypes: ( 2.16.840.1.113730.3.1.2351 NAME ( 'passwordUserAttributes' 'pwdUserAttributes' ) DESC '389 Directory Server password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN '389 Directory Server' )

  attributeTypes: ( 2.16.840.1.113730.3.1.2352 NAME ( 'passwordBadWords' 'pwdBadWords' ) DESC '389 Directory Server password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN '389 Directory Server' )

+ attributeTypes: ( 2.16.840.1.113730.3.1.2366 NAME 'pwdReset' DESC '389 Directory Server password policy attribute type' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE USAGE directoryOperation X-ORIGIN '389 Directory Server' )

  attributeTypes: ( 2.16.840.1.113730.3.1.198 NAME 'memberURL' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Directory Server' )

  attributeTypes: ( 2.16.840.1.113730.3.1.199 NAME 'memberCertificateDescription' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Directory Server' )

  attributeTypes: ( 2.16.840.1.113730.3.1.207 NAME 'vlvBase' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape Directory Server' )
@@ -155,7 +156,7 @@ 

  objectClasses: ( 2.16.840.1.113730.3.2.7 NAME 'nsLicenseUser' DESC 'Netscape defined objectclass' SUP top MAY ( nsLicensedFor $ nsLicenseStartTime $ nsLicenseEndTime ) X-ORIGIN 'Netscape Administration Services' )

  objectClasses: ( 2.16.840.1.113730.3.2.1 NAME 'changeLogEntry' DESC 'LDAP changelog objectclass' SUP top MUST ( targetdn $ changeTime $ changenumber $ changeType ) MAY ( changes $ newrdn $ deleteoldrdn $ newsuperior ) X-ORIGIN 'Changelog Internet Draft' )

  objectClasses: ( 2.16.840.1.113730.3.2.6 NAME 'referral' DESC 'LDAP referrals objectclass' SUP top MAY ( ref ) X-ORIGIN 'LDAPv3 referrals Internet Draft' )

- objectClasses: ( 2.16.840.1.113730.3.2.12 NAME 'passwordObject' DESC 'Netscape defined password policy objectclass' SUP top MAY ( pwdpolicysubentry $ passwordExpirationTime $ passwordExpWarned $ passwordRetryCount $ retryCountResetTime $ accountUnlockTime $ passwordHistory $ passwordAllowChangeTime $ passwordGraceUserTime ) X-ORIGIN 'Netscape Directory Server' )

+ objectClasses: ( 2.16.840.1.113730.3.2.12 NAME 'passwordObject' DESC 'Netscape defined password policy objectclass' SUP top MAY ( pwdpolicysubentry $ passwordExpirationTime $ passwordExpWarned $ passwordRetryCount $ retryCountResetTime $ accountUnlockTime $ passwordHistory $ passwordAllowChangeTime $ passwordGraceUserTime $ pwdReset ) X-ORIGIN 'Netscape Directory Server' )

  objectClasses: ( 2.16.840.1.113730.3.2.13 NAME 'passwordPolicy' DESC 'Netscape defined password policy objectclass' SUP top MAY ( passwordMaxAge $ passwordExp $ passwordMinLength $ passwordKeepHistory $ passwordInHistory $ passwordChange $ passwordWarning $ passwordLockout $ passwordMaxFailure $ passwordResetDuration $ passwordUnlock $ passwordLockoutDuration $ passwordCheckSyntax $ passwordMustChange $ passwordStorageScheme $ passwordMinAge $ passwordResetFailureCount $ passwordGraceLimit $ passwordMinDigits $ passwordMinAlphas $ passwordMinUppers $ passwordMinLowers $ passwordMinSpecials $ passwordMin8bit $ passwordMaxRepeats $ passwordMinCategories $ passwordMinTokenLength $ passwordTrackUpdateTime $ passwordAdminDN $ passwordDictCheck $ passwordDictPath $ passwordPalindrome $ passwordMaxSequence $ passwordMaxClassChars $ passwordMaxSeqSets $ passwordBadWords $ passwordUserAttributes $ passwordSendExpiringTime ) X-ORIGIN 'Netscape Directory Server' )

  objectClasses: ( 2.16.840.1.113730.3.2.30 NAME 'glue' DESC 'Netscape defined objectclass' SUP top X-ORIGIN 'Netscape Directory Server' )

  objectClasses: ( 2.16.840.1.113730.3.2.32 NAME 'netscapeMachineData' DESC 'Netscape defined objectclass' SUP top X-ORIGIN 'Netscape Directory Server' )

file modified
+11 -1
@@ -715,6 +715,14 @@ 

          slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordgraceusertime", "0");

      }

  

+     if (slapi_entry_attr_hasvalue(e, "pwdReset", "TRUE")) {

+         /*

+          * Password was previously reset, just reset the "reset" flag for now.

+          * If the password is being reset again we will catch it below...

+          */

+         slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "pwdReset", "FALSE");

+     }

+ 

      /*

       * If the password is reset by a different user, mark it the first time logon.  If this is an internal

       * operation, we have a special case for the password modify extended operation where
@@ -723,8 +731,10 @@ 

       */

      if ((internal_op && pwpolicy->pw_must_change && (!pb_conn || strcasecmp(target_dn, pb_conn->c_dn))) ||

          (!internal_op && pwpolicy->pw_must_change &&

-          ((target_dn && bind_dn && strcasecmp(target_dn, bind_dn)) && pw_is_pwp_admin(pb, pwpolicy)))) {

+          ((target_dn && bind_dn && strcasecmp(target_dn, bind_dn)) && pw_is_pwp_admin(pb, pwpolicy))))

+     {

          pw_exp_date = NO_TIME;

+         slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "pwdReset", "TRUE");

      } else if (pwpolicy->pw_exp == 1) {

          Slapi_Entry *pse = NULL;

  

Ack from me, this seems quite simple.

The patch looks good but I miss how this password policy is enforced ?
I would expect any operation except MOD(userPassword) to be rejected and possibly a controlResult being sent. Is it already enforced with passwordExpirationTime ?

The patch looks good but I miss how this password policy is enforced ?
I would expect any operation except MOD(userPassword) to be rejected and possibly a controlResult being sent. Is it already enforced with passwordExpirationTime ?

We already enforce this, this RFE was to add a new attribute to the entry. It's basically redundant as the code already checks for "NO_TIME" to enforce password must be reset. But to be compatible with other LDAP vendors/clients we need this new attribute that makes it very clear the user must reset their password.

@mreynolds thanks for the explanation. You have my ACK as well

rebased onto 7923698

2 years ago

Pull-Request has been merged by mreynolds

2 years ago

389-ds-base is moving from Pagure to Github. This means that new issues and pull requests
will be accepted only in 389-ds-base's github repository.

This pull request has been cloned to Github as issue and is available here:
- https://github.com/389ds/389-ds-base/issues/3969

If you want to continue to work on the PR, please navigate to the github issue,
download the patch from the attachments and file a new pull request.

Thank you for understanding. We apologize for all inconvenience.

Pull-Request has been closed by spichugi

a year ago