diff --git a/.drone.star b/.drone.star index a96030e1..fc9efeac 100644 --- a/.drone.star +++ b/.drone.star @@ -4,7 +4,7 @@ MINIO_MC = "minio/mc:RELEASE.2020-12-18T10-53-53Z" OC_CI_ALPINE = "owncloudci/alpine:latest" OC_CI_BAZEL_BUILDIFIER = "owncloudci/bazel-buildifier" OC_CI_CEPH = "owncloudci/ceph:tag-build-master-jewel-ubuntu-16.04" -OC_CI_CORE = "owncloudci/core" +OC_CI_CORE = "owncloudci/core:php82" OC_CI_DRONE_SKIP_PIPELINE = "owncloudci/drone-skip-pipeline" OC_CI_NODEJS = "owncloudci/nodejs:%s" OC_CI_ORACLE_XE = "owncloudci/oracle-xe:latest" @@ -22,7 +22,7 @@ SELENIUM_STANDALONE_CHROME_DEBUG = "selenium/standalone-chrome-debug:3.141.59-ox SELENIUM_STANDALONE_FIREFOX_DEBUG = "selenium/standalone-firefox-debug:3.8.1" SONARSOURCE_SONAR_SCANNER_CLI = "sonarsource/sonar-scanner-cli" -DEFAULT_PHP_VERSION = "7.4" +DEFAULT_PHP_VERSION = "8.2" DEFAULT_NODEJS_VERSION = "14" # minio mc environment variables @@ -60,14 +60,7 @@ config = { ], "codestyle": True, "phpstan": True, - "phan": { - "multipleVersions": { - "phpVersions": [ - DEFAULT_PHP_VERSION, - "7.3", - ], - }, - }, + "phan": False, "javascript": False, "phpunit": { "allDatabases": { @@ -2247,7 +2240,7 @@ def installCore(ctx, version, db, useBundledApp): "name": "install-core", "image": OC_CI_CORE, "settings": { - "version": version, + "git_reference": "feat/php8", "core_path": dir["server"], "db_type": dbType, "db_name": database, @@ -2821,7 +2814,7 @@ def ldapIntegration(ctx): default = { "servers": ["daily-master-qa"], - "phpVersions": ["7.4"], + "phpVersions": ["8.2"], "databases": ["mysql:8.0"], "ldapNeeded": True, "logLevel": "2", diff --git a/composer.json b/composer.json index be5b30ce..f2e3738a 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "config": { "platform": { - "php": "7.3" + "php": "8.2" }, "allow-plugins": { "bamarni/composer-bin-plugin": true @@ -12,7 +12,7 @@ "laminas/laminas-ldap": "^2.13" }, "require": { - "php": ">=7.3", + "php": ">=8.2", "ext-ldap": "*" }, "extra": { diff --git a/composer.lock b/composer.lock index da3018e6..3d20f11c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "16a905380dcafacc284725c5fb720338", + "content-hash": "e3d4044bc5f08135c805c52461148541", "packages": [], "packages-dev": [ { @@ -66,34 +66,34 @@ }, { "name": "laminas/laminas-ldap", - "version": "2.13.0", + "version": "2.17.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-ldap.git", - "reference": "308f7749b12e2c14e91f51ddca4e2296fafe2367" + "reference": "cb66c477ec2fd2a7f38527c59d0635a9166b6597" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-ldap/zipball/308f7749b12e2c14e91f51ddca4e2296fafe2367", - "reference": "308f7749b12e2c14e91f51ddca4e2296fafe2367", + "url": "https://api.github.com/repos/laminas/laminas-ldap/zipball/cb66c477ec2fd2a7f38527c59d0635a9166b6597", + "reference": "cb66c477ec2fd2a7f38527c59d0635a9166b6597", "shasum": "" }, "require": { "ext-ldap": "*", - "php": "^7.3 || ~8.0.0 || ~8.1.0" + "php": "~8.0.0 || ~8.1.0 || ~8.2.0" }, "conflict": { "zendframework/zend-ldap": "*" }, "require-dev": { - "laminas/laminas-coding-standard": "~1.0.0", - "laminas/laminas-config": "^3.7.0", - "laminas/laminas-eventmanager": "^3.3", - "laminas/laminas-stdlib": "^3.3", - "php-mock/php-mock-phpunit": "^2.6", - "phpunit/phpunit": "^9.5.8", - "psalm/plugin-phpunit": "^0.16.1", - "vimeo/psalm": "^4.13.1" + "laminas/laminas-coding-standard": "~2.4.0", + "laminas/laminas-config": "^3.8.0", + "laminas/laminas-eventmanager": "^3.6.0", + "laminas/laminas-stdlib": "^3.15.0", + "php-mock/php-mock-phpunit": "^2.6.1", + "phpunit/phpunit": "^9.5.26", + "psalm/plugin-phpunit": "^0.18.0", + "vimeo/psalm": "^5.0.0" }, "suggest": { "laminas/laminas-eventmanager": "Laminas\\EventManager component" @@ -128,7 +128,7 @@ "type": "community_bridge" } ], - "time": "2022-03-19T15:18:53+00:00" + "time": "2022-12-19T19:50:51+00:00" } ], "aliases": [], @@ -137,12 +137,12 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=7.3", + "php": ">=8.2", "ext-ldap": "*" }, "platform-dev": [], "platform-overrides": { - "php": "7.3" + "php": "8.2" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/lib/Access.php b/lib/Access.php index 273616d9..6c19ec83 100644 --- a/lib/Access.php +++ b/lib/Access.php @@ -254,7 +254,7 @@ public function readAttribute($dn, $attr, $filter = 'objectClass=*') { /** * Runs an read operation against LDAP * - * @param resource $cr the LDAP connection + * @param \LDAP\Connection $cr the LDAP connection * @param string $dn * @param string|array $attributes * @param string $filter @@ -769,7 +769,8 @@ public function countUsersByLoginName($loginName) { */ public function fetchListOfUsers($filter, $attr, $limit = null, $offset = null) { $ldapRecords = $this->searchUsers($filter, $attr, $limit, $offset); - return $this->fetchList($ldapRecords, \count($attr) > 1); + $manyAttributes = \is_string($attr) ? false : \count($attr) > 1; + return $this->fetchList($ldapRecords, $manyAttributes); } /** diff --git a/lib/Connection.php b/lib/Connection.php index d96bf244..3197c434 100644 --- a/lib/Connection.php +++ b/lib/Connection.php @@ -83,7 +83,7 @@ */ class Connection extends LDAPUtility { /** - * @var resource|null + * @var \LDAP\Connection | null */ private $ldapConnectionRes; @@ -201,7 +201,7 @@ public function setIgnoreValidation($state) { /** * Returns the LDAP handler * - * @return resource | null + * @return \LDAP\Connection | null * * @throws \OC\ServerNotAvailableException * @throws BindFailedException diff --git a/lib/ILDAPWrapper.php b/lib/ILDAPWrapper.php index 150c8615..fae49395 100644 --- a/lib/ILDAPWrapper.php +++ b/lib/ILDAPWrapper.php @@ -40,7 +40,7 @@ interface ILDAPWrapper { /** * Bind to LDAP directory - * @param resource $link LDAP link resource + * @param \LDAP\Connection $link LDAP link resource * @param string $dn an RDN to log in with * @param string $password the password * @return bool true on success, false otherwise @@ -59,7 +59,7 @@ public function connect($host, $port); /** * Send LDAP pagination control - * @param resource $link LDAP link resource + * @param \LDAP\Connection $link LDAP link resource * @param int $pageSize number of results per page * @param bool $isCritical Indicates whether the pagination is critical of not. * @param string $cookie structure sent by LDAP server @@ -69,8 +69,8 @@ public function controlPagedResult($link, $pageSize, $isCritical, $cookie); /** * Retrieve the LDAP pagination cookie - * @param resource $link LDAP link resource - * @param resource $result LDAP result resource + * @param \LDAP\Connection $link LDAP link resource + * @param \LDAP\Result $result LDAP result resource * @param string $cookie structure sent by LDAP server * @param int $estimated The estimated number of entries to retrieve. * @return bool true on success, false otherwise @@ -81,7 +81,7 @@ public function controlPagedResultResponse($link, $result, &$cookie = null, &$es /** * Count the number of entries in a search - * @param resource $link LDAP link resource + * @param \LDAP\Connection $link LDAP link resource * @param resource $result LDAP result resource * @return int|false number of results on success, false otherwise */ @@ -89,14 +89,14 @@ public function countEntries($link, $result); /** * Return the LDAP error number of the last LDAP command - * @param resource $link LDAP link resource + * @param \LDAP\Connection $link LDAP link resource * @return string error message as string */ public function errno($link); /** * Return the LDAP error message of the last LDAP command - * @param resource $link LDAP link resource + * @param \LDAP\Connection $link LDAP link resource * @return int error code as integer */ public function error($link); @@ -124,7 +124,7 @@ public function explodeDN($dn, $withAttrib); /** * Return first result id - * @param resource $link LDAP link resource + * @param \LDAP\Connection $link LDAP link resource * @param resource $result LDAP result resource * @return Resource an LDAP search result resource * */ @@ -132,7 +132,7 @@ public function firstEntry($link, $result); /** * Get attributes from a search result entry - * @param resource $link LDAP link resource + * @param \LDAP\Connection $link LDAP link resource * @param resource $result LDAP result resource * @return array containing the results, false on error * */ @@ -140,7 +140,7 @@ public function getAttributes($link, $result); /** * Get the DN of a result entry - * @param resource $link LDAP link resource + * @param \LDAP\Connection $link LDAP link resource * @param resource $result LDAP result resource * @return string containing the DN, false on error */ @@ -148,7 +148,7 @@ public function getDN($link, $result); /** * Get all result entries - * @param resource $link LDAP link resource + * @param \LDAP\Connection $link LDAP link resource * @param resource $result LDAP result resource * @return array containing the results, false on error */ @@ -156,7 +156,7 @@ public function getEntries($link, $result); /** * Return next result id - * @param resource $link LDAP link resource + * @param \LDAP\Connection $link LDAP link resource * @param resource $result LDAP entry result resource * @return resource an LDAP search result resource * */ @@ -164,7 +164,7 @@ public function nextEntry($link, $result); /** * Read an entry - * @param resource $link LDAP link resource + * @param \LDAP\Connection $link LDAP link resource * @param string $baseDN The DN of the entry to read from * @param string $filter An LDAP filter * @param array $attr array of the attributes to read @@ -174,7 +174,8 @@ public function read($link, $baseDN, $filter, $attr); /** * Search LDAP tree - * @param resource $link LDAP link resource + * + * @param \LDAP\Connection $link LDAP link resource * @param string $baseDN The DN of the entry to read from * @param string $filter An LDAP filter * @param array $attr array of the attributes to read @@ -186,7 +187,7 @@ public function search($link, $baseDN, $filter, $attr, $attrsOnly = 0, $limit = /** * Sets the value of the specified option to be $value - * @param resource $link LDAP link resource + * @param \LDAP\Connection $link LDAP link resource * @param string $option a defined LDAP Server option * @param int $value the new value for the option * @return bool true on success, false otherwise @@ -195,14 +196,14 @@ public function setOption($link, $option, $value); /** * establish Start TLS - * @param resource $link LDAP link resource + * @param \LDAP\Connection $link LDAP link resource * @return bool true on success, false otherwise */ public function startTls($link); /** * Unbind from LDAP directory - * @param resource $link LDAP link resource + * @param \LDAP\Connection $link LDAP link resource * @return bool true on success, false otherwise */ public function unbind($link); @@ -223,7 +224,7 @@ public function hasPagedResultSupport(); /** * Checks whether the submitted parameter is a resource - * @param resource $resource the resource variable to check + * @param \LDAP\Connection|resource $resource the resource variable to check * @return bool true if it is a resource, false otherwise */ public function isResource($resource); diff --git a/lib/LDAP.php b/lib/LDAP.php index 71f06593..49faf705 100644 --- a/lib/LDAP.php +++ b/lib/LDAP.php @@ -32,9 +32,10 @@ class LDAP implements ILDAPWrapper { protected $curFunc = ''; protected $curArgs = []; + private array $pagedSearchControl; /** - * @param resource $link + * @param \LDAP\Connection $link * @param string $dn * @param string $password * @return bool|mixed @@ -62,37 +63,36 @@ public function connect($host, $port) { } /** - * @param LDAP|resource $link - * @param LDAP|resource $result + * @param \LDAP\Connection $link + * @param \LDAP\Result $result * @param string $cookie * @param int $estimated $cookie - * @return bool|LDAP + * @return bool */ public function controlPagedResultResponse($link, $result, &$cookie = null, &$estimated = null) { - $this->preFunctionCall( - 'ldap_control_paged_result_response', - [$link, $result, $cookie, $estimated] - ); - $result = @\ldap_control_paged_result_response($link, $result, $cookie, $estimated); // suppress deprecation for 7.4 - $this->postFunctionCall(); - - return $result; + $ret = ldap_parse_result($link, $result, $errcode, $matcheddn, $errmsg, $referrals, $controls); + if (!$ret) { + throw new \Exception('ldap_parse_result failed'); + } + $cookie = $controls[LDAP_CONTROL_PAGEDRESULTS]['value']['cookie'] ?? ''; + $estimated = $controls[LDAP_CONTROL_PAGEDRESULTS]['value']['size'] ?? ''; + return true; } /** - * @param LDAP|resource $link + * @param \LDAP\Connection $link * @param int $pageSize * @param bool $isCritical * @param string $cookie * @return mixed|true */ public function controlPagedResult($link, $pageSize, $isCritical, $cookie) { - return @$this->invokeLDAPMethod('control_paged_result', $link, $pageSize, // suppress deprecation for 7.4 - $isCritical, $cookie); + $this->pagedSearchControl = compact('pageSize', 'isCritical', 'cookie'); + return true; } /** - * @param LDAP|resource $link + * @param \LDAP\Connection $link * @param LDAP|resource $result * @return mixed */ @@ -101,7 +101,7 @@ public function countEntries($link, $result) { } /** - * @param LDAP|resource $link + * @param \LDAP\Connection $link * @return mixed|string */ public function errno($link) { @@ -109,7 +109,7 @@ public function errno($link) { } /** - * @param LDAP|resource $link + * @param \LDAP\Connection $link * @return int|mixed */ public function error($link) { @@ -142,7 +142,7 @@ public function explodeDN($dn, $withAttrib) { } /** - * @param LDAP|resource $link + * @param \LDAP\Connection $link * @param LDAP|resource $result * @return mixed */ @@ -151,7 +151,7 @@ public function firstEntry($link, $result) { } /** - * @param LDAP|resource $link + * @param \LDAP\Connection $link * @param LDAP|resource $result * @return array|mixed */ @@ -160,7 +160,7 @@ public function getAttributes($link, $result) { } /** - * @param LDAP|resource $link + * @param \LDAP\Connection $link * @param LDAP|resource $result * @return mixed|string */ @@ -169,7 +169,7 @@ public function getDN($link, $result) { } /** - * @param LDAP|resource $link + * @param \LDAP\Connection $link * @param LDAP|resource $result * @return array|mixed */ @@ -178,7 +178,7 @@ public function getEntries($link, $result) { } /** - * @param LDAP|resource $link + * @param \LDAP\Connection $link * @param resource $result * @return mixed */ @@ -187,7 +187,7 @@ public function nextEntry($link, $result) { } /** - * @param LDAP|resource $link + * @param \LDAP\Connection $link * @param string $baseDN * @param string $filter * @param array $attr @@ -198,7 +198,7 @@ public function read($link, $baseDN, $filter, $attr) { } /** - * @param LDAP|resource $link + * @param \LDAP\Connection $link * @param string $baseDN * @param string $filter * @param array $attr @@ -207,11 +207,17 @@ public function read($link, $baseDN, $filter, $attr) { * @return mixed */ public function search($link, $baseDN, $filter, $attr, $attrsOnly = 0, $limit = 0) { - return $this->invokeLDAPMethod('search', $link, $baseDN, $filter, $attr, $attrsOnly, $limit); + if ($this->pagedSearchControl['pageSize'] > 0) { + $control = [['oid' => LDAP_CONTROL_PAGEDRESULTS, 'value' => [ + 'size' => $this->pagedSearchControl['pageSize'], + 'cookie' => $this->pagedSearchControl['cookie']]]]; + } + + return ldap_search($link, $baseDN, $filter, $attr, $attrsOnly, $limit, -1, 0, $control ?? []); } /** - * @param LDAP|resource $link + * @param \LDAP\Connection $link * @param string $option * @param int $value * @return bool|mixed @@ -221,7 +227,7 @@ public function setOption($link, $option, $value) { } /** - * @param LDAP|resource $link + * @param \LDAP\Connection $link * @return mixed|true */ public function startTls($link) { @@ -229,7 +235,7 @@ public function startTls($link) { } /** - * @param resource $link + * @param \LDAP\Connection $link * @return bool|mixed */ public function unbind($link) { @@ -238,7 +244,7 @@ public function unbind($link) { /** * Checks whether the server supports LDAP - * @return boolean if it the case, false otherwise + * @return boolean * */ public function areLDAPFunctionsAvailable() { return \function_exists('ldap_connect'); @@ -246,30 +252,31 @@ public function areLDAPFunctionsAvailable() { /** * Checks whether PHP supports LDAP Paged Results - * @return boolean if it the case, false otherwise * */ - public function hasPagedResultSupport() { - $hasSupport = \function_exists('ldap_control_paged_result') - && \function_exists('ldap_control_paged_result_response'); - return $hasSupport; + public function hasPagedResultSupport(): bool { + return true; } - /** - * Checks whether the submitted parameter is a resource - * @param Resource $resource the resource variable to check - * @return bool true if it is a resource, false otherwise - */ public function isResource($resource) { + if ($resource instanceof \LDAP\Connection) { + return true; + } + if ($resource instanceof \LDAP\Result) { + return true; + } + if ($resource instanceof \LDAP\ResultEntry) { + return true; + } return \is_resource($resource); } - private function formatLdapCallArguments($func, $arguments) { + private function formatLdapCallArguments($func, $arguments): string { $argumentsLog = \implode( ",", \array_map( - function ($argument) { + static function ($argument) { if (\is_string($argument) || \is_bool($argument) || \is_numeric($argument)) { - return \strval($argument); + return (string)$argument; } return \gettype($argument); }, @@ -282,13 +289,14 @@ function ($argument) { /** * @return mixed + * @throws ServerNotAvailableException */ private function invokeLDAPMethod() { $arguments = \func_get_args(); $func = 'ldap_' . \array_shift($arguments); if (\function_exists($func)) { // Start logging event - $eventId = \uniqid($func); + $eventId = \uniqid($func, true); \OC::$server->getEventLogger()->start($eventId, $this->formatLdapCallArguments($func, $arguments)); // Execute call @@ -341,7 +349,7 @@ private function postFunctionCall() { throw new \Exception('LDAP Operations error', $errorCode); } else { \OC::$server->getLogger()->debug( - "LDAP error {$errorMsg} ({$errorCode}) after calling {$this->curFunc}", + "LDAP error $errorMsg ($errorCode) after calling $this->curFunc", [ 'app' => 'user_ldap'] ); } diff --git a/phpstan.neon b/phpstan.neon index cd706f61..2aa6786b 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -7,15 +7,15 @@ parameters: - %currentWorkingDirectory%/appinfo/Migrations/*.php ignoreErrors: - - message: '!Parameter #1 \$link of method OCA\\User_LDAP\\ILDAPWrapper::bind\(\) expects resource, null given.!' + message: '!Parameter #1 \$link of method OCA\\User_LDAP\\ILDAPWrapper::bind\(\) expects LDAP\\Connection, null given.!' path: lib/Connection.php count: 2 - - message: '!Parameter #1 \$link of method OCA\\User_LDAP\\ILDAPWrapper::errno\(\) expects resource, null given.!' + message: '!Parameter #1 \$link of method OCA\\User_LDAP\\ILDAPWrapper::errno\(\) expects LDAP\\Connection, null given.!' path: lib/Connection.php count: 2 - - message: '!Parameter #1 \$link of method OCA\\User_LDAP\\ILDAPWrapper::error\(\) expects resource, null given.!' + message: '!Parameter #1 \$link of method OCA\\User_LDAP\\ILDAPWrapper::error\(\) expects LDAP\\Connection, null given.!' path: lib/Connection.php count: 2 - diff --git a/tests/integration/AbstractIntegrationTest.php b/tests/integration/AbstractIntegrationTest.php index 181737ed..b77b3855 100644 --- a/tests/integration/AbstractIntegrationTest.php +++ b/tests/integration/AbstractIntegrationTest.php @@ -22,13 +22,13 @@ namespace OCA\User_LDAP\Tests\Integration; -use Exception; use OC; use OCA\User_LDAP\Access; use OCA\User_LDAP\Connection; use OCA\User_LDAP\Configuration; use OCA\User_LDAP\LDAP; use OCA\User_LDAP\User\Manager; +use Throwable; use function get_class_methods; use function strpos; @@ -164,7 +164,7 @@ private function runTest(string $method): void { print(PHP_EOL . '>>> !!! Test ' . $method . ' FAILED !!! <<<' . PHP_EOL . PHP_EOL); exit(1); } - } catch (Exception $ex) { + } catch (Throwable $ex) { print(PHP_EOL . '>>> !!! Test ' . $method . ' FAILED !!! <<<' . PHP_EOL . PHP_EOL); print((string)$ex); exit(1);