Bug 57681 - Day of password expiry, a passwordchange is prompted but not followed through with sso login
Summary: Day of password expiry, a passwordchange is prompted but not followed through...
Status: CLOSED FIXED
Alias: None
Product: UCS
Classification: Unclassified
Component: UMC - Users
Version: UCS 5.0
Hardware: Other Linux
: P5 normal
Target Milestone: UCS 5.0-10-errata
Assignee: Arvid Requate
QA Contact: Marius Meschter
URL: https://git.knut.univention.de/univen...
Keywords:
Depends on:
Blocks: 58048
  Show dependency treegraph
 
Reported: 2024-10-21 11:54 CEST by Christina Scheinig
Modified: 2025-06-05 09:24 CEST (History)
5 users (show)

See Also:
What kind of report is it?: Bug Report
What type of bug is this?: 5: Major Usability: Impairs usability in key scenarios
Who will be affected by this bug?: 1: Will affect a very few installed domains
How will those affected feel about the bug?: 5: Blocking further progress on the daily work
User Pain: 0.143
Enterprise Customer affected?:
School Customer affected?: Yes
ISV affected?:
Waiting Support:
Flags outvoted (downgraded) after PO Review:
Ticket number: 2024101621000304
Bug group (optional):
Customer ID:
Max CVSS v3 score:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Christina Scheinig univentionstaff 2024-10-21 11:54:08 CEST
The customer reported, and I can reproduce it, that the password cannot be changed from a teacher (user) after the password is expired by a policy and the user logs in via saml.

How to reproduce:
root@primary:~# univention-app info
UCS: 5.0-9 errata1125
Installed: samba4=4.16 self-service=5.0 self-service-backend=5.0

or

root@ucs-single:~# univention-app info
UCS: 5.0-9 errata1125
Installed: self-service=5.0 self-service-backend=5.0
Upgradable: 

use a password policy, to set the password expiry date:
DN: cn=pw-teacher,cn=policies,dc=lilly,dc=cat
  expiryInterval: 3
  ldapFilter: None
  length: 1
  name: pw-teacher
  pwLength: 10
  pwQualityCheck: TRUE


Adjust this policy on the user.

When the day comes, the user is prompted to change his password. He logs in via saml/sso (no keycloak) and sets the new password. Positive feedback " Your password is changed, please login"
Using the new Password shows: "Nutzername oder Passwort falsch.
Entweder es konnte kein Nutzer mit dem angegebenen Nutzernamen gefunden werden oder das Passwort ist falsch. Überprüfen Sie die Zugangsdaten und probieren Sie es nochmal"
-----------------
"Username or password incorrect.
Either no user with the specified user name could be found or the password is incorrect. Check the access data and try again”

So this is a loop now, using the old password, the user is still prompted to set a new password.
Next day, everything works fine.


So swpool is a user, where the checkbox, "has to change his password on next login" is set manually.
---------------
root@primary:~# univention-ldapsearch -LLL uid=swpool shadowMax shadowLastChange sambaPwdLastSet krb5PasswordEnd
dn: uid=swpool,cn=users,dc=lilly,dc=cat
shadowMax: 1
shadowLastChange: 20015
sambaPwdLastSet: 0
krb5PasswordEnd: 20241021000000Z

lillycat is a user, with the password policy
root@primary:~# univention-ldapsearch -LLL uid=lillycat shadowMax shadowLastChange sambaPwdLastSet krb5PasswordEnd
dn: uid=lillycat,cn=users,dc=lilly,dc=cat
shadowMax: 3
shadowLastChange: 20014
sambaPwdLastSet: 1729243804
krb5PasswordEnd: 20241021000000Z
----------------
udm shows different:
DN: uid=swpool,cn=users,dc=lilly,dc=cat
passwordexpiry: 2024-10-20

DN: uid=lillycat,cn=users,dc=lilly,dc=cat
passwordexpiry: 2024-10-21


If we do not use sso, the password is not marked as expired and works fine.

For analysis I have a test environment (10.200.43.140)
Comment 1 Julia Bremer univentionstaff 2024-10-21 20:05:13 CEST
The reason is, that at the day of expiry, 
both shadowLastChange + shadowMax
and krb5PasswordEnd point to the same day.

shadowLastChange + shadowMax on that user equate to '2024-10-21'
And krb5PasswordEnd is 20241021000000Z.

This should mean that they are consistent, right? Suprise, they are not.
Kerberos regards krb5PasswordEnd as the first day where the password is expired.
While Unix (with the shadow attributes) regards the day of expiry as the last day the password is valid. 


This leads to this very strange behaviour on the day where the password expires. 
SimpleSAMLphp checks in its php code if the password is expired.
It checks the Kerberos attributes and the Unix attributes. When any of them regard the password as being expired, it prepares for a password change and the password change page is rendered.
After the user puts in username and password, the UMCs set-password endpoint is called. 
The UMC goes through the PAM stack. And the PAM stack uses pam_unix first.
For pam_unix, the user is dandy, not expired, auth successful, no passwordchange to do. Returns success. 

Then the user gets a "password change successful" message and is happy and can login. 

Every time they log in again on that day, they'll get that password change prompt and they'll only be able to log in with the old password and not with the new one (because no passwordchange has actually happened).

From reading the code, this looks like the same problem could be in Keycloak. 

I don't know how to solve this best.
Maybe we could set shadowMax to be one day less than the Administrator configured in their passwordpolicy.
Comment 2 Julia Bremer univentionstaff 2024-11-19 13:17:35 CET
From looking at the code this is also relevant for Keycloak.
Comment 3 Jan-Luca Kiok univentionstaff 2024-11-21 17:39:12 CET
A great example for the ambiguous meaning of "expiry date": Is it the day that the password expires (meaning that if 21.11. is configured you cannot login anymore beginning with 21.11. 00:00 h) or is it the last day until the password expires (like a "best before" date: You have _until the 21.11. to change the password, afterwards on the 22.11. 00:00 h, it will be expired).

We are aiming for a uniform, consistent handling in our products in alignment with connected services if possible, so we should go for the former: If it says "21.11." then you cannot login on the 21.11. 00:00.
Comment 5 Arvid Requate univentionstaff 2025-03-03 19:21:21 CET
e94b377c00d | Issue univention/ucs#2552: shadowMax := pwhistoryPolicy.expiryInterval - 1
0f8bb9696c0 | Issue univention/ucs#2552 changelogs and advisories

Package: univention-directory-manager-modules
Version: 15.0.28-9
Branch: 5.0-0
Scope: errata5.0-9

Package: univention-s4-connector
Version: 14.0.19-2
Branch: 5.0-0
Scope: errata5.0-9
Comment 6 Arvid Requate univentionstaff 2025-03-03 22:07:34 CET
0c139780155 | Issue univention/ucs#2552: AD-Connector too

Package: univention-ad-connector
Version: 14.0.20-4
Branch: 5.0-0
Scope: errata5.0-9
Comment 7 Arvid Requate univentionstaff 2025-03-04 19:42:51 CET
cf02335b4 | Adjust shadowbind overlay to treat shadowMax == 0 like pam_unix does

Package: openldap
Version: 2.4.47+dfsg-3+deb10u7A~5.0.0.202503041938
Branch: 5.0-0
Scope: errata5.0-9
Comment 8 Arvid Requate univentionstaff 2025-03-04 20:15:53 CET
d46080ed935 | Handle case pwhistoryPolicy.expiryInterval == 0 (or undefined)
bb1cd434b11 | adjust tests to work with shadowMax = expiryInterval - 1

Package: univention-directory-manager-modules
Version: 15.0.28-10
Branch: 5.0-0
Scope: errata5.0-9

Package: univention-ad-connector
Version: 14.0.20-5
Branch: 5.0-0
Scope: errata5.0-9

Package: ucs-test
Version: 12.0.23-41
Branch: 5.0-0
Scope: errata5.0-9
Comment 9 Arvid Requate univentionstaff 2025-03-05 10:48:03 CET
"b50-scope errata5.0-9" gets the version wrong (should be ~5.0-9...),
so I've rebuilt the package and directly specified the version:

Package: openldap
Version: 2.4.47+dfsg-3+deb10u7A~5.0.9.202503051037
Branch: 5.0-0
Scope: errata5.0-9
Comment 10 Arvid Requate univentionstaff 2025-03-07 18:09:51 CET
As the process for the patch level release 5.0-10 is already in it's final stages
we decided not to interfere and release this via errata5.0-10.

a05327945dc | shadowMax := pwhistoryPolicy.expiryInterval - 1
b1148fe5df6 | changelogs and advisories
0f471b96d46 | Handle case pwhistoryPolicy.expiryInterval == 0 (or undefined)

Package: univention-directory-manager-modules
Version: 15.0.29-1
Branch: 5.0-0
Scope: errata5.0-10

Package: univention-s4-connector
Version: 14.0.20-1
Branch: 5.0-0
Scope: errata5.0-10

ab2a0db34b8 | AD-Connector too
7da8a92a0a7 | changelogs and advisories (fixup)

Package: univention-ad-connector
Version: 14.0.21-1
Branch: 5.0-0
Scope: errata5.0-10

d5632c3fcc2 | reduce flakiness of playwright password change test

Package: ucs-test
Version: 10.0.24-5
Branch: 5.0-0
Scope: errata5.0-10

repo_admin.py --cherrypick --release 5.0-0 --source errata5.0-9 --releasedest 5.0-0 --dest errata5.0-10 --package openldap
75cde93ca | patch merged by repo-ng
build-package-architecture-ng -r 5.0-0-0 -s errata5.0-10 --version "2.4.47+dfsg-3+deb10u7A~5.0.10.202503071652" -p openldap

Package: openldap
Version: 2.4.47+dfsg-3+deb10u7A~5.0.10.202503071652
Branch: 5.0-0
Scope: errata5.0-10

e8d07f728ac | Advisory update for errata5.0-10
Comment 11 Marius Meschter univentionstaff 2025-03-11 09:01:30 CET
OK: YAML
OK: Changelog
OK: Password change on the day of password expiry works both with Keycloak and simpleSAMLphp
OK: Tests
OK: User has to change password on next login
OK: change password in Windows correctly syncs PW expiry to UCS (S4C)
OK: change password in Windows correctly syncs PW expiry to UCS (ADC)
OK: Password change prompt on day of expiry aligns with Windows
Comment 12 Arvid Requate univentionstaff 2025-03-12 13:13:37 CET
a61c0574cab | fix 55_adconnector/503test_password_change_next_logon

Package: ucs-test              
Version: 10.0.24-7               
Branch: 5.0-0                 
Scope: errata5.0-10