Bug 489379

Summary: passwordExpirationTime in entry being added collides with passwordMustChange policy
Product: Red Hat Directory Server Reporter: Ulf Weltman <ulf.weltman>
Component: Security - Password PolicyAssignee: Rich Megginson <rmeggins>
Status: CLOSED CURRENTRELEASE QA Contact: Viktor Ashirov <vashirov>
Severity: medium Docs Contact:
Priority: high    
Version: 8.0CC: amsharma, jgalipea, nhosoi, nkinder
Target Milestone: ---   
Target Release: ---   
Hardware: All   
OS: All   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2016-05-06 14:33:44 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On:    
Bug Blocks: 576869, 639035    
Attachments:
Description Flags
patch proposal
rmeggins: review+, nhosoi: review+
Password Policy none

Description Ulf Weltman 2009-03-09 19:13:58 UTC
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.

Comment 1 Ulf Weltman 2010-09-29 21:13:07 UTC
Created attachment 450591 [details]
patch proposal

Comment 3 Noriko Hosoi 2010-12-16 02:14:05 UTC
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

Comment 4 Noriko Hosoi 2010-12-16 02:22:11 UTC
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

Comment 5 Amita Sharma 2011-05-12 12:05:23 UTC
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>>>

Comment 6 Amita Sharma 2011-05-12 12:06:06 UTC
Created attachment 498520 [details]
Password Policy

Comment 7 Noriko Hosoi 2011-05-12 17:28:19 UTC
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.

Comment 8 Amita Sharma 2011-05-13 06:35:45 UTC
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

Comment 9 Noriko Hosoi 2011-05-13 15:49:11 UTC
Cool!  Thanks, Amita!