@@ -84,7 +84,7 @@ public function __construct(IUserManager $userManager, IUserSession $userSession
84
84
* @return int bitwise-or'ed actions
85
85
*/
86
86
public function respondToActions () {
87
- $ setPassword = function_exists ( ' ldap_exop_passwd ' ) && !$ this ->ldapConnect ->hasPasswordPolicy ()
87
+ $ setPassword = $ this -> canSetPassword ( ) && !$ this ->ldapConnect ->hasPasswordPolicy ()
88
88
? Backend::SET_PASSWORD
89
89
: 0 ;
90
90
@@ -140,7 +140,7 @@ public function setDisplayName($uid, $displayName) {
140
140
* checks whether the user is allowed to change his avatar in Nextcloud
141
141
*
142
142
* @param string $uid the Nextcloud user name
143
- * @return boolean either the user can or cannot
143
+ * @return bool either the user can or cannot
144
144
*/
145
145
public function canChangeAvatar ($ uid ) {
146
146
return $ this ->configuration ->hasAvatarPermission ();
@@ -222,7 +222,12 @@ public function createUser($uid, $password) {
222
222
$ displayNameAttribute = $ this ->ldapConnect ->getDisplayNameAttribute ();
223
223
}
224
224
225
+ if ($ connection === false ) {
226
+ throw new \Exception ('Could not bind to LDAP server ' );
227
+ }
228
+
225
229
[$ newUserDN , $ newUserEntry ] = $ this ->buildNewEntry ($ uid , $ password , $ base );
230
+
226
231
$ newUserDN = $ this ->ldapProvider ->sanitizeDN ([$ newUserDN ])[0 ];
227
232
$ this ->ensureAttribute ($ newUserEntry , $ displayNameAttribute , $ uid );
228
233
@@ -244,27 +249,8 @@ public function createUser($uid, $password) {
244
249
throw new \Exception ('Cannot create user: ' . ldap_error ($ connection ), ldap_errno ($ connection ));
245
250
}
246
251
247
- // Set password through ldap password exop, if supported
248
252
if ($ this ->respondToActions () & Backend::SET_PASSWORD ) {
249
- try {
250
- $ ret = ldap_exop_passwd ($ connection , $ newUserDN , '' , $ password );
251
- if ($ ret === false ) {
252
- $ message = 'ldap_exop_passwd failed, falling back to ldap_mod_replace to to set password for new user ' ;
253
- $ this ->logger ->debug ($ message , ['app ' => Application::APP_ID ]);
254
-
255
- // Fallback to `userPassword` in case the server does not support exop_passwd
256
- $ ret = ldap_mod_replace ($ connection , $ newUserDN , ['userPassword ' => $ password ]);
257
- if ($ ret === false ) {
258
- $ message = 'Failed to set password for new user {dn} ' ;
259
- $ this ->logger ->error ($ message , [
260
- 'app ' => Application::APP_ID ,
261
- 'dn ' => $ newUserDN ,
262
- ]);
263
- }
264
- }
265
- } catch (\Exception $ e ) {
266
- $ this ->logger ->error ($ e ->getMessage (), ['exception ' => $ e , 'app ' => Application::APP_ID ]);
267
- }
253
+ $ this ->handleSetPassword ($ newUserDN , $ password , $ connection );
268
254
}
269
255
return $ ret ? $ newUserDN : false ;
270
256
}
@@ -350,6 +336,15 @@ public function deleteUser($uid): bool {
350
336
return $ res ;
351
337
}
352
338
339
+ /**
340
+ * checks whether the user is allowed to change their password in Nextcloud
341
+ *
342
+ * @return bool either the user can or cannot
343
+ */
344
+ public function canSetPassword (): bool {
345
+ return $ this ->configuration ->hasPasswordPermission ();
346
+ }
347
+
353
348
/**
354
349
* Set password
355
350
*
@@ -360,27 +355,17 @@ public function deleteUser($uid): bool {
360
355
* Change the password of a user
361
356
*/
362
357
public function setPassword ($ uid , $ password ) {
363
- if (!function_exists ('ldap_exop_passwd ' )) {
364
- // since PHP 7.2 – respondToActions checked this already, this
365
- // method should not be called. Double check due to public scope.
366
- // This method can be removed when Nextcloud 16 compat is dropped.
367
- return false ;
368
- }
369
- try {
370
- $ cr = $ this ->ldapProvider ->getLDAPConnection ($ uid );
371
- $ userDN = $ this ->getUserDN ($ uid );
372
- return ldap_exop_passwd ($ cr , $ userDN , '' , $ password ) !== false ;
373
- } catch (\Exception $ e ) {
374
- $ this ->logger ->error ($ e ->getMessage (), ['exception ' => $ e , 'app ' => Application::APP_ID ]);
375
- }
376
- return false ;
358
+ $ connection = $ this ->ldapProvider ->getLDAPConnection ($ uid );
359
+ $ userDN = $ this ->getUserDN ($ uid );
360
+
361
+ return $ this ->handleSetPassword ($ userDN , $ password , $ connection );
377
362
}
378
363
379
364
/**
380
365
* get the user's home directory
381
366
*
382
367
* @param string $uid the username
383
- * @return boolean
368
+ * @return bool
384
369
*/
385
370
public function getHome ($ uid ) {
386
371
// Not implemented
@@ -444,4 +429,62 @@ public function changeUserHook(IUser $user, string $feature, $attr1, $attr2): vo
444
429
private function getUserDN ($ uid ): string {
445
430
return $ this ->ldapProvider ->getUserDN ($ uid );
446
431
}
432
+
433
+ /**
434
+ * Handle setting user password password
435
+ *
436
+ * @param string $userDN The username
437
+ * @param string $password The new password
438
+ * @param \LDAP\Connection $connection The LDAP connection to use
439
+ * @return bool
440
+ *
441
+ * Change the password of a user
442
+ */
443
+ private function handleSetPassword (string $ userDN , string $ password , \LDAP \Connection $ connection ): bool {
444
+ try {
445
+ $ ret = false ;
446
+
447
+ // try ldap_exop_passwd first
448
+ if ($ this ->ldapConnect ->hasPasswdExopSupport ($ connection )) {
449
+ if (ldap_exop_passwd ($ connection , $ userDN , '' , $ password ) === true ) {
450
+ // `ldap_exop_passwd` is either FALSE or the password, in the later case return TRUE
451
+ return true ;
452
+ }
453
+
454
+ $ message = 'Failed to set password for user {dn} using ldap_exop_passwd ' ;
455
+ $ this ->logger ->error ($ message , [
456
+ 'ldap_error ' => ldap_error ($ connection ),
457
+ 'app ' => Application::APP_ID ,
458
+ 'dn ' => $ userDN ,
459
+ ]);
460
+ } else {
461
+ // Use ldap_mod_replace in case the server does not support exop_passwd
462
+ $ entry = [];
463
+ if ($ this ->configuration ->useUnicodePassword ()) {
464
+ $ entry ['unicodePwd ' ] = iconv ('UTF-8 ' , 'UTF-16LE ' , '" ' . $ password . '" ' );
465
+ } else {
466
+ $ entry ['userPassword ' ] = $ password ;
467
+ }
468
+
469
+ if (ldap_mod_replace ($ connection , $ userDN , $ entry )) {
470
+ return true ;
471
+ }
472
+
473
+ $ message = 'Failed to set password for user {dn} using ldap_mod_replace ' ;
474
+ $ this ->logger ->error ($ message , [
475
+ 'ldap_error ' => ldap_error ($ connection ),
476
+ 'app ' => Application::APP_ID ,
477
+ 'dn ' => $ userDN ,
478
+ ]);
479
+ }
480
+ return false ;
481
+ } catch (\Exception $ e ) {
482
+ $ this ->logger ->error ('Exception occured while setting the password of user {dn} ' , [
483
+ 'app ' => Application::APP_ID ,
484
+ 'exception ' => $ e ,
485
+ 'dn ' => $ userDN ,
486
+ ]);
487
+ return false ;
488
+ }
489
+ }
447
490
}
0 commit comments