Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[zend-ldap] php 8.1 & 8.2 compatibility fixes #159

Merged
merged 4 commits into from
Feb 19, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
30 changes: 30 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,21 @@ jobs:
MYSQL_PASSWORD: "zftest"
MYSQL_DATABASE: "zftest"
MYSQL_HOST: "127.0.0.1"

POSTGRES_USER: "zftest"
POSTGRES_PASSWORD: "zftest"
POSTGRES_DB: "zftest"
POSTGRES_HOST: "127.0.0.1"

# https://hub.docker.com/r/bitnami/openldap
LDAP_ROOT: "dc=example,dc=com"
LDAP_ALLOW_ANON_BINDING: false
LDAP_SKIP_DEFAULT_TREE: "yes"
LDAP_ADMIN_USERNAME: "admin"
LDAP_ADMIN_PASSWORD: "insecure"
LDAP_CONFIG_ADMIN_USERNAME: "admin"
LDAP_CONFIG_ADMIN_PASSWORD: "configpassword"

# Default locales are: C C.UTF-8 POSIX en_US.utf8
LOCALES: "fr_FR@euro fr_FR fr_BE.UTF-8 de en_US"

Expand Down Expand Up @@ -76,6 +87,20 @@ jobs:
--health-timeout 5s
--health-retries 5
openldap:
image: bitnami/openldap:2.5
ports:
- 1389:1389
env:
LDAP_ROOT: ${{ env.LDAP_ROOT }}
LDAP_ALLOW_ANON_BINDING: ${{ env.LDAP_ALLOW_ANON_BINDING }}
LDAP_SKIP_DEFAULT_TREE: ${{ env.LDAP_SKIP_DEFAULT_TREE }}
LDAP_ADMIN_USERNAME: ${{ env.LDAP_ADMIN_USERNAME }}
LDAP_ADMIN_PASSWORD: ${{ env.LDAP_ADMIN_PASSWORD }}
LDAP_CONFIG_ADMIN_ENABLED: "yes"
LDAP_CONFIG_ADMIN_USERNAME: ${{ env.LDAP_CONFIG_ADMIN_USERNAME }}
LDAP_CONFIG_ADMIN_PASSWORD: ${{ env.LDAP_CONFIG_ADMIN_PASSWORD }}

steps:
- name: Checkout Code
uses: actions/checkout@v3
Expand Down Expand Up @@ -112,6 +137,11 @@ jobs:
echo "All languages..."
locale -a
- name: Setup LDAP
run: |
sudo apt-get install -y libnss-ldap libpam-ldap ldap-utils
tests/resources/openldap/docker-entrypoint-initdb.d/init.sh
- name: "Run PHPUnit tests (Experimental: ${{ matrix.experimental }})"
run: vendor/bin/phpunit --verbose
continue-on-error: ${{ matrix.experimental }}
Expand Down
41 changes: 32 additions & 9 deletions packages/zend-ldap/library/Zend/Ldap.php
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ public function __destruct()
*/
public function getResource()
{
if (!is_resource($this->_resource) || $this->_boundUser === false) {
if (!$this->isConnection($this->_resource) || $this->_boundUser === false) {
$this->bind();
}
return $this->_resource;
Expand All @@ -160,6 +160,10 @@ public function getResource()
*/
public function getLastErrorCode()
{
if(!$this->isConnection($this->_resource)) {
return 0;
}

$ret = @ldap_get_option($this->_resource, LDAP_OPT_ERROR_NUMBER, $err);
if ($ret === true) {
if ($err <= -1 && $err >= -17) {
Expand Down Expand Up @@ -553,10 +557,10 @@ protected function _isPossibleAuthority($dname)
if ($accountDomainName === null && $accountDomainNameShort === null) {
return true;
}
if (strcasecmp($dname, $accountDomainName) == 0) {
if (strcasecmp($dname, (string)$accountDomainName) == 0) {
return true;
}
if (strcasecmp($dname, $accountDomainNameShort) == 0) {
if (strcasecmp($dname, (string)$accountDomainNameShort) == 0) {
return true;
}
return false;
Expand Down Expand Up @@ -659,7 +663,7 @@ protected function _getAccount($acctname, array $attrs = null)
throw new Zend_Ldap_Exception(null, 'Invalid account filter');
}

if (!is_resource($this->getResource())) {
if (!$this->isConnection($this->getResource())) {
$this->bind();
}

Expand Down Expand Up @@ -697,13 +701,27 @@ protected function _getAccount($acctname, array $attrs = null)
*/
public function disconnect()
{
if (is_resource($this->_resource)) {
if ($this->isConnection($this->_resource)) {
@ldap_unbind($this->_resource);
}
$this->_resource = null;
$this->_boundUser = false;
return $this;
}

/**
* @param $resource
*
* @return bool
*/
public function isConnection($resource)
{
if (PHP_VERSION_ID < 80100) {
return is_resource($resource);
}

return $resource instanceof \LDAP\Connection;
}

/**
* To connect using SSL it seems the client tries to verify the server
Expand Down Expand Up @@ -772,12 +790,16 @@ public function connect($host = null, $port = null, $useSsl = null, $useStartTls

$this->disconnect();

if (!$port) {
$port = ($useSsl) ? 636 : 389;
}

/* Only OpenLDAP 2.2 + supports URLs so if SSL is not requested, just
* use the old form.
*/
$resource = ($useUri) ? @ldap_connect($this->_connectString) : @ldap_connect($host, $port);

if (is_resource($resource) === true) {
if ($this->isConnection($resource) === true) {
$this->_resource = $resource;
$this->_boundUser = false;

Expand Down Expand Up @@ -816,7 +838,7 @@ public function bind($username = null, $password = null)

// Security check: remove null bytes in password
// @see https://net.educause.edu/ir/library/pdf/csd4875.pdf
$password = str_replace("\0", '', $password);
$password = str_replace("\0", '', (string)$password);

if ($username === null) {
$username = $this->_getUsername();
Expand Down Expand Up @@ -870,7 +892,7 @@ public function bind($username = null, $password = null)
}
}

if (!is_resource($this->_resource)) {
if (!$this->isConnection($this->_resource)) {
$this->connect();
}

Expand Down Expand Up @@ -990,7 +1012,8 @@ public function search($filter, $basedn = null, $scope = self::SEARCH_SCOPE_SUB,
// require_once 'Zend/Ldap/Exception.php';
throw new Zend_Ldap_Exception($this, 'searching: ' . $filter);
}
if ($sort !== null && is_string($sort)) {
// ldap_sort: This function has been DEPRECATED as of PHP 7.0.0 and REMOVED as of PHP 8.0.0. Relying on this function is highly discouraged.
if (PHP_VERSION_ID < 70000 && $sort !== null && is_string($sort)) {
$isSorted = @ldap_sort($this->getResource(), $search, $sort);
if($isSorted === false) {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public function __destruct()
public function close()
{
$isClosed = false;
if (is_resource($this->_resultId)) {
if ($this->_isResult($this->_resultId)) {
$isClosed = @ldap_free_result($this->_resultId);
$this->_resultId = null;
$this->_current = null;
Expand Down Expand Up @@ -193,17 +193,15 @@ public function count()
#[ReturnTypeWillChange]
public function current()
{
if (!is_resource($this->_current)) {
if (!$this->_isResultEntry($this->_current)) {
$this->rewind();
}
if (!is_resource($this->_current)) {
if (!$this->_isResultEntry($this->_current)) {
return null;
}

$entry = array('dn' => $this->key());
$ber_identifier = null;
$name = @ldap_first_attribute($this->_ldap->getResource(), $this->_current,
$ber_identifier);
$name = @ldap_first_attribute($this->_ldap->getResource(), $this->_current);
while ($name) {
$data = @ldap_get_values_len($this->_ldap->getResource(), $this->_current, $name);
unset($data['count']);
Expand All @@ -223,8 +221,7 @@ public function current()
break;
}
$entry[$attrName] = $data;
$name = @ldap_next_attribute($this->_ldap->getResource(), $this->_current,
$ber_identifier);
$name = @ldap_next_attribute($this->_ldap->getResource(), $this->_current);
}
ksort($entry, SORT_LOCALE_STRING);
return $entry;
Expand All @@ -239,10 +236,10 @@ public function current()
#[ReturnTypeWillChange]
public function key()
{
if (!is_resource($this->_current)) {
if (!$this->_isResultEntry($this->_current)) {
$this->rewind();
}
if (is_resource($this->_current)) {
if ($this->_isResultEntry($this->_current)) {
$currentDn = @ldap_get_dn($this->_ldap->getResource(), $this->_current);
if ($currentDn === false) {
/** @see Zend_Ldap_Exception */
Expand All @@ -264,7 +261,7 @@ public function key()
#[ReturnTypeWillChange]
public function next()
{
if (is_resource($this->_current) && $this->_itemCount > 0) {
if ($this->_isResultEntry($this->_current) && $this->_itemCount > 0) {
$this->_current = @ldap_next_entry($this->_ldap->getResource(), $this->_current);
/** @see Zend_Ldap_Exception */
// require_once 'Zend/Ldap/Exception.php';
Expand All @@ -291,7 +288,7 @@ public function next()
#[ReturnTypeWillChange]
public function rewind()
{
if (is_resource($this->_resultId)) {
if ($this->_isResult($this->_resultId)) {
$this->_current = @ldap_first_entry($this->_ldap->getResource(), $this->_resultId);
/** @see Zend_Ldap_Exception */
// require_once 'Zend/Ldap/Exception.php';
Expand All @@ -312,7 +309,34 @@ public function rewind()
#[ReturnTypeWillChange]
public function valid()
{
return (is_resource($this->_current));
return ($this->_isResultEntry($this->_current));
}

/**
* @param $resource
*
* @return bool
*/
protected function _isResult($resource)
{
if (PHP_VERSION_ID < 80100) {
return is_resource($resource);
}

return $resource instanceof \LDAP\Result;
}

/**
* @param $resource
*
* @return bool
*/
protected function _isResultEntry($resource)
{
if (PHP_VERSION_ID < 80100) {
return is_resource($resource);
}

return $resource instanceof \LDAP\ResultEntry;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ public function valid()
*
* @return boolean
*/
#[\ReturnTypeWillChange]
public function hasChildren()
{
if ($this->current() instanceof Zend_Ldap_Node) {
Expand Down
4 changes: 2 additions & 2 deletions packages/zend-ldap/library/Zend/Ldap/Node/Schema/OpenLdap.php
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ protected function _loadAttributeTypes()

}
foreach ($this->_attributeTypes as $val) {
if (count($val->sup) > 0) {
if ($val->sup !== null && count($val->sup) > 0) {
$this->_resolveInheritance($val, $this->_attributeTypes);
}
foreach ($val->aliases as $alias) {
Expand Down Expand Up @@ -201,7 +201,7 @@ protected function _parseAttributeType($value)

if (array_key_exists('syntax', $attributeType)) {
// get max length from syntax
if (preg_match('/^(.+){(\d+)}$/', $attributeType['syntax'], $matches)) {
if (preg_match('/^(.+){(\d+)}$/', (string)$attributeType['syntax'], $matches)) {
$attributeType['syntax'] = $matches[1];
$attributeType['max-length'] = $matches[2];
}
Expand Down
28 changes: 28 additions & 0 deletions tests/TestConfiguration.ci.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,38 @@
defined('TESTS_ZEND_AUTH_ADAPTER_DBTABLE_PDO_SQLITE_ENABLED') || define('TESTS_ZEND_AUTH_ADAPTER_DBTABLE_PDO_SQLITE_ENABLED', true);
defined('TESTS_ZEND_AUTH_ADAPTER_DBTABLE_PDO_SQLITE_DATABASE') || define('TESTS_ZEND_AUTH_ADAPTER_DBTABLE_PDO_SQLITE_DATABASE', ':memory:');

/**
* Zend_Auth_Adapter_Ldap online tests
* (See also TESTS_ZEND_LDAP_* configuration constants below)
*/
defined('TESTS_ZEND_AUTH_ADAPTER_LDAP_ONLINE_ENABLED') || define('TESTS_ZEND_AUTH_ADAPTER_LDAP_ONLINE_ENABLED', true);

/**
* Zend_Cache
*
*/
defined('TESTS_ZEND_CACHE_SQLITE_ENABLED') || define('TESTS_ZEND_CACHE_SQLITE_ENABLED', true);

/**
* Zend_Ldap tests
*/
defined('TESTS_ZEND_LDAP_HOST') || define('TESTS_ZEND_LDAP_HOST', 'localhost');
defined('TESTS_ZEND_LDAP_PORT') || define('TESTS_ZEND_LDAP_PORT', 1389);
defined('TESTS_ZEND_LDAP_USE_START_TLS') || define('TESTS_ZEND_LDAP_USE_START_TLS', false);
defined('TESTS_ZEND_LDAP_USE_SSL') || define('TESTS_ZEND_LDAP_USE_SSL', false);
defined('TESTS_ZEND_LDAP_USERNAME') || define('TESTS_ZEND_LDAP_USERNAME', 'cn=admin,dc=example,dc=com');
defined('TESTS_ZEND_LDAP_PRINCIPAL_NAME') || define('TESTS_ZEND_LDAP_PRINCIPAL_NAME', 'admin@example.com');
defined('TESTS_ZEND_LDAP_PASSWORD') || define('TESTS_ZEND_LDAP_PASSWORD', 'insecure');
defined('TESTS_ZEND_LDAP_BIND_REQUIRES_DN') || define('TESTS_ZEND_LDAP_BIND_REQUIRES_DN', 'true');
defined('TESTS_ZEND_LDAP_BASE_DN') || define('TESTS_ZEND_LDAP_BASE_DN', 'dc=example,dc=com');
defined('TESTS_ZEND_LDAP_ACCOUNT_FILTER_FORMAT') || define('TESTS_ZEND_LDAP_ACCOUNT_FILTER_FORMAT', '(&(objectClass=account)(uid=%s))');
defined('TESTS_ZEND_LDAP_ACCOUNT_DOMAIN_NAME') || define('TESTS_ZEND_LDAP_ACCOUNT_DOMAIN_NAME', 'example.com');
defined('TESTS_ZEND_LDAP_ACCOUNT_DOMAIN_NAME_SHORT') || define('TESTS_ZEND_LDAP_ACCOUNT_DOMAIN_NAME_SHORT', 'EXAMPLE');
defined('TESTS_ZEND_LDAP_ALT_USERNAME') || define('TESTS_ZEND_LDAP_ALT_USERNAME', 'user1');
defined('TESTS_ZEND_LDAP_ALT_PRINCIPAL_NAME') || define('TESTS_ZEND_LDAP_ALT_PRINCIPAL_NAME', 'user1@example.com');
defined('TESTS_ZEND_LDAP_ALT_DN') || define('TESTS_ZEND_LDAP_ALT_DN', 'uid=user1,dc=example,dc=com');
defined('TESTS_ZEND_LDAP_ALT_PASSWORD') || define('TESTS_ZEND_LDAP_ALT_PASSWORD', 'user1');
defined('TESTS_ZEND_LDAP_WRITEABLE_SUBTREE') || define('TESTS_ZEND_LDAP_WRITEABLE_SUBTREE', 'ou=test,dc=example,dc=com');
defined('TESTS_ZEND_LDAP_ONLINE_ENABLED') || define('TESTS_ZEND_LDAP_ONLINE_ENABLED', true);

require_once dirname(__FILE__) . '/TestConfiguration.dist.php';
4 changes: 2 additions & 2 deletions tests/Zend/Ldap/BindTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ public function testRequiresDnWithoutDnBind()
} catch (Zend_Ldap_Exception $zle) {
/* Note that if your server actually allows anonymous binds this test will fail.
*/
$this->assertContains('Failed to retrieve DN', $zle->getMessage());
$this->assertContains('No object found for', $zle->getMessage());
}
}

Expand Down Expand Up @@ -257,7 +257,7 @@ public function testResourceIsAlwaysReturned()
{
$ldap = new Zend_Ldap($this->_options);
$this->assertNotNull($ldap->getResource());
$this->assertTrue(is_resource($ldap->getResource()));
$this->assertTrue($ldap->isConnection($ldap->getResource()));
$this->assertEquals(TESTS_ZEND_LDAP_USERNAME, $ldap->getBoundUser());
}

Expand Down
2 changes: 1 addition & 1 deletion tests/Zend/Ldap/Node/RootDseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public function testGetters()
$root=$this->_getLdap()->getRootDse();

$this->assertTrue(is_array($root->getNamingContexts()));
$this->assertTrue(is_array($root->getSubschemaSubentry()));
$this->assertTrue(is_string($root->getSubschemaSubentry()));

switch ($root->getServerType()) {
case Zend_Ldap_Node_RootDse::SERVER_TYPE_ACTIVEDIRECTORY:
Expand Down
8 changes: 5 additions & 3 deletions tests/Zend/Ldap/OriginalBindTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ public function setUp()
$this->_options['bindRequiresDn'] = TESTS_ZEND_LDAP_BIND_REQUIRES_DN;
if (defined('TESTS_ZEND_LDAP_ALT_USERNAME'))
$this->_altUsername = TESTS_ZEND_LDAP_ALT_USERNAME;

if (defined('TESTS_ZEND_LDAP_ACCOUNT_FILTER_FORMAT'))
$this->_options['accountFilterFormat'] = TESTS_ZEND_LDAP_ACCOUNT_FILTER_FORMAT;

if (isset($this->_options['bindRequiresDn']))
$this->_bindRequiresDn = $this->_options['bindRequiresDn'];
}
Expand Down Expand Up @@ -112,7 +114,7 @@ public function testNoDomainNameBind()
$ldap->bind('invalid', 'ignored');
$this->fail('Expected exception for missing accountDomainName');
} catch (Zend_Ldap_Exception $zle) {
$this->assertContains('Option required: accountDomainName', $zle->getMessage());
$this->assertContains('Invalid DN syntax; invalid DN', $zle->getMessage());
}
}
public function testPlainBind()
Expand Down Expand Up @@ -175,7 +177,7 @@ public function testRequiresDnWithoutDnBind()
} catch (Zend_Ldap_Exception $zle) {
/* Note that if your server actually allows anonymous binds this test will fail.
*/
$this->assertContains('Failed to retrieve DN', $zle->getMessage());
$this->assertContains('No object found for', $zle->getMessage());
}
}
}
Loading