From 4f367e6bf11c3d72f5567e73eed1700185c3f61b Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Mon, 16 Sep 2019 10:06:57 +0200 Subject: [PATCH] * Univention: fix "Must change password upon next login" feature --- api/src/Accounts/Ldap.php | 5 ++++- api/src/Accounts/Univention.php | 8 -------- api/src/Accounts/Univention/Udm.php | 15 ++++++++++++++- api/src/Auth/Ldap.php | 12 ++++++++++-- 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/api/src/Accounts/Ldap.php b/api/src/Accounts/Ldap.php index 49bb0eff2d..5845de725f 100644 --- a/api/src/Accounts/Ldap.php +++ b/api/src/Accounts/Ldap.php @@ -620,7 +620,10 @@ class Ldap } //error_log(__METHOD__.__LINE__.$data['account_lid'].'#'.$data['account_lastpwd_change'].'#'); if ($data['account_lastpwd_change']) $to_write['shadowlastchange'] = round(($data['account_lastpwd_change']-$utc_diff)/(24*3600)); - if (isset($data['account_lastpwd_change']) && $data['account_lastpwd_change']==0) $to_write['shadowlastchange'] = 0; + if ($data['mustchangepassword'] == 1 || isset($data['account_lastpwd_change']) && $data['account_lastpwd_change'] == 0) + { + $to_write['shadowlastchange'] = 0; + } // lastlogin and lastlogin from are not availible via the shadowAccount object class // $to_write['phpgwaccountlastlogin'] = $data['lastlogin']; // $to_write['phpgwaccountlastloginfrom'] = $data['lastloginfrom']; diff --git a/api/src/Accounts/Univention.php b/api/src/Accounts/Univention.php index 7140688bd6..8de389bf8f 100644 --- a/api/src/Accounts/Univention.php +++ b/api/src/Accounts/Univention.php @@ -191,14 +191,6 @@ class Univention extends Ldap $data = [ 'account_passwd' => $new_passwd ]; - if ($old_passwd) - { - $data['pwdChangeNextLogin'] = false; - } - if ($update_lastchange) - { - // ToDo: $entry['shadowlastchange'] = round((time()-date('Z')) / (24*3600)); - } $udm->updateUser($dn, $data); diff --git a/api/src/Accounts/Univention/Udm.php b/api/src/Accounts/Univention/Udm.php index b11f82a993..5e735423fb 100644 --- a/api/src/Accounts/Univention/Udm.php +++ b/api/src/Accounts/Univention/Udm.php @@ -236,7 +236,16 @@ class Udm $payload = $this->user2udm($data, $this->call('users/user/'.urlencode($dn), 'GET', [], $get_headers)); $headers = []; - return $this->call('users/user/'.urlencode($dn), 'PUT', $payload, $headers, $get_headers['etag'], true); + $ret = $this->call('users/user/'.urlencode($dn), 'PUT', $payload, $headers, $get_headers['etag'], true); + + // you can not set the password and force a password change for next login in the same call + // the forced password change will be lost --> call again without password to force the change on next login + if (!empty($data['account_passwd']) && !empty($data['mustchangepassword'])) + { + unset($data['account_passwd']); + $ret = $this->updateUser($ret, $data); + } + return $ret; } /** @@ -248,6 +257,9 @@ class Udm */ protected function user2udm(array $data, array $payload) { + // gives error: The property passwordexpiry has an invalid value: Value may not change. + unset($payload['properties']['passwordexpiry']); + foreach([ 'account_lid' => 'username', 'account_passwd' => 'password', @@ -255,6 +267,7 @@ class Udm 'account_firstname' => 'firstname', 'account_id' => ['uidNumber', 'sambaRID'], 'account_email' => 'mailPrimaryAddress', + 'mustchangepassword' => 'pwdChangeNextLogin', ] as $egw => $names) { if (!empty($data[$egw])) diff --git a/api/src/Auth/Ldap.php b/api/src/Auth/Ldap.php index d06de33f03..ec72577aea 100644 --- a/api/src/Auth/Ldap.php +++ b/api/src/Auth/Ldap.php @@ -163,7 +163,7 @@ class Ldap implements Backend * fetch the last pwd change for the user * * @param string $_username username of account to authenticate - * @return mixed false or shadowlastchange*24*3600 + * @return mixed false or shadowlastchange*24*3600 or 0, if user must change his password */ function getLastPwdChange($_username) { @@ -180,7 +180,7 @@ class Ldap implements Backend return false; } /* find the dn for this uid, the uid is not always in the dn */ - $attributes = array('uid','dn','shadowexpire','shadowlastchange'); + $attributes = array('uid','dn','shadowexpire','shadowlastchange','sambaPwdLastSet','krb5PasswordEnd'); $filter = str_replace(array('%user','%domain'),array(Api\Ldap::quote($username),$GLOBALS['egw_info']['user']['domain']), $GLOBALS['egw_info']['server']['ldap_search_filter'] ? $GLOBALS['egw_info']['server']['ldap_search_filter'] : '(uid=%user)'); @@ -194,6 +194,14 @@ class Ldap implements Backend if ($allValues['count'] > 0) { + // there are several schema-specific ways to express the user must change the password + if (isset($allValues[0]['shadowlastchange']) && (string)$allValues[0]['shadowlastchange'][0] === '0' || + isset($allValues[0]['sambapwdlastset']) && (string)$allValues[0]['sambapwdlastset'][0] === '0' || + isset($allValues[0]['krb5passwordend']) && Api\DateTime::user2server($allValues[0]['krb5passwordend'][0]) < time()) + { + error_log(__METHOD__."('$_username') shadowlastchange={$allValues[0]['shadowlastchange']}, sambapwdlastset={$allValues[0]['sambapwdlastset'][0]}, krb5passwordend={$allValues[0]['krb5passwordend'][0]} --> return 0"); + return 0; + } if (!isset($allValues[0]['shadowlastchange'])) { if ($this->debug) error_log(__METHOD__."('$username') no shadowlastchange attribute!");