If we have passwordMustChange policy enabled and try to add an entry that already contains an passwordExpirationTime attribute, then the passwordMustChange code will insert another passwordExpirationTime attribute with the magic 19700101000000Z value. This wont work because passwordExpirationTime is single-valued: ldap_add: Object class violation ldap_add: additional info: single-valued attribute "passwordExpirationTime" has multiple values We need to pick one passwordExpirationTime value to "win". I think it makes sense for the value that exists in the entry being added to win, but I'm open to discussion if it's felt that would violate the password policy. To make the existing passwordExpirationTime value win, in add_password_attrs() in pw.c I think the logic can be changed so the scan for passwordExpirationTime happens unconditionally and then not touch it even if pwpolicy->pw_must_change is set.
Created attachment 450591 [details] patch proposal
Steps to verify: Enable fine-grained password policy, and click "fine-grained subtree policy enabled", "User must change password after reset", "User may change password" and set "Allow changes in N day(s)". Any digit is fine. Click Password expires after N days. Any ditit is fine. Sample entry 1 (passwordExpirationTime has already passed): ldapmodify ... << EOF dn: cn=test user0,ou=People,dc=example,dc=com objectClass: top objectClass: person sn: user0 cn: test user0 userPassword: tuser0 passwordExpirationTime: 20120326005407Z EOF This entry should be successfully added. Search should return both passwordExpirationTime and passwordallowchangetime. Note: passwordExpirationTime should be the same value added originally. $ ldapsearch ... -b "cn=test user0,ou=people,dc=example,dc=com" "(cn=*)" \ passwordExpirationTime passwordallowchangetime dn: cn=test user0,ou=People,dc=example,dc=com passwordExpirationTime: 20120326005407Z passwordallowchangetime: 20101221015915Z Sample entry 2 (passwordExpirationTime has already passed): ldapmodify ... << EOF dn: cn=test user1,ou=People,dc=example,dc=com objectClass: top objectClass: person sn: user1 cn: test user1 userPassword: tuser1 passwordExpirationTime: 20000326005407Z EOF This entry should be successfully added. Search should return just passwordExpirationTime. Note: passwordExpirationTime should be the same value added originally. $ ldapsearch ... -b "cn=test user1,ou=people,dc=example,dc=com" "(cn=*)" \ passwordExpirationTime passwordallowchangetime dn: cn=test user1,ou=People,dc=example,dc=com passwordExpirationTime: 20000326005407Z Sample entry 3 (Entry includes both passwordExpirationTime and passwordallowchangetime): ldapmodify ... << EOF dn: cn=test user2,ou=People,dc=example,dc=com objectClass: top objectClass: person sn: user2 cn: test user2 userPassword: tuser2 passwordExpirationTime: 20120326005407Z passwordallowchangetime: 20110326005407Z EOF This entry should be successfully added. Search should return both passwordExpirationTime and passwordallowchangetime. Note: both values should be the same as the ones added originally. $ ldapsearch ... -b "cn=test user2,ou=people,dc=example,dc=com" "(cn=*)" \ passwordExpirationTime passwordallowchangetime dn: cn=test user2,ou=People,dc=example,dc=com passwordExpirationTime: 20120326005407Z passwordallowchangetime: 20110326005407Z
Reviewed by Rich and Noriko. Pushing the patch to master on behalf of Ulf. (Thanks for the patch!!) $ git merge 489379 Updating ad544f2..f977972 Fast-forward ldap/servers/slapd/pw.c | 57 +++++++++++++++++++++++++++++++--------------- 1 files changed, 38 insertions(+), 19 deletions(-) $ git push Counting objects: 11, done. Delta compression using up to 2 threads. Compressing objects: 100% (6/6), done. Writing objects: 100% (6/6), 1.54 KiB, done. Total 6 (delta 4), reused 0 (delta 0) To ssh://git.fedorahosted.org/git/389/ds.git ad544f2..f977972 master -> master
Hi Noriko, Thanks for the steps you have added. My results are not matching the expected results, Please advice. Steps to verify $ldapadd -x -h localhost -p 389 -D "cn=Directory Manager" -w Secret << EOF dn: uid=ams,dc=example,dc=com cn: ams sn: ams givenname: ams objectclass: top objectclass: person objectclass: organizationalPerson objectclass: inetOrgPerson uid: ams mail: ams userpassword: amsamsams EOF Enable fine-grained password policy, and click "fine-grained subtree policy enabled", "User must change password after reset", "User may change password" and set "Allow changes in N day(s)". Any digit is fine. Click Password expires after N days. Any ditit is fine. Done from Console - check the attachment added.Screenshot-Subtree Password Policy.png Sample entry 1 (passwordExpirationTime has already passed): ldapmodify -a -h localhost -p 389 -D "cn=Directory Manager" -w Secret123 << EOF dn: cn=ams,dc=example,dc=com objectClass: top objectClass: person sn: ams cn: ams userPassword: amsamsams passwordExpirationTime: 20120326005407Z EOF This entry should be successfully added. adding new entry "cn=ams,dc=example,dc=com" Search should return both passwordExpirationTime and passwordallowchangetime. Note: passwordExpirationTime should be the same value added originally. $ ldapsearch -h localhost -p 389 -D "cn=Directory Manager" -w Secret123 -b "cn=ams,dc=example,dc=com" "(cn=*)" passwordExpirationTime passwordallowchangetime # ams, example.com dn: cn=ams,dc=example,dc=com passwordExpirationTime: 20120326005407Z << Not returning value for passwordallowchangetime>> Sample entry 2 (passwordExpirationTime has already passed): ldapmodify -a -h localhost -p 389 -D "cn=Directory Manager" -w Secret123 << EOF dn: cn=ams,dc=example,dc=com objectClass: top objectClass: person sn: ams cn: ams userPassword: amsamsams passwordExpirationTime: 20000326005407Z EOF This entry should be successfully added. << adding new entry "cn=ams,dc=example,dc=com" ldap_add: Already exists (68) >> Search should return just passwordExpirationTime. Note: passwordExpirationTime should be the same value added originally. $ ldapsearch -h localhost -p 389 -D "cn=Directory Manager" -w Secret123 -b "cn=ams,dc=example,dc=com" "(cn=*)" passwordExpirationTime passwordallowchangetime dn: cn=ams,dc=example,dc=com passwordExpirationTime: 20120326005407Z Sample entry 3 (Entry includes both passwordExpirationTime and passwordallowchangetime): ldapmodify -a -h localhost -p 389 -D "cn=Directory Manager" -w Secret123 << EOF dn: cn=ams,dc=example,dc=com objectClass: top objectClass: person sn: ams cn: ams userPassword: amsamsams passwordExpirationTime: 20120326005407Z passwordallowchangetime: 20110326005407Z EOF This entry should be successfully added. << adding new entry "cn=ams,dc=example,dc=com" ldap_add: Already exists (68) >> Search should return both passwordExpirationTime and passwordallowchangetime. Note: both values should be the same as the ones added originally. $ ldapsearch -h localhost -p 389 -D "cn=Directory Manager" -w Secret123 -b "cn=ams,dc=example,dc=com" "(cn=*)" passwordExpirationTime passwordallowchangetime # ams, example.com dn: cn=ams,dc=example,dc=com passwordExpirationTime: 20120326005407Z << Single value returned>>>
Created attachment 498520 [details] Password Policy
Hi Amita, Let me make sure one thing. When you set up the fine-grained password, did you do this first? Choose Configuration tab on the DS Console Click Data on the left pane, then choose Passwords tab Click "Enable fine-grained password policy" This is what I meant by "Enable fine-grained password policy" in the steps. You can double-check it by searching "nsslapd-pwpolicy-local" in the cn=config entry in your config file (/etc/dirsrv/slapd-ID/dse.ldif). BTW, I have to fix this line Sample entry 1 (passwordExpirationTime has already passed): to Sample entry 1 (passwordExpirationTime has not passed yet): (Sorry, copy&paste bug. :p) Your sample 2 and 3 tests are failing since you are trying to add the same entry which already exists in the DB. I suppose that's not a problem you are trying to report...? To solve it, you could use other users than cn=ams, as I did in my steps. (see user0,1,2) Or you could modify the password-time values by ldapmodify.
Thanks Noriko, VERIFIED Successfully :) Sample entry 1 (passwordExpirationTime has not passed yet): ldapmodify -a -h localhost -p 389 -D "cn=Directory Manager" -w Secret123 << EOF dn: cn=ams33,dc=example,dc=com objectClass: top objectClass: person sn: ams cn: ams userPassword: amsamsams passwordExpirationTime: 20120326005407Z EOF This entry should be successfully added. Search should return both passwordExpirationTime and passwordallowchangetime. Note: passwordExpirationTime should be the same value added originally. $ ldapsearch -h localhost -p 389 -D "cn=Directory Manager" -w Secret123 -b "cn=ams33,dc=example,dc=com" "(cn=*)" passwordExpirationTime passwordallowchangetime # ams33, example.com dn: cn=ams33,dc=example,dc=com passwordExpirationTime: 20120326005407Z passwordallowchangetime: 20110518062925Z Sample entry 2 (passwordExpirationTime has already passed): ldapmodify -a -h localhost -p 389 -D "cn=Directory Manager" -w Secret123 << EOF dn: cn=ams44,dc=example,dc=com objectClass: top objectClass: person sn: ams cn: ams userPassword: amsamsams passwordExpirationTime: 20000326005407Z EOF This entry should be successfully added. Search should return just passwordExpirationTime. Note: passwordExpirationTime should be the same value added originally. $ ldapsearch -h localhost -p 389 -D "cn=Directory Manager" -w Secret123 -b "cn=ams44,dc=example,dc=com" "(cn=*)" passwordExpirationTime passwordallowchangetime # ams44, example.com dn: cn=ams44,dc=example,dc=com passwordExpirationTime: 20000326005407Z Sample entry 3 (Entry includes both passwordExpirationTime and passwordallowchangetime): ldapmodify -a -h localhost -p 389 -D "cn=Directory Manager" -w Secret123 << EOF dn: cn=ams66,dc=example,dc=com objectClass: top objectClass: person sn: ams cn: ams userPassword: amsamsams passwordExpirationTime: 20120326005407Z passwordallowchangetime: 20110326005407Z EOF This entry should be successfully added. Search should return both passwordExpirationTime and passwordallowchangetime. Note: both values should be the same as the ones added originally. $ ldapsearch -h localhost -p 389 -D "cn=Directory Manager" -w Secret123 -b "cn=ams66,dc=example,dc=com" "(cn=*)" passwordExpirationTime passwordallowchangetime # ams66, example.com dn: cn=ams66,dc=example,dc=com passwordExpirationTime: 20120326005407Z passwordallowchangetime: 20110326005407Z
Cool! Thanks, Amita!