Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\LdapWriteSupport\AppInfo;

use OCA\LdapWriteSupport\Listener\GroupBackendRegisteredListener;
Expand Down
36 changes: 15 additions & 21 deletions lib/Command/GroupAdminsToLdap.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2019 Cooperativa EITA <eita.org.br>
Expand All @@ -22,37 +24,23 @@ class GroupAdminsToLdap extends Command {
/**
* This adds/removes group subadmins as ldap group owners
*/
private $simulate = false;
private $verbose = false;

/** @var SubAdmin */
private $subAdmin;
/** @var IConfig */
private $ocConfig;
/** @var Helper */
private $helper;
/** @var Group_Proxy */
private $groupProxy;
private bool $simulate = false;
private bool $verbose = false;

/**
* GroupAdminsToLdap constructor.
*/
public function __construct(
SubAdmin $subAdmin,
IConfig $ocConfig,
Helper $helper,
Group_Proxy $groupProxy,
private SubAdmin $subAdmin,
private IConfig $ocConfig,
private Helper $helper,
private Group_Proxy $groupProxy,
) {
parent::__construct();

$this->subAdmin = $subAdmin;
$this->ocConfig = $ocConfig;
$this->helper = $helper;
$this->groupProxy = $groupProxy;
}

#[\Override]
protected function configure() {
protected function configure(): void {
$this
->setName('ldap-ext:sync-group-admins')
->setDescription('syncs group admin informations to ldap')
Expand Down Expand Up @@ -147,6 +135,9 @@ function diff_user_arrays($array1, $array2) {

foreach ($onlyInNC as $gid => $users) {
$groupDN = $access->getGroupMapper()->getDNByName($gid);
if ($groupDN === false) {
throw new Exception('Failed to find group '.$gid);
}
foreach ($users as $uid) {
$userDN = $access->getUserMapper()->getDNByName($uid);
$entry = [
Expand All @@ -163,6 +154,9 @@ function diff_user_arrays($array1, $array2) {

foreach ($onlyInLDAP as $gid => $users) {
$groupDN = $access->getGroupMapper()->getDNByName($gid);
if ($groupDN === false) {
throw new Exception('Failed to find group '.$gid);
}
foreach ($users as $uid) {
$userDN = $access->getUserMapper()->getDNByName($uid);
$entry = [
Expand Down
26 changes: 12 additions & 14 deletions lib/LDAPConnect.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2017 Cooperativa EITA <eita.org.br>
Expand All @@ -16,26 +18,23 @@
use Psr\Log\LoggerInterface;

class LDAPConnect {
/** @var Configuration */
private $ldapConfig;
/** @var bool|null */
private $passwdSupport;
private Configuration $ldapConfig;
private ?bool $passwdSupport;

public function __construct(
Helper $ldapBackendHelper,
private LoggerInterface $logger,
) {
$this->passwdSupport = null;
$ldapConfigPrefixes = $ldapBackendHelper->getServerConfigurationPrefixes(true);
$prefix = array_shift($ldapConfigPrefixes);
$prefix = array_shift($ldapConfigPrefixes) ?? '';
$this->ldapConfig = new Configuration($prefix);
}

/**
* @return resource|Connection
* @throws ServerNotAvailableException
*/
public function connect() {
public function connect(): Connection {
$ldapHost = $this->ldapConfig->ldapHost;
$ldapPort = $this->ldapConfig->ldapPort;

Expand All @@ -51,7 +50,7 @@ public function connect() {

// Connecting to LDAP - TODO: connect directly via LDAP plugin
$cr = ldap_connect($ldapHost);
if (!is_resource($cr) && !is_object($cr)) {
if (!is_object($cr)) {
$this->logger->error('Unable to connect to LDAP host {ldapHost}:{ldapPort}',
[
'app' => Application::APP_ID,
Expand All @@ -72,10 +71,9 @@ public function connect() {
}

/**
* @return false|resource|Connection
* @throws ServerNotAvailableException
*/
public function bind() {
public function bind(): Connection|false {
$ds = $this->connect();
$dn = $this->ldapConfig->ldapAgentName;
$secret = $this->ldapConfig->ldapAgentPassword;
Expand All @@ -95,10 +93,9 @@ public function bind() {
}

/**
* @return false|resource|Connection
* @throws ServerNotAvailableException
*/
public function getLDAPConnection() {
public function getLDAPConnection(): Connection|false {
return $this->bind();
}

Expand Down Expand Up @@ -142,11 +139,12 @@ public function hasPasswordPolicy(): bool {
* checks whether the LDAP server supports the passwd exop
*
* @param Connection $connection LDAP connection to check
* @return boolean either the user can or cannot
* @return bool either the user can or cannot
*/
public function hasPasswdExopSupport($connection): bool {
public function hasPasswdExopSupport(Connection $connection): bool {
// TODO: We should cache this by ldap prefix, but currently we have no access to it.
if (is_null($this->passwdSupport)) {
/** @var \LDAP\Result|false */
$ret = ldap_read($connection, '', '(objectclass=*)', ['supportedExtension']);
if ($ret === false) {
$this->passwdSupport = false;
Expand Down
2 changes: 2 additions & 0 deletions lib/LDAPGroupManager.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2017-2019 Cooperativa EITA <eita.org.br>
Expand Down Expand Up @@ -77,7 +79,7 @@
$connection = $this->ldapProvider->getGroupLDAPConnection($gid);
$groupDN = $this->ldapProvider->getGroupDN($gid);

if (!$ret = ldap_delete($connection, $groupDN)) {

Check failure on line 82 in lib/LDAPGroupManager.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

PossiblyInvalidArgument

lib/LDAPGroupManager.php:82:27: PossiblyInvalidArgument: Argument 1 of ldap_delete expects LDAP\Connection, but possibly different type LDAP\Connection|resource provided (see https://psalm.dev/092)
$this->logger->error('Unable to delete LDAP Group: ' . $gid);
} else {
$this->logger->notice('Delete LDAP Group: ' . $gid);
Expand Down Expand Up @@ -116,7 +118,7 @@
break;
}

if (!$ret = ldap_mod_add($connection, $groupDN, $entry)) {

Check failure on line 121 in lib/LDAPGroupManager.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

PossiblyInvalidArgument

lib/LDAPGroupManager.php:121:28: PossiblyInvalidArgument: Argument 1 of ldap_mod_add expects LDAP\Connection, but possibly different type LDAP\Connection|resource provided (see https://psalm.dev/092)
$this->logger->error('Unable to add user ' . $uid . ' to group ' . $gid);
} else {
$this->logger->notice('Add user: ' . $uid . ' to group: ' . $gid);
Expand Down Expand Up @@ -155,7 +157,7 @@
break;
}

if (!$ret = ldap_mod_del($connection, $groupDN, $entry)) {

Check failure on line 160 in lib/LDAPGroupManager.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

PossiblyInvalidArgument

lib/LDAPGroupManager.php:160:28: PossiblyInvalidArgument: Argument 1 of ldap_mod_del expects LDAP\Connection, but possibly different type LDAP\Connection|resource provided (see https://psalm.dev/092)
$this->logger->error('Unable to remove user: ' . $uid . ' from group: ' . $gid);
} else {
$this->logger->notice('Remove user: ' . $uid . ' from group: ' . $gid);
Expand Down
38 changes: 14 additions & 24 deletions lib/LDAPUserManager.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2017-2019 Cooperativa EITA <eita.org.br>
Expand Down Expand Up @@ -48,7 +50,7 @@
* @return int bitwise-or'ed actions
*/
#[\Override]
public function respondToActions() {
public function respondToActions(): int {
$setPassword = $this->canSetPassword() && !$this->ldapConnect->hasPasswordPolicy()
? Backend::SET_PASSWORD
: 0;
Expand All @@ -63,12 +65,11 @@
*
* @param string $uid user ID of the user
* @param string $displayName new user's display name
* @return string
* @throws HintException
* @throws ServerNotAvailableException
*/
#[\Override]
public function setDisplayName($uid, $displayName) {
public function setDisplayName($uid, $displayName): string {
$userDN = $this->getUserDN($uid);

$connection = $this->ldapProvider->getLDAPConnection($uid);
Expand All @@ -84,7 +85,7 @@
);
}

if (!is_resource($connection) && !is_object($connection)) {
if (!is_object($connection)) {
$this->logger->debug('LDAP resource not available', ['app' => 'ldap_write_support']);
throw new ServerNotAvailableException('LDAP server is not available');
}
Expand All @@ -106,10 +107,9 @@
* checks whether the user is allowed to change his avatar in Nextcloud
*
* @param string $uid the Nextcloud user name
* @return bool either the user can or cannot
*/
#[\Override]
public function canChangeAvatar($uid) {
public function canChangeAvatar($uid): bool {
return $this->configuration->hasAvatarPermission();
}

Expand All @@ -131,7 +131,7 @@
$data = $avatar->data();

$connection = $this->ldapProvider->getLDAPConnection($user->getUID());
ldap_mod_replace($connection, $userDN, ['jpegphoto' => $data]);

Check failure on line 134 in lib/LDAPUserManager.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

PossiblyInvalidArgument

lib/LDAPUserManager.php:134:21: PossiblyInvalidArgument: Argument 1 of ldap_mod_replace expects LDAP\Connection, but possibly different type LDAP\Connection|resource provided (see https://psalm.dev/092)
}
}

Expand All @@ -150,7 +150,7 @@

$emailField = $this->ldapProvider->getLDAPEmailField($user->getUID());
$connection = $this->ldapProvider->getLDAPConnection($user->getUID());
ldap_mod_replace($connection, $userDN, [$emailField => $newEmail]);

Check failure on line 153 in lib/LDAPUserManager.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

PossiblyInvalidArgument

lib/LDAPUserManager.php:153:20: PossiblyInvalidArgument: Argument 1 of ldap_mod_replace expects LDAP\Connection, but possibly different type LDAP\Connection|resource provided (see https://psalm.dev/092)
}

/**
Expand All @@ -158,11 +158,10 @@
*
* @param string $uid The username of the user to create
* @param string $password The password of the new user
* @return bool|string the created user of false
* @throws Exception
*/
#[\Override]
public function createUser($uid, $password) {
public function createUser($uid, $password): string|false {
$adminUser = $this->userSession->getUser();
$requireActorFromLDAP = $this->configuration->isLdapActorRequired();
if ($requireActorFromLDAP && !$adminUser instanceof IUser) {
Expand Down Expand Up @@ -199,7 +198,7 @@
$newUserDN = $this->ldapProvider->sanitizeDN([$newUserDN])[0];
$this->ensureAttribute($newUserEntry, $displayNameAttribute, $uid);

$ret = ldap_add($connection, $newUserDN, $newUserEntry);

Check failure on line 201 in lib/LDAPUserManager.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

PossiblyInvalidArgument

lib/LDAPUserManager.php:201:19: PossiblyInvalidArgument: Argument 1 of ldap_add expects LDAP\Connection, but possibly different type LDAP\Connection|resource provided (see https://psalm.dev/092)

$message = 'Create LDAP user \'{username}\' ({dn})';
$logMethod = 'info';
Expand All @@ -214,11 +213,11 @@
]);

if (!$ret && $this->configuration->isPreventFallback()) {
throw new \Exception('Cannot create user: ' . ldap_error($connection), ldap_errno($connection));

Check failure on line 216 in lib/LDAPUserManager.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

PossiblyInvalidArgument

lib/LDAPUserManager.php:216:86: PossiblyInvalidArgument: Argument 1 of ldap_errno expects LDAP\Connection, but possibly different type LDAP\Connection|resource provided (see https://psalm.dev/092)

Check failure on line 216 in lib/LDAPUserManager.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

PossiblyInvalidArgument

lib/LDAPUserManager.php:216:61: PossiblyInvalidArgument: Argument 1 of ldap_error expects LDAP\Connection, but possibly different type LDAP\Connection|resource provided (see https://psalm.dev/092)
}

if ($this->respondToActions() & Backend::SET_PASSWORD) {
$this->handleSetPassword($newUserDN, $password, $connection);

Check failure on line 220 in lib/LDAPUserManager.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

PossiblyInvalidArgument

lib/LDAPUserManager.php:220:52: PossiblyInvalidArgument: Argument 3 of OCA\LdapWriteSupport\LDAPUserManager::handleSetPassword expects LDAP\Connection, but possibly different type LDAP\Connection|resource provided (see https://psalm.dev/092)
}
return $ret ? $newUserDN : false;
}
Expand All @@ -230,7 +229,7 @@
}
}

public function buildNewEntry($username, $password, $base): array {
private function buildNewEntry(string $username, string $password, string $base): array {
// Make sure the parameters don't fool the following algorithm
if (str_contains($username, PHP_EOL)) {
throw new Exception('Username contains a new line');
Expand All @@ -253,7 +252,7 @@
foreach ($lines as $line) {
$split = explode(':', $line, 2);
$key = trim($split[0]);
$value = trim($split[1]);
$value = trim($split[1] ?? '');
if (!isset($entry[$key])) {
$entry[$key] = $value;
} elseif (is_array($entry[$key])) {
Expand All @@ -268,15 +267,11 @@
return [$dn, $entry];
}

/**
* @param $uid
* @return bool
*/
public function deleteUser($uid): bool {
$connection = $this->ldapProvider->getLDAPConnection($uid);
$userDN = $this->getUserDN($uid);
$user = $this->userManager->get($uid);
if ($res = ldap_delete($connection, $userDN)) {

Check failure on line 274 in lib/LDAPUserManager.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

PossiblyInvalidArgument

lib/LDAPUserManager.php:274:26: PossiblyInvalidArgument: Argument 1 of ldap_delete expects LDAP\Connection, but possibly different type LDAP\Connection|resource provided (see https://psalm.dev/092)
$message = 'Delete LDAP user (isDeleted): ' . $uid;
$this->logger->notice($message, ['app' => Application::APP_ID]);
if (
Expand Down Expand Up @@ -318,12 +313,11 @@
*
* @param string $uid The username
* @param string $password The new password
* @return bool
*
* Change the password of a user
*/
#[\Override]
public function setPassword($uid, $password) {
public function setPassword($uid, $password): bool {
$connection = $this->ldapProvider->getLDAPConnection($uid);
$userDN = $this->getUserDN($uid);

Expand All @@ -334,10 +328,9 @@
* get the user's home directory
*
* @param string $uid the username
* @return bool
*/
#[\Override]
public function getHome($uid) {
public function getHome($uid): bool {
// Not implemented
return false;
}
Expand All @@ -346,21 +339,18 @@
* get display name of the user
*
* @param string $uid user ID of the user
* @return string display name
*/
#[\Override]
public function getDisplayName($uid) {
public function getDisplayName($uid): string {
// Not implemented
return $uid;
}

/**
* Count the number of users
*
* @return int|bool
*/
#[\Override]
public function countUsers() {
public function countUsers(): false {
// Not implemented
return false;
}
Expand Down Expand Up @@ -398,7 +388,7 @@
}
}

private function getUserDN($uid): string {
private function getUserDN(string $uid): string {
return $this->ldapProvider->getUserDN($uid);
}

Expand Down
7 changes: 2 additions & 5 deletions lib/Listener/GroupBackendRegisteredListener.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
Expand All @@ -18,14 +19,10 @@
* @template-implements IEventListener<GroupBackendRegistered>
*/
class GroupBackendRegisteredListener implements IEventListener {
/** @var IAppManager */
private $appManager;

public function __construct(
IAppManager $appManager,
private IAppManager $appManager,
private LDAPGroupManager $ldapGroupManager,
) {
$this->appManager = $appManager;
}

/**
Expand Down
7 changes: 2 additions & 5 deletions lib/Listener/UserBackendRegisteredListener.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
Expand All @@ -18,14 +19,10 @@
* @template-implements IEventListener<UserBackendRegistered>
*/
class UserBackendRegisteredListener implements IEventListener {
/** @var IAppManager */
private $appManager;

public function __construct(
IAppManager $appManager,
private IAppManager $appManager,
private LDAPUserManager $ldapUserManager,
) {
$this->appManager = $appManager;
}

/**
Expand Down
Loading
Loading