first commit
This commit is contained in:
57
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/AbstractConnection.php
vendored
Normal file
57
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/AbstractConnection.php
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Adapter;
|
||||
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
/**
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
*/
|
||||
abstract class AbstractConnection implements ConnectionInterface
|
||||
{
|
||||
protected $config;
|
||||
|
||||
public function __construct(array $config = [])
|
||||
{
|
||||
$resolver = new OptionsResolver();
|
||||
|
||||
$this->configureOptions($resolver);
|
||||
|
||||
$this->config = $resolver->resolve($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'host' => 'localhost',
|
||||
'version' => 3,
|
||||
'connection_string' => null,
|
||||
'encryption' => 'none',
|
||||
'options' => [],
|
||||
]);
|
||||
|
||||
$resolver->setDefault('port', fn (Options $options) => 'ssl' === $options['encryption'] ? 636 : 389);
|
||||
|
||||
$resolver->setDefault('connection_string', fn (Options $options) => sprintf('ldap%s://%s:%s', 'ssl' === $options['encryption'] ? 's' : '', $options['host'], $options['port']));
|
||||
|
||||
$resolver->setAllowedTypes('host', 'string');
|
||||
$resolver->setAllowedTypes('port', 'numeric');
|
||||
$resolver->setAllowedTypes('connection_string', 'string');
|
||||
$resolver->setAllowedTypes('version', 'numeric');
|
||||
$resolver->setAllowedValues('encryption', ['none', 'ssl', 'tls']);
|
||||
$resolver->setAllowedTypes('options', 'array');
|
||||
}
|
||||
}
|
50
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/AbstractQuery.php
vendored
Normal file
50
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/AbstractQuery.php
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Adapter;
|
||||
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
/**
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
*/
|
||||
abstract class AbstractQuery implements QueryInterface
|
||||
{
|
||||
protected $connection;
|
||||
protected $dn;
|
||||
protected $query;
|
||||
protected $options;
|
||||
|
||||
public function __construct(ConnectionInterface $connection, string $dn, string $query, array $options = [])
|
||||
{
|
||||
$resolver = new OptionsResolver();
|
||||
$resolver->setDefaults([
|
||||
'filter' => '*',
|
||||
'maxItems' => 0,
|
||||
'sizeLimit' => 0,
|
||||
'timeout' => 0,
|
||||
'deref' => static::DEREF_NEVER,
|
||||
'attrsOnly' => 0,
|
||||
'scope' => static::SCOPE_SUB,
|
||||
'pageSize' => 0,
|
||||
]);
|
||||
$resolver->setAllowedValues('deref', [static::DEREF_ALWAYS, static::DEREF_NEVER, static::DEREF_FINDING, static::DEREF_SEARCHING]);
|
||||
$resolver->setAllowedValues('scope', [static::SCOPE_BASE, static::SCOPE_ONE, static::SCOPE_SUB]);
|
||||
|
||||
$resolver->setNormalizer('filter', fn (Options $options, $value) => \is_array($value) ? $value : [$value]);
|
||||
|
||||
$this->connection = $connection;
|
||||
$this->dn = $dn;
|
||||
$this->query = $query;
|
||||
$this->options = $resolver->resolve($options);
|
||||
}
|
||||
}
|
38
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/AdapterInterface.php
vendored
Normal file
38
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/AdapterInterface.php
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Adapter;
|
||||
|
||||
/**
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
*/
|
||||
interface AdapterInterface
|
||||
{
|
||||
/**
|
||||
* Returns the current connection.
|
||||
*/
|
||||
public function getConnection(): ConnectionInterface;
|
||||
|
||||
/**
|
||||
* Creates a new Query.
|
||||
*/
|
||||
public function createQuery(string $dn, string $query, array $options = []): QueryInterface;
|
||||
|
||||
/**
|
||||
* Fetches the entry manager instance.
|
||||
*/
|
||||
public function getEntryManager(): EntryManagerInterface;
|
||||
|
||||
/**
|
||||
* Escape a string for use in an LDAP filter or DN.
|
||||
*/
|
||||
public function escape(string $subject, string $ignore = '', int $flags = 0): string;
|
||||
}
|
28
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/CollectionInterface.php
vendored
Normal file
28
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/CollectionInterface.php
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Adapter;
|
||||
|
||||
use Symfony\Component\Ldap\Entry;
|
||||
|
||||
/**
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
*
|
||||
* @extends \ArrayAccess<int, Entry>
|
||||
* @extends \IteratorAggregate<int, Entry>
|
||||
*/
|
||||
interface CollectionInterface extends \Countable, \IteratorAggregate, \ArrayAccess
|
||||
{
|
||||
/**
|
||||
* @return list<Entry>
|
||||
*/
|
||||
public function toArray(): array;
|
||||
}
|
38
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/ConnectionInterface.php
vendored
Normal file
38
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/ConnectionInterface.php
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Adapter;
|
||||
|
||||
use Symfony\Component\Ldap\Exception\AlreadyExistsException;
|
||||
use Symfony\Component\Ldap\Exception\ConnectionTimeoutException;
|
||||
use Symfony\Component\Ldap\Exception\InvalidCredentialsException;
|
||||
|
||||
/**
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
*/
|
||||
interface ConnectionInterface
|
||||
{
|
||||
/**
|
||||
* Checks whether the connection was already bound or not.
|
||||
*/
|
||||
public function isBound(): bool;
|
||||
|
||||
/**
|
||||
* Binds the connection against a user's DN and password.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws AlreadyExistsException When the connection can't be created because of an LDAP_ALREADY_EXISTS error
|
||||
* @throws ConnectionTimeoutException When the connection can't be created because of an LDAP_TIMEOUT error
|
||||
* @throws InvalidCredentialsException When the connection can't be created because of an LDAP_INVALID_CREDENTIALS error
|
||||
*/
|
||||
public function bind(?string $dn = null, #[\SensitiveParameter] ?string $password = null);
|
||||
}
|
74
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/EntryManagerInterface.php
vendored
Normal file
74
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/EntryManagerInterface.php
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Adapter;
|
||||
|
||||
use Symfony\Component\Ldap\Entry;
|
||||
use Symfony\Component\Ldap\Exception\LdapException;
|
||||
use Symfony\Component\Ldap\Exception\NotBoundException;
|
||||
|
||||
/**
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
* @author Bob van de Vijver <bobvandevijver@hotmail.com>
|
||||
* @author Kevin Schuurmans <kevin.schuurmans@freshheads.com>
|
||||
*/
|
||||
interface EntryManagerInterface
|
||||
{
|
||||
/**
|
||||
* Adds a new entry in the Ldap server.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws NotBoundException
|
||||
* @throws LdapException
|
||||
*/
|
||||
public function add(Entry $entry);
|
||||
|
||||
/**
|
||||
* Updates an entry from the Ldap server.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws NotBoundException
|
||||
* @throws LdapException
|
||||
*/
|
||||
public function update(Entry $entry);
|
||||
|
||||
/**
|
||||
* Moves an entry on the Ldap server.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws NotBoundException
|
||||
* @throws LdapException
|
||||
*/
|
||||
public function move(Entry $entry, string $newParent);
|
||||
|
||||
/**
|
||||
* Renames an entry on the Ldap server.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws NotBoundException
|
||||
* @throws LdapException
|
||||
*/
|
||||
public function rename(Entry $entry, string $newRdn, bool $removeOldRdn = true);
|
||||
|
||||
/**
|
||||
* Removes an entry from the Ldap server.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws NotBoundException
|
||||
* @throws LdapException
|
||||
*/
|
||||
public function remove(Entry $entry);
|
||||
}
|
70
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/ExtLdap/Adapter.php
vendored
Normal file
70
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/ExtLdap/Adapter.php
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Adapter\ExtLdap;
|
||||
|
||||
use Symfony\Component\Ldap\Adapter\AdapterInterface;
|
||||
use Symfony\Component\Ldap\Adapter\ConnectionInterface;
|
||||
use Symfony\Component\Ldap\Adapter\EntryManagerInterface;
|
||||
use Symfony\Component\Ldap\Adapter\QueryInterface;
|
||||
use Symfony\Component\Ldap\Exception\LdapException;
|
||||
|
||||
/**
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
*/
|
||||
class Adapter implements AdapterInterface
|
||||
{
|
||||
private array $config;
|
||||
private ConnectionInterface $connection;
|
||||
private EntryManagerInterface $entryManager;
|
||||
|
||||
public function __construct(array $config = [])
|
||||
{
|
||||
if (!\extension_loaded('ldap')) {
|
||||
throw new LdapException('The LDAP PHP extension is not enabled.');
|
||||
}
|
||||
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function getConnection(): ConnectionInterface
|
||||
{
|
||||
return $this->connection ??= new Connection($this->config);
|
||||
}
|
||||
|
||||
public function getEntryManager(): EntryManagerInterface
|
||||
{
|
||||
return $this->entryManager ??= new EntryManager($this->getConnection());
|
||||
}
|
||||
|
||||
public function createQuery(string $dn, string $query, array $options = []): QueryInterface
|
||||
{
|
||||
return new Query($this->getConnection(), $dn, $query, $options);
|
||||
}
|
||||
|
||||
public function escape(string $subject, string $ignore = '', int $flags = 0): string
|
||||
{
|
||||
$value = ldap_escape($subject, $ignore, $flags);
|
||||
|
||||
// Per RFC 4514, leading/trailing spaces should be encoded in DNs, as well as carriage returns.
|
||||
if ($flags & \LDAP_ESCAPE_DN) {
|
||||
if (!empty($value) && ' ' === $value[0]) {
|
||||
$value = '\\20'.substr($value, 1);
|
||||
}
|
||||
if (!empty($value) && ' ' === $value[\strlen($value) - 1]) {
|
||||
$value = substr($value, 0, -1).'\\20';
|
||||
}
|
||||
$value = str_replace("\r", '\0d', $value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
137
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/ExtLdap/Collection.php
vendored
Normal file
137
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/ExtLdap/Collection.php
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Adapter\ExtLdap;
|
||||
|
||||
use Symfony\Component\Ldap\Adapter\CollectionInterface;
|
||||
use Symfony\Component\Ldap\Entry;
|
||||
use Symfony\Component\Ldap\Exception\LdapException;
|
||||
|
||||
/**
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
*/
|
||||
class Collection implements CollectionInterface
|
||||
{
|
||||
private Connection $connection;
|
||||
private Query $search;
|
||||
/** @var list<Entry> */
|
||||
private array $entries;
|
||||
|
||||
public function __construct(Connection $connection, Query $search)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
$this->search = $search;
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return $this->entries ??= iterator_to_array($this->getIterator(), false);
|
||||
}
|
||||
|
||||
public function count(): int
|
||||
{
|
||||
$con = $this->connection->getResource();
|
||||
$searches = $this->search->getResources();
|
||||
$count = 0;
|
||||
foreach ($searches as $search) {
|
||||
$searchCount = ldap_count_entries($con, $search);
|
||||
if (false === $searchCount) {
|
||||
throw new LdapException('Error while retrieving entry count: '.ldap_error($con));
|
||||
}
|
||||
$count += $searchCount;
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
public function getIterator(): \Traversable
|
||||
{
|
||||
if (0 === $this->count()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$con = $this->connection->getResource();
|
||||
$searches = $this->search->getResources();
|
||||
foreach ($searches as $search) {
|
||||
$current = ldap_first_entry($con, $search);
|
||||
|
||||
if (false === $current) {
|
||||
throw new LdapException('Could not rewind entries array: '.ldap_error($con));
|
||||
}
|
||||
|
||||
yield $this->getSingleEntry($con, $current);
|
||||
|
||||
while (false !== $current = ldap_next_entry($con, $current)) {
|
||||
yield $this->getSingleEntry($con, $current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function offsetExists(mixed $offset): bool
|
||||
{
|
||||
$this->toArray();
|
||||
|
||||
return isset($this->entries[$offset]);
|
||||
}
|
||||
|
||||
public function offsetGet(mixed $offset): ?Entry
|
||||
{
|
||||
$this->toArray();
|
||||
|
||||
return $this->entries[$offset] ?? null;
|
||||
}
|
||||
|
||||
public function offsetSet(mixed $offset, mixed $value): void
|
||||
{
|
||||
$this->toArray();
|
||||
|
||||
$this->entries[$offset] = $value;
|
||||
}
|
||||
|
||||
public function offsetUnset($offset): void
|
||||
{
|
||||
$this->toArray();
|
||||
|
||||
unset($this->entries[$offset]);
|
||||
}
|
||||
|
||||
private function getSingleEntry($con, $current): Entry
|
||||
{
|
||||
$attributes = ldap_get_attributes($con, $current);
|
||||
|
||||
if (false === $attributes) {
|
||||
throw new LdapException('Could not fetch attributes: '.ldap_error($con));
|
||||
}
|
||||
|
||||
$attributes = $this->cleanupAttributes($attributes);
|
||||
|
||||
$dn = ldap_get_dn($con, $current);
|
||||
|
||||
if (false === $dn) {
|
||||
throw new LdapException('Could not fetch DN: '.ldap_error($con));
|
||||
}
|
||||
|
||||
return new Entry($dn, $attributes);
|
||||
}
|
||||
|
||||
private function cleanupAttributes(array $entry): array
|
||||
{
|
||||
$attributes = array_diff_key($entry, array_flip(range(0, $entry['count'] - 1)) + [
|
||||
'count' => null,
|
||||
'dn' => null,
|
||||
]);
|
||||
array_walk($attributes, function (&$value) {
|
||||
unset($value['count']);
|
||||
});
|
||||
|
||||
return $attributes;
|
||||
}
|
||||
}
|
189
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/ExtLdap/Connection.php
vendored
Normal file
189
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/ExtLdap/Connection.php
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Adapter\ExtLdap;
|
||||
|
||||
use LDAP\Connection as LDAPConnection;
|
||||
use Symfony\Component\Ldap\Adapter\AbstractConnection;
|
||||
use Symfony\Component\Ldap\Exception\AlreadyExistsException;
|
||||
use Symfony\Component\Ldap\Exception\ConnectionException;
|
||||
use Symfony\Component\Ldap\Exception\ConnectionTimeoutException;
|
||||
use Symfony\Component\Ldap\Exception\InvalidCredentialsException;
|
||||
use Symfony\Component\Ldap\Exception\LdapException;
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
/**
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
*/
|
||||
class Connection extends AbstractConnection
|
||||
{
|
||||
private const LDAP_INVALID_CREDENTIALS = 0x31;
|
||||
private const LDAP_TIMEOUT = 0x55;
|
||||
private const LDAP_ALREADY_EXISTS = 0x44;
|
||||
private const PRECONNECT_OPTIONS = [
|
||||
ConnectionOptions::DEBUG_LEVEL,
|
||||
ConnectionOptions::X_TLS_CACERTDIR,
|
||||
ConnectionOptions::X_TLS_CACERTFILE,
|
||||
ConnectionOptions::X_TLS_REQUIRE_CERT,
|
||||
];
|
||||
|
||||
private bool $bound = false;
|
||||
private ?LDAPConnection $connection = null;
|
||||
|
||||
public function __sleep(): array
|
||||
{
|
||||
throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function __wakeup()
|
||||
{
|
||||
throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
$this->disconnect();
|
||||
}
|
||||
|
||||
public function isBound(): bool
|
||||
{
|
||||
return $this->bound;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password WARNING: When the LDAP server allows unauthenticated binds, a blank $password will always be valid
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function bind(?string $dn = null, #[\SensitiveParameter] ?string $password = null)
|
||||
{
|
||||
if (!$this->connection) {
|
||||
$this->connect();
|
||||
}
|
||||
|
||||
if (false === @ldap_bind($this->connection, $dn, $password)) {
|
||||
$error = ldap_error($this->connection);
|
||||
switch (ldap_errno($this->connection)) {
|
||||
case self::LDAP_INVALID_CREDENTIALS:
|
||||
throw new InvalidCredentialsException($error);
|
||||
case self::LDAP_TIMEOUT:
|
||||
throw new ConnectionTimeoutException($error);
|
||||
case self::LDAP_ALREADY_EXISTS:
|
||||
throw new AlreadyExistsException($error);
|
||||
}
|
||||
throw new ConnectionException($error);
|
||||
}
|
||||
|
||||
$this->bound = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function getResource(): ?LDAPConnection
|
||||
{
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function setOption(string $name, array|string|int|bool $value)
|
||||
{
|
||||
if (!@ldap_set_option($this->connection, ConnectionOptions::getOption($name), $value)) {
|
||||
throw new LdapException(sprintf('Could not set value "%s" for option "%s".', $value, $name));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|string|int|null
|
||||
*/
|
||||
public function getOption(string $name)
|
||||
{
|
||||
if (!@ldap_get_option($this->connection, ConnectionOptions::getOption($name), $ret)) {
|
||||
throw new LdapException(sprintf('Could not retrieve value for option "%s".', $name));
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
parent::configureOptions($resolver);
|
||||
|
||||
$resolver->setDefault('debug', false);
|
||||
$resolver->setAllowedTypes('debug', 'bool');
|
||||
$resolver->setDefault('referrals', false);
|
||||
$resolver->setAllowedTypes('referrals', 'bool');
|
||||
$resolver->setDefault('options', function (OptionsResolver $options, Options $parent) {
|
||||
$options->setDefined(array_map('strtolower', array_keys((new \ReflectionClass(ConnectionOptions::class))->getConstants())));
|
||||
|
||||
if (true === $parent['debug']) {
|
||||
$options->setDefault('debug_level', 7);
|
||||
}
|
||||
|
||||
if (!isset($parent['network_timeout'])) {
|
||||
$options->setDefault('network_timeout', \ini_get('default_socket_timeout'));
|
||||
}
|
||||
|
||||
$options->setDefaults([
|
||||
'protocol_version' => $parent['version'],
|
||||
'referrals' => $parent['referrals'],
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
private function connect(): void
|
||||
{
|
||||
if ($this->connection) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this->config['options'] as $name => $value) {
|
||||
if (\in_array(ConnectionOptions::getOption($name), self::PRECONNECT_OPTIONS, true)) {
|
||||
$this->setOption($name, $value);
|
||||
}
|
||||
}
|
||||
|
||||
if (false === $connection = ldap_connect($this->config['connection_string'])) {
|
||||
throw new LdapException('Invalid connection string: '.$this->config['connection_string']);
|
||||
} else {
|
||||
$this->connection = $connection;
|
||||
}
|
||||
|
||||
foreach ($this->config['options'] as $name => $value) {
|
||||
if (!\in_array(ConnectionOptions::getOption($name), self::PRECONNECT_OPTIONS, true)) {
|
||||
$this->setOption($name, $value);
|
||||
}
|
||||
}
|
||||
|
||||
if ('tls' === $this->config['encryption'] && false === @ldap_start_tls($this->connection)) {
|
||||
throw new LdapException('Could not initiate TLS connection: '.ldap_error($this->connection));
|
||||
}
|
||||
}
|
||||
|
||||
private function disconnect(): void
|
||||
{
|
||||
if ($this->connection) {
|
||||
ldap_unbind($this->connection);
|
||||
}
|
||||
|
||||
$this->connection = null;
|
||||
$this->bound = false;
|
||||
}
|
||||
}
|
93
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/ExtLdap/ConnectionOptions.php
vendored
Normal file
93
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/ExtLdap/ConnectionOptions.php
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Adapter\ExtLdap;
|
||||
|
||||
use Symfony\Component\Ldap\Exception\LdapException;
|
||||
|
||||
/**
|
||||
* A class representing the Ldap extension's options, which can be used with
|
||||
* ldap_set_option or ldap_get_option.
|
||||
*
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class ConnectionOptions
|
||||
{
|
||||
public const API_INFO = 0x00;
|
||||
public const DEREF = 0x02;
|
||||
public const SIZELIMIT = 0x03;
|
||||
public const TIMELIMIT = 0x04;
|
||||
public const REFERRALS = 0x08;
|
||||
public const RESTART = 0x09;
|
||||
public const PROTOCOL_VERSION = 0x11;
|
||||
public const SERVER_CONTROLS = 0x12;
|
||||
public const CLIENT_CONTROLS = 0x13;
|
||||
public const API_FEATURE_INFO = 0x15;
|
||||
public const HOST_NAME = 0x30;
|
||||
public const ERROR_NUMBER = 0x31;
|
||||
public const ERROR_STRING = 0x32;
|
||||
public const MATCHED_DN = 0x33;
|
||||
public const DEBUG_LEVEL = 0x5001;
|
||||
public const TIMEOUT = 0x5002;
|
||||
public const NETWORK_TIMEOUT = 0x5005;
|
||||
public const X_TLS_CACERTFILE = 0x6002;
|
||||
public const X_TLS_CACERTDIR = 0x6003;
|
||||
public const X_TLS_CERTFILE = 0x6004;
|
||||
public const X_TLS_CRL_ALL = 0x02;
|
||||
public const X_TLS_CRL_NONE = 0x00;
|
||||
public const X_TLS_CRL_PEER = 0x01;
|
||||
public const X_TLS_KEYFILE = 0x6005;
|
||||
public const X_TLS_REQUIRE_CERT = 0x6006;
|
||||
public const X_TLS_PROTOCOL_MIN = 0x6007;
|
||||
public const X_TLS_CIPHER_SUITE = 0x6008;
|
||||
public const X_TLS_RANDOM_FILE = 0x6009;
|
||||
public const X_TLS_CRLFILE = 0x6010;
|
||||
public const X_TLS_PACKAGE = 0x6011;
|
||||
public const X_TLS_CRLCHECK = 0x600B;
|
||||
public const X_TLS_DHFILE = 0x600E;
|
||||
public const X_SASL_MECH = 0x6100;
|
||||
public const X_SASL_REALM = 0x6101;
|
||||
public const X_SASL_AUTHCID = 0x6102;
|
||||
public const X_SASL_AUTHZID = 0x6103;
|
||||
public const X_KEEPALIVE_IDLE = 0x6300;
|
||||
public const X_KEEPALIVE_PROBES = 0x6301;
|
||||
public const X_KEEPALIVE_INTERVAL = 0x6302;
|
||||
|
||||
public static function getOptionName(string $name): string
|
||||
{
|
||||
return sprintf('%s::%s', self::class, strtoupper($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches an option's corresponding constant value from an option name.
|
||||
* The option name can either be in snake or camel case.
|
||||
*
|
||||
* @throws LdapException
|
||||
*/
|
||||
public static function getOption(string $name): int
|
||||
{
|
||||
// Convert
|
||||
$constantName = self::getOptionName($name);
|
||||
|
||||
if (!\defined($constantName)) {
|
||||
throw new LdapException(sprintf('Unknown option "%s".', $name));
|
||||
}
|
||||
|
||||
return \constant($constantName);
|
||||
}
|
||||
|
||||
public static function isOption(string $name): bool
|
||||
{
|
||||
return \defined(self::getOptionName($name));
|
||||
}
|
||||
}
|
189
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/ExtLdap/EntryManager.php
vendored
Normal file
189
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/ExtLdap/EntryManager.php
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Adapter\ExtLdap;
|
||||
|
||||
use LDAP\Connection as LDAPConnection;
|
||||
use Symfony\Component\Ldap\Adapter\EntryManagerInterface;
|
||||
use Symfony\Component\Ldap\Entry;
|
||||
use Symfony\Component\Ldap\Exception\LdapException;
|
||||
use Symfony\Component\Ldap\Exception\NotBoundException;
|
||||
use Symfony\Component\Ldap\Exception\UpdateOperationException;
|
||||
|
||||
/**
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
* @author Bob van de Vijver <bobvandevijver@hotmail.com>
|
||||
*/
|
||||
class EntryManager implements EntryManagerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private Connection $connection,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function add(Entry $entry)
|
||||
{
|
||||
$con = $this->getConnectionResource();
|
||||
|
||||
if (!@ldap_add($con, $entry->getDn(), $entry->getAttributes())) {
|
||||
throw new LdapException(sprintf('Could not add entry "%s": ', $entry->getDn()).ldap_error($con), ldap_errno($con));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function update(Entry $entry)
|
||||
{
|
||||
$con = $this->getConnectionResource();
|
||||
|
||||
if (!@ldap_modify($con, $entry->getDn(), $entry->getAttributes())) {
|
||||
throw new LdapException(sprintf('Could not update entry "%s": ', $entry->getDn()).ldap_error($con), ldap_errno($con));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function remove(Entry $entry)
|
||||
{
|
||||
$con = $this->getConnectionResource();
|
||||
|
||||
if (!@ldap_delete($con, $entry->getDn())) {
|
||||
throw new LdapException(sprintf('Could not remove entry "%s": ', $entry->getDn()).ldap_error($con), ldap_errno($con));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds values to an entry's multi-valued attribute from the LDAP server.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws NotBoundException
|
||||
* @throws LdapException
|
||||
*/
|
||||
public function addAttributeValues(Entry $entry, string $attribute, array $values)
|
||||
{
|
||||
$con = $this->getConnectionResource();
|
||||
|
||||
if (!@ldap_mod_add($con, $entry->getDn(), [$attribute => $values])) {
|
||||
throw new LdapException(sprintf('Could not add values to entry "%s", attribute "%s": ', $entry->getDn(), $attribute).ldap_error($con), ldap_errno($con));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes values from an entry's multi-valued attribute from the LDAP server.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws NotBoundException
|
||||
* @throws LdapException
|
||||
*/
|
||||
public function removeAttributeValues(Entry $entry, string $attribute, array $values)
|
||||
{
|
||||
$con = $this->getConnectionResource();
|
||||
|
||||
if (!@ldap_mod_del($con, $entry->getDn(), [$attribute => $values])) {
|
||||
throw new LdapException(sprintf('Could not remove values from entry "%s", attribute "%s": ', $entry->getDn(), $attribute).ldap_error($con), ldap_errno($con));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function rename(Entry $entry, string $newRdn, bool $removeOldRdn = true)
|
||||
{
|
||||
$con = $this->getConnectionResource();
|
||||
|
||||
if (!@ldap_rename($con, $entry->getDn(), $newRdn, '', $removeOldRdn)) {
|
||||
throw new LdapException(sprintf('Could not rename entry "%s" to "%s": ', $entry->getDn(), $newRdn).ldap_error($con), ldap_errno($con));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves an entry on the Ldap server.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws NotBoundException if the connection has not been previously bound
|
||||
* @throws LdapException if an error is thrown during the rename operation
|
||||
*/
|
||||
public function move(Entry $entry, string $newParent)
|
||||
{
|
||||
$rdn = $this->parseRdnFromEntry($entry);
|
||||
$con = $this->getConnectionResource();
|
||||
// deleteOldRdn does not matter here, since the Rdn will not be changing in the move.
|
||||
if (!@ldap_rename($con, $entry->getDn(), $rdn, $newParent, true)) {
|
||||
throw new LdapException(sprintf('Could not move entry "%s" to "%s": ', $entry->getDn(), $newParent).ldap_error($con), ldap_errno($con));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the connection resource, but first check if the connection is bound.
|
||||
*/
|
||||
private function getConnectionResource(): LDAPConnection
|
||||
{
|
||||
// If the connection is not bound, throw an exception. Users should use an explicit bind call first.
|
||||
if (!$this->connection->isBound()) {
|
||||
throw new NotBoundException('Query execution is not possible without binding the connection first.');
|
||||
}
|
||||
|
||||
return $this->connection->getResource();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param iterable<int, UpdateOperation> $operations An array or iterable of UpdateOperation instances
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws UpdateOperationException in case of an error
|
||||
*/
|
||||
public function applyOperations(string $dn, iterable $operations)
|
||||
{
|
||||
$operationsMapped = [];
|
||||
foreach ($operations as $modification) {
|
||||
$operationsMapped[] = $modification->toArray();
|
||||
}
|
||||
|
||||
$con = $this->getConnectionResource();
|
||||
if (!@ldap_modify_batch($con, $dn, $operationsMapped)) {
|
||||
throw new UpdateOperationException(sprintf('Error executing UpdateOperation on "%s": ', $dn).ldap_error($con), ldap_errno($con));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function parseRdnFromEntry(Entry $entry): string
|
||||
{
|
||||
if (!preg_match('/(^[^,\\\\]*(?:\\\\.[^,\\\\]*)*),/', $entry->getDn(), $matches)) {
|
||||
throw new LdapException(sprintf('Entry "%s" malformed, could not parse RDN.', $entry->getDn()));
|
||||
}
|
||||
|
||||
return $matches[1];
|
||||
}
|
||||
}
|
209
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/ExtLdap/Query.php
vendored
Normal file
209
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/ExtLdap/Query.php
vendored
Normal file
@@ -0,0 +1,209 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Adapter\ExtLdap;
|
||||
|
||||
use LDAP\Result;
|
||||
use Symfony\Component\Ldap\Adapter\AbstractQuery;
|
||||
use Symfony\Component\Ldap\Adapter\CollectionInterface;
|
||||
use Symfony\Component\Ldap\Exception\LdapException;
|
||||
use Symfony\Component\Ldap\Exception\NotBoundException;
|
||||
|
||||
/**
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
* @author Bob van de Vijver <bobvandevijver@hotmail.com>
|
||||
*/
|
||||
class Query extends AbstractQuery
|
||||
{
|
||||
public const PAGINATION_OID = \LDAP_CONTROL_PAGEDRESULTS;
|
||||
|
||||
/** @var Result[] */
|
||||
private array $results;
|
||||
|
||||
private array $serverctrls = [];
|
||||
|
||||
public function __sleep(): array
|
||||
{
|
||||
throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function __wakeup()
|
||||
{
|
||||
throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
$con = $this->connection->getResource();
|
||||
|
||||
if (!isset($this->results)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this->results as $result) {
|
||||
if (false === $result || null === $result) {
|
||||
continue;
|
||||
}
|
||||
if (!ldap_free_result($result)) {
|
||||
throw new LdapException('Could not free results: '.ldap_error($con));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function execute(): CollectionInterface
|
||||
{
|
||||
if (!isset($this->results)) {
|
||||
// If the connection is not bound, throw an exception. Users should use an explicit bind call first.
|
||||
if (!$this->connection->isBound()) {
|
||||
throw new NotBoundException('Query execution is not possible without binding the connection first.');
|
||||
}
|
||||
|
||||
$this->results = [];
|
||||
$con = $this->connection->getResource();
|
||||
|
||||
$func = match ($this->options['scope']) {
|
||||
static::SCOPE_BASE => 'ldap_read',
|
||||
static::SCOPE_ONE => 'ldap_list',
|
||||
static::SCOPE_SUB => 'ldap_search',
|
||||
default => throw new LdapException(sprintf('Could not search in scope "%s".', $this->options['scope'])),
|
||||
};
|
||||
|
||||
$itemsLeft = $maxItems = $this->options['maxItems'];
|
||||
$pageSize = $this->options['pageSize'];
|
||||
// Deal with the logic to handle maxItems properly. If we can satisfy it in
|
||||
// one request based on pageSize, we don't need to bother sending page control
|
||||
// to the server so that it can determine what we already know.
|
||||
if (0 !== $maxItems && $pageSize > $maxItems) {
|
||||
$pageSize = 0;
|
||||
} elseif (0 !== $maxItems) {
|
||||
$pageSize = min($maxItems, $pageSize);
|
||||
}
|
||||
$pageControl = $this->options['scope'] != static::SCOPE_BASE && $pageSize > 0;
|
||||
$cookie = '';
|
||||
do {
|
||||
if ($pageControl) {
|
||||
$this->controlPagedResult($pageSize, true, $cookie);
|
||||
}
|
||||
$sizeLimit = $itemsLeft;
|
||||
if ($pageSize > 0 && $sizeLimit >= $pageSize) {
|
||||
$sizeLimit = 0;
|
||||
}
|
||||
$search = @$func($con, $this->dn, $this->query, $this->options['filter'], $this->options['attrsOnly'], $sizeLimit, $this->options['timeout'], $this->options['deref'], $this->serverctrls);
|
||||
|
||||
if (false === $search) {
|
||||
$ldapError = '';
|
||||
if ($errno = ldap_errno($con)) {
|
||||
$ldapError = sprintf(' LDAP error was [%d] %s', $errno, ldap_error($con));
|
||||
}
|
||||
if ($pageControl) {
|
||||
$this->resetPagination();
|
||||
}
|
||||
|
||||
throw new LdapException(sprintf('Could not complete search with dn "%s", query "%s" and filters "%s".%s.', $this->dn, $this->query, implode(',', $this->options['filter']), $ldapError), $errno);
|
||||
}
|
||||
|
||||
$this->results[] = $search;
|
||||
$itemsLeft -= min($itemsLeft, $pageSize);
|
||||
|
||||
if (0 !== $maxItems && 0 === $itemsLeft) {
|
||||
break;
|
||||
}
|
||||
if ($pageControl) {
|
||||
ldap_parse_result($con, $search, $errcode, $matcheddn, $errmsg, $referrals, $controls);
|
||||
|
||||
$cookie = $controls[\LDAP_CONTROL_PAGEDRESULTS]['value']['cookie'] ?? '';
|
||||
}
|
||||
} while (null !== $cookie && '' !== $cookie);
|
||||
|
||||
if ($pageControl) {
|
||||
$this->resetPagination();
|
||||
}
|
||||
}
|
||||
|
||||
return new Collection($this->connection, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an LDAP search resource. If this query resulted in multiple searches, only the first
|
||||
* page will be returned.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function getResource(int $idx = 0): ?Result
|
||||
{
|
||||
return $this->results[$idx] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all LDAP search resources.
|
||||
*
|
||||
* @return Result[]
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function getResources(): array
|
||||
{
|
||||
return $this->results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets pagination on the current connection.
|
||||
*/
|
||||
private function resetPagination(): void
|
||||
{
|
||||
$con = $this->connection->getResource();
|
||||
$this->controlPagedResult(0, false, '');
|
||||
$this->serverctrls = [];
|
||||
|
||||
// This is a workaround for a bit of a bug in the above invocation
|
||||
// of ldap_control_paged_result. Instead of indicating to extldap that
|
||||
// we no longer wish to page queries on this link, this invocation sets
|
||||
// the LDAP_CONTROL_PAGEDRESULTS OID with a page size of 0. This isn't
|
||||
// well defined by RFC 2696 if there is no cookie present, so some servers
|
||||
// will interpret it differently and do the wrong thing. Forcefully remove
|
||||
// the OID for now until a fix can make its way through the versions of PHP
|
||||
// the we support.
|
||||
//
|
||||
// This is not supported in PHP < 7.2, so these versions will remain broken.
|
||||
$ctl = [];
|
||||
ldap_get_option($con, \LDAP_OPT_SERVER_CONTROLS, $ctl);
|
||||
if (!empty($ctl)) {
|
||||
foreach ($ctl as $idx => $info) {
|
||||
if (static::PAGINATION_OID == $info['oid']) {
|
||||
unset($ctl[$idx]);
|
||||
}
|
||||
}
|
||||
ldap_set_option($con, \LDAP_OPT_SERVER_CONTROLS, $ctl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets LDAP pagination controls.
|
||||
*/
|
||||
private function controlPagedResult(int $pageSize, bool $critical, string $cookie): bool
|
||||
{
|
||||
$this->serverctrls = [
|
||||
[
|
||||
'oid' => \LDAP_CONTROL_PAGEDRESULTS,
|
||||
'isCritical' => $critical,
|
||||
'value' => [
|
||||
'size' => $pageSize,
|
||||
'cookie' => $cookie,
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
62
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/ExtLdap/UpdateOperation.php
vendored
Normal file
62
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/ExtLdap/UpdateOperation.php
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Adapter\ExtLdap;
|
||||
|
||||
use Symfony\Component\Ldap\Exception\UpdateOperationException;
|
||||
|
||||
class UpdateOperation
|
||||
{
|
||||
private int $operationType;
|
||||
private ?array $values;
|
||||
private string $attribute;
|
||||
|
||||
private const VALID_OPERATION_TYPES = [
|
||||
\LDAP_MODIFY_BATCH_ADD,
|
||||
\LDAP_MODIFY_BATCH_REMOVE,
|
||||
\LDAP_MODIFY_BATCH_REMOVE_ALL,
|
||||
\LDAP_MODIFY_BATCH_REPLACE,
|
||||
];
|
||||
|
||||
/**
|
||||
* @param int $operationType An LDAP_MODIFY_BATCH_* constant
|
||||
* @param string $attribute The attribute to batch modify on
|
||||
*
|
||||
* @throws UpdateOperationException on consistency errors during construction
|
||||
*/
|
||||
public function __construct(int $operationType, string $attribute, ?array $values)
|
||||
{
|
||||
if (!\in_array($operationType, self::VALID_OPERATION_TYPES, true)) {
|
||||
throw new UpdateOperationException(sprintf('"%s" is not a valid modification type.', $operationType));
|
||||
}
|
||||
if (\LDAP_MODIFY_BATCH_REMOVE_ALL === $operationType && null !== $values) {
|
||||
throw new UpdateOperationException(sprintf('$values must be null for LDAP_MODIFY_BATCH_REMOVE_ALL operation, "%s" given.', get_debug_type($values)));
|
||||
}
|
||||
|
||||
$this->operationType = $operationType;
|
||||
$this->attribute = $attribute;
|
||||
$this->values = $values;
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
$op = [
|
||||
'attrib' => $this->attribute,
|
||||
'modtype' => $this->operationType,
|
||||
];
|
||||
|
||||
if (\LDAP_MODIFY_BATCH_REMOVE_ALL !== $this->operationType) {
|
||||
$op['values'] = $this->values;
|
||||
}
|
||||
|
||||
return $op;
|
||||
}
|
||||
}
|
39
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/QueryInterface.php
vendored
Normal file
39
plugins/simplesaml/lib/vendor/symfony/ldap/Adapter/QueryInterface.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Adapter;
|
||||
|
||||
use Symfony\Component\Ldap\Exception\LdapException;
|
||||
use Symfony\Component\Ldap\Exception\NotBoundException;
|
||||
|
||||
/**
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
* @author Bob van de Vijver <bobvandevijver@hotmail.com>
|
||||
*/
|
||||
interface QueryInterface
|
||||
{
|
||||
public const DEREF_NEVER = 0x00;
|
||||
public const DEREF_SEARCHING = 0x01;
|
||||
public const DEREF_FINDING = 0x02;
|
||||
public const DEREF_ALWAYS = 0x03;
|
||||
|
||||
public const SCOPE_BASE = 'base';
|
||||
public const SCOPE_ONE = 'one';
|
||||
public const SCOPE_SUB = 'sub';
|
||||
|
||||
/**
|
||||
* Executes a query and returns the list of Ldap entries.
|
||||
*
|
||||
* @throws NotBoundException
|
||||
* @throws LdapException
|
||||
*/
|
||||
public function execute(): CollectionInterface;
|
||||
}
|
75
plugins/simplesaml/lib/vendor/symfony/ldap/CHANGELOG.md
vendored
Normal file
75
plugins/simplesaml/lib/vendor/symfony/ldap/CHANGELOG.md
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
6.2
|
||||
---
|
||||
|
||||
* Deprecate `{username}` parameter use in favour of `{user_identifier}`
|
||||
|
||||
6.1
|
||||
---
|
||||
|
||||
* Return a 500 Internal Server Error if LDAP server in unavailable during user enumeration / authentication
|
||||
* Introduce `InvalidSearchCredentialsException` to differentiate between cases where user-provided credentials are invalid and cases where the configured search credentials are invalid
|
||||
|
||||
6.0
|
||||
---
|
||||
|
||||
* Removed `LdapUser::getUsername()` method, use `getUserIdentifier()` instead
|
||||
* Removed `LdapUserProvider::loadUserByUsername()` method, use `loadUserByIdentifier()` instead
|
||||
|
||||
5.3
|
||||
---
|
||||
|
||||
* The authenticator system is no longer experimental
|
||||
* Added caseSensitive option for attribute keys in the Entry class.
|
||||
|
||||
5.1.0
|
||||
-----
|
||||
|
||||
* Added `Security\LdapBadge`, `Security\LdapAuthenticator` and `Security\CheckLdapCredentialsListener` to integrate with the authenticator Security system
|
||||
|
||||
5.0.0
|
||||
-----
|
||||
|
||||
* Added method `move() to `EntryManagerInterface`
|
||||
* Added pagination support to the ExtLdap adapter with the pageSize query option
|
||||
|
||||
4.4.0
|
||||
-----
|
||||
|
||||
* Added the "extra_fields" option, an array of custom fields to pull from the LDAP server
|
||||
|
||||
4.3.0
|
||||
-----
|
||||
|
||||
* Added `EntryManager::move`, not implementing it is deprecated
|
||||
* Added pagination support to the ExtLdap adapter with the pageSize query option
|
||||
|
||||
4.2.0
|
||||
-----
|
||||
|
||||
* Added `EntryManager::applyOperations`
|
||||
* Added timeout option to `ConnectionOptions`
|
||||
|
||||
4.1.0
|
||||
-----
|
||||
|
||||
* Added support for adding values to multi-valued attributes
|
||||
* Added support for removing values from multi-valued attributes
|
||||
|
||||
4.0.0
|
||||
-----
|
||||
|
||||
* Removed the `LdapClient` class and the `LdapClientInterface`
|
||||
* Removed the `RenameEntryInterface` interface and merged with `EntryManagerInterface`
|
||||
|
||||
3.3.0
|
||||
-----
|
||||
|
||||
* The `RenameEntryInterface` inferface is deprecated, and will be merged with `EntryManagerInterface` in 4.0.
|
||||
|
||||
3.1.0
|
||||
-----
|
||||
|
||||
* The `LdapClient` class is deprecated. Use the `Ldap` class instead.
|
127
plugins/simplesaml/lib/vendor/symfony/ldap/Entry.php
vendored
Normal file
127
plugins/simplesaml/lib/vendor/symfony/ldap/Entry.php
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap;
|
||||
|
||||
/**
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
* @author Karl Shea <karl@karlshea.com>
|
||||
*/
|
||||
class Entry
|
||||
{
|
||||
private string $dn;
|
||||
|
||||
/**
|
||||
* @var array<string, array>
|
||||
*/
|
||||
private array $attributes = [];
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
private array $lowerMap = [];
|
||||
|
||||
/**
|
||||
* @param array<string, array> $attributes
|
||||
*/
|
||||
public function __construct(string $dn, array $attributes = [])
|
||||
{
|
||||
$this->dn = $dn;
|
||||
|
||||
foreach ($attributes as $key => $attribute) {
|
||||
$this->setAttribute($key, $attribute);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entry's DN.
|
||||
*/
|
||||
public function getDn(): string
|
||||
{
|
||||
return $this->dn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an attribute exists.
|
||||
*
|
||||
* @param string $name The name of the attribute
|
||||
* @param bool $caseSensitive Whether the check should be case-sensitive
|
||||
*/
|
||||
public function hasAttribute(string $name, bool $caseSensitive = true): bool
|
||||
{
|
||||
$attributeKey = $this->getAttributeKey($name, $caseSensitive);
|
||||
|
||||
if (null === $attributeKey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isset($this->attributes[$attributeKey]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a specific attribute's value.
|
||||
*
|
||||
* As LDAP can return multiple values for a single attribute,
|
||||
* this value is returned as an array.
|
||||
*
|
||||
* @param string $name The name of the attribute
|
||||
* @param bool $caseSensitive Whether the attribute name is case-sensitive
|
||||
*/
|
||||
public function getAttribute(string $name, bool $caseSensitive = true): ?array
|
||||
{
|
||||
$attributeKey = $this->getAttributeKey($name, $caseSensitive);
|
||||
|
||||
if (null === $attributeKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->attributes[$attributeKey] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the complete list of attributes.
|
||||
*/
|
||||
public function getAttributes(): array
|
||||
{
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a value for the given attribute.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setAttribute(string $name, array $value)
|
||||
{
|
||||
$this->attributes[$name] = $value;
|
||||
$this->lowerMap[strtolower($name)] = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a given attribute.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function removeAttribute(string $name)
|
||||
{
|
||||
unset($this->attributes[$name]);
|
||||
unset($this->lowerMap[strtolower($name)]);
|
||||
}
|
||||
|
||||
private function getAttributeKey(string $name, bool $caseSensitive = true): ?string
|
||||
{
|
||||
if ($caseSensitive) {
|
||||
return $name;
|
||||
}
|
||||
|
||||
return $this->lowerMap[strtolower($name)] ?? null;
|
||||
}
|
||||
}
|
21
plugins/simplesaml/lib/vendor/symfony/ldap/Exception/AlreadyExistsException.php
vendored
Normal file
21
plugins/simplesaml/lib/vendor/symfony/ldap/Exception/AlreadyExistsException.php
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Exception;
|
||||
|
||||
/**
|
||||
* AlreadyExistsException is thrown if the element already exists.
|
||||
*
|
||||
* @author Hamza Amrouche <hamza.simperfit@gmail.com>
|
||||
*/
|
||||
class AlreadyExistsException extends ConnectionException
|
||||
{
|
||||
}
|
21
plugins/simplesaml/lib/vendor/symfony/ldap/Exception/ConnectionException.php
vendored
Normal file
21
plugins/simplesaml/lib/vendor/symfony/ldap/Exception/ConnectionException.php
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Exception;
|
||||
|
||||
/**
|
||||
* ConnectionException is thrown if binding to ldap cannot be established.
|
||||
*
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
*/
|
||||
class ConnectionException extends \RuntimeException implements ExceptionInterface
|
||||
{
|
||||
}
|
21
plugins/simplesaml/lib/vendor/symfony/ldap/Exception/ConnectionTimeoutException.php
vendored
Normal file
21
plugins/simplesaml/lib/vendor/symfony/ldap/Exception/ConnectionTimeoutException.php
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Exception;
|
||||
|
||||
/**
|
||||
* ConnectionTimeoutException is thrown if binding to ldap time out.
|
||||
*
|
||||
* @author Hamza Amrouche <hamza.simperfit@gmail.com>
|
||||
*/
|
||||
class ConnectionTimeoutException extends ConnectionException
|
||||
{
|
||||
}
|
21
plugins/simplesaml/lib/vendor/symfony/ldap/Exception/DriverNotFoundException.php
vendored
Normal file
21
plugins/simplesaml/lib/vendor/symfony/ldap/Exception/DriverNotFoundException.php
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Exception;
|
||||
|
||||
/**
|
||||
* LdapException is thrown if php ldap module is not loaded.
|
||||
*
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
*/
|
||||
class DriverNotFoundException extends \RuntimeException implements ExceptionInterface
|
||||
{
|
||||
}
|
21
plugins/simplesaml/lib/vendor/symfony/ldap/Exception/ExceptionInterface.php
vendored
Normal file
21
plugins/simplesaml/lib/vendor/symfony/ldap/Exception/ExceptionInterface.php
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Exception;
|
||||
|
||||
/**
|
||||
* Base ExceptionInterface for the Ldap component.
|
||||
*
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
*/
|
||||
interface ExceptionInterface extends \Throwable
|
||||
{
|
||||
}
|
21
plugins/simplesaml/lib/vendor/symfony/ldap/Exception/InvalidCredentialsException.php
vendored
Normal file
21
plugins/simplesaml/lib/vendor/symfony/ldap/Exception/InvalidCredentialsException.php
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Exception;
|
||||
|
||||
/**
|
||||
* InvalidCredentialsException is thrown if binding to ldap has been done with invalid credentials.
|
||||
*
|
||||
* @author Hamza Amrouche <hamza.simperfit@gmail.com>
|
||||
*/
|
||||
class InvalidCredentialsException extends ConnectionException
|
||||
{
|
||||
}
|
22
plugins/simplesaml/lib/vendor/symfony/ldap/Exception/InvalidSearchCredentialsException.php
vendored
Normal file
22
plugins/simplesaml/lib/vendor/symfony/ldap/Exception/InvalidSearchCredentialsException.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Exception;
|
||||
|
||||
/**
|
||||
* InvalidSearchCredentialsException is thrown if binding to ldap fails when
|
||||
* using the configured search_dn and search_password.
|
||||
*
|
||||
* @author Jeroen de Boer <info@jayfrown.nl>
|
||||
*/
|
||||
class InvalidSearchCredentialsException extends InvalidCredentialsException
|
||||
{
|
||||
}
|
21
plugins/simplesaml/lib/vendor/symfony/ldap/Exception/LdapException.php
vendored
Normal file
21
plugins/simplesaml/lib/vendor/symfony/ldap/Exception/LdapException.php
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Exception;
|
||||
|
||||
/**
|
||||
* LdapException is thrown if php ldap module is not loaded.
|
||||
*
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
*/
|
||||
class LdapException extends \RuntimeException implements ExceptionInterface
|
||||
{
|
||||
}
|
21
plugins/simplesaml/lib/vendor/symfony/ldap/Exception/NotBoundException.php
vendored
Normal file
21
plugins/simplesaml/lib/vendor/symfony/ldap/Exception/NotBoundException.php
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Exception;
|
||||
|
||||
/**
|
||||
* NotBoundException is thrown if the connection with the LDAP server is not yet bound.
|
||||
*
|
||||
* @author Bob van de Vijver <bobvandevijver@hotmail.com>
|
||||
*/
|
||||
class NotBoundException extends \RuntimeException implements ExceptionInterface
|
||||
{
|
||||
}
|
16
plugins/simplesaml/lib/vendor/symfony/ldap/Exception/UpdateOperationException.php
vendored
Normal file
16
plugins/simplesaml/lib/vendor/symfony/ldap/Exception/UpdateOperationException.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Exception;
|
||||
|
||||
class UpdateOperationException extends LdapException
|
||||
{
|
||||
}
|
19
plugins/simplesaml/lib/vendor/symfony/ldap/LICENSE
vendored
Normal file
19
plugins/simplesaml/lib/vendor/symfony/ldap/LICENSE
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2004-present Fabien Potencier
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
66
plugins/simplesaml/lib/vendor/symfony/ldap/Ldap.php
vendored
Normal file
66
plugins/simplesaml/lib/vendor/symfony/ldap/Ldap.php
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap;
|
||||
|
||||
use Symfony\Component\Ldap\Adapter\AdapterInterface;
|
||||
use Symfony\Component\Ldap\Adapter\EntryManagerInterface;
|
||||
use Symfony\Component\Ldap\Adapter\ExtLdap\Adapter;
|
||||
use Symfony\Component\Ldap\Adapter\QueryInterface;
|
||||
use Symfony\Component\Ldap\Exception\DriverNotFoundException;
|
||||
|
||||
/**
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
*/
|
||||
final class Ldap implements LdapInterface
|
||||
{
|
||||
private AdapterInterface $adapter;
|
||||
|
||||
public function __construct(AdapterInterface $adapter)
|
||||
{
|
||||
$this->adapter = $adapter;
|
||||
}
|
||||
|
||||
public function bind(?string $dn = null, #[\SensitiveParameter] ?string $password = null): void
|
||||
{
|
||||
$this->adapter->getConnection()->bind($dn, $password);
|
||||
}
|
||||
|
||||
public function query(string $dn, string $query, array $options = []): QueryInterface
|
||||
{
|
||||
return $this->adapter->createQuery($dn, $query, $options);
|
||||
}
|
||||
|
||||
public function getEntryManager(): EntryManagerInterface
|
||||
{
|
||||
return $this->adapter->getEntryManager();
|
||||
}
|
||||
|
||||
public function escape(string $subject, string $ignore = '', int $flags = 0): string
|
||||
{
|
||||
return $this->adapter->escape($subject, $ignore, $flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Ldap instance.
|
||||
*
|
||||
* @param string $adapter The adapter name
|
||||
* @param array $config The adapter's configuration
|
||||
*/
|
||||
public static function create(string $adapter, array $config = []): static
|
||||
{
|
||||
if ('ext_ldap' !== $adapter) {
|
||||
throw new DriverNotFoundException(sprintf('Adapter "%s" not found. Only "ext_ldap" is supported at the moment.', $adapter));
|
||||
}
|
||||
|
||||
return new self(new Adapter($config));
|
||||
}
|
||||
}
|
48
plugins/simplesaml/lib/vendor/symfony/ldap/LdapInterface.php
vendored
Normal file
48
plugins/simplesaml/lib/vendor/symfony/ldap/LdapInterface.php
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap;
|
||||
|
||||
use Symfony\Component\Ldap\Adapter\EntryManagerInterface;
|
||||
use Symfony\Component\Ldap\Adapter\QueryInterface;
|
||||
use Symfony\Component\Ldap\Exception\ConnectionException;
|
||||
|
||||
/**
|
||||
* Ldap interface.
|
||||
*
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
*/
|
||||
interface LdapInterface
|
||||
{
|
||||
public const ESCAPE_FILTER = 0x01;
|
||||
public const ESCAPE_DN = 0x02;
|
||||
|
||||
/**
|
||||
* Return a connection bound to the ldap.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws ConnectionException if dn / password could not be bound
|
||||
*/
|
||||
public function bind(?string $dn = null, #[\SensitiveParameter] ?string $password = null);
|
||||
|
||||
/**
|
||||
* Queries a ldap server for entries matching the given criteria.
|
||||
*/
|
||||
public function query(string $dn, string $query, array $options = []): QueryInterface;
|
||||
|
||||
public function getEntryManager(): EntryManagerInterface;
|
||||
|
||||
/**
|
||||
* Escape a string for use in an LDAP filter or DN.
|
||||
*/
|
||||
public function escape(string $subject, string $ignore = '', int $flags = 0): string;
|
||||
}
|
22
plugins/simplesaml/lib/vendor/symfony/ldap/README.md
vendored
Normal file
22
plugins/simplesaml/lib/vendor/symfony/ldap/README.md
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
Ldap Component
|
||||
==============
|
||||
|
||||
The LDAP component provides a LDAP client for PHP on top of PHP's ldap
|
||||
extension.
|
||||
|
||||
Disclaimer
|
||||
----------
|
||||
|
||||
This component is only stable since Symfony 3.1. Earlier versions
|
||||
have been marked as internal as they still needed some work.
|
||||
Breaking changes were introduced in Symfony 3.1, so code relying on
|
||||
previous version of the component will break with this version.
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
* [Documentation](https://symfony.com/doc/current/components/ldap)
|
||||
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
|
||||
* [Report issues](https://github.com/symfony/symfony/issues) and
|
||||
[send Pull Requests](https://github.com/symfony/symfony/pulls)
|
||||
in the [main Symfony repository](https://github.com/symfony/symfony)
|
115
plugins/simplesaml/lib/vendor/symfony/ldap/Security/CheckLdapCredentialsListener.php
vendored
Normal file
115
plugins/simplesaml/lib/vendor/symfony/ldap/Security/CheckLdapCredentialsListener.php
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Security;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\Ldap\Exception\InvalidCredentialsException;
|
||||
use Symfony\Component\Ldap\Exception\InvalidSearchCredentialsException;
|
||||
use Symfony\Component\Ldap\LdapInterface;
|
||||
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
|
||||
use Symfony\Component\Security\Core\Exception\LogicException;
|
||||
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
|
||||
use Symfony\Component\Security\Http\Event\CheckPassportEvent;
|
||||
|
||||
/**
|
||||
* Verifies password credentials using an LDAP service whenever the
|
||||
* LdapBadge is attached to the Security passport.
|
||||
*
|
||||
* @author Wouter de Jong <wouter@wouterj.nl>
|
||||
*/
|
||||
class CheckLdapCredentialsListener implements EventSubscriberInterface
|
||||
{
|
||||
private ContainerInterface $ldapLocator;
|
||||
|
||||
public function __construct(ContainerInterface $ldapLocator)
|
||||
{
|
||||
$this->ldapLocator = $ldapLocator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function onCheckPassport(CheckPassportEvent $event)
|
||||
{
|
||||
$passport = $event->getPassport();
|
||||
if (!$passport->hasBadge(LdapBadge::class)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var LdapBadge $ldapBadge */
|
||||
$ldapBadge = $passport->getBadge(LdapBadge::class);
|
||||
if ($ldapBadge->isResolved()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$passport->hasBadge(PasswordCredentials::class)) {
|
||||
throw new \LogicException(sprintf('LDAP authentication requires a passport containing password credentials, authenticator "%s" does not fulfill these requirements.', $event->getAuthenticator()::class));
|
||||
}
|
||||
|
||||
/** @var PasswordCredentials $passwordCredentials */
|
||||
$passwordCredentials = $passport->getBadge(PasswordCredentials::class);
|
||||
if ($passwordCredentials->isResolved()) {
|
||||
throw new \LogicException('LDAP authentication password verification cannot be completed because something else has already resolved the PasswordCredentials.');
|
||||
}
|
||||
|
||||
if (!$this->ldapLocator->has($ldapBadge->getLdapServiceId())) {
|
||||
throw new \LogicException(sprintf('Cannot check credentials using the "%s" ldap service, as such service is not found. Did you maybe forget to add the "ldap" service tag to this service?', $ldapBadge->getLdapServiceId()));
|
||||
}
|
||||
|
||||
$presentedPassword = $passwordCredentials->getPassword();
|
||||
if ('' === $presentedPassword) {
|
||||
throw new BadCredentialsException('The presented password cannot be empty.');
|
||||
}
|
||||
|
||||
$user = $passport->getUser();
|
||||
|
||||
/** @var LdapInterface $ldap */
|
||||
$ldap = $this->ldapLocator->get($ldapBadge->getLdapServiceId());
|
||||
try {
|
||||
if ($ldapBadge->getQueryString()) {
|
||||
if ('' !== $ldapBadge->getSearchDn() && '' !== $ldapBadge->getSearchPassword()) {
|
||||
try {
|
||||
$ldap->bind($ldapBadge->getSearchDn(), $ldapBadge->getSearchPassword());
|
||||
} catch (InvalidCredentialsException) {
|
||||
throw new InvalidSearchCredentialsException();
|
||||
}
|
||||
} else {
|
||||
throw new LogicException('Using the "query_string" config without using a "search_dn" and a "search_password" is not supported.');
|
||||
}
|
||||
$identifier = $ldap->escape($user->getUserIdentifier(), '', LdapInterface::ESCAPE_FILTER);
|
||||
$query = str_replace('{user_identifier}', $identifier, $ldapBadge->getQueryString());
|
||||
$result = $ldap->query($ldapBadge->getDnString(), $query)->execute();
|
||||
if (1 !== $result->count()) {
|
||||
throw new BadCredentialsException('The presented user identifier is invalid.');
|
||||
}
|
||||
|
||||
$dn = $result[0]->getDn();
|
||||
} else {
|
||||
$identifier = $ldap->escape($user->getUserIdentifier(), '', LdapInterface::ESCAPE_DN);
|
||||
$dn = str_replace('{user_identifier}', $identifier, $ldapBadge->getDnString());
|
||||
}
|
||||
|
||||
$ldap->bind($dn, $presentedPassword);
|
||||
} catch (InvalidCredentialsException) {
|
||||
throw new BadCredentialsException('The presented password is invalid.');
|
||||
}
|
||||
|
||||
$passwordCredentials->markResolved();
|
||||
$ldapBadge->markResolved();
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [CheckPassportEvent::class => ['onCheckPassport', 144]];
|
||||
}
|
||||
}
|
108
plugins/simplesaml/lib/vendor/symfony/ldap/Security/LdapAuthenticator.php
vendored
Normal file
108
plugins/simplesaml/lib/vendor/symfony/ldap/Security/LdapAuthenticator.php
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Security;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface;
|
||||
use Symfony\Component\Security\Http\Authenticator\InteractiveAuthenticatorInterface;
|
||||
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
|
||||
use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;
|
||||
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
|
||||
use Symfony\Component\Security\Http\EntryPoint\Exception\NotAnEntryPointException;
|
||||
|
||||
/**
|
||||
* This class decorates internal authenticators to add the LDAP integration.
|
||||
*
|
||||
* In your own authenticators, it is recommended to directly use the
|
||||
* LdapBadge in the authenticate() method. This class should only be
|
||||
* used for Symfony or third party authenticators.
|
||||
*
|
||||
* @author Wouter de Jong <wouter@wouterj.nl>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class LdapAuthenticator implements AuthenticationEntryPointInterface, InteractiveAuthenticatorInterface
|
||||
{
|
||||
private AuthenticatorInterface $authenticator;
|
||||
private string $ldapServiceId;
|
||||
private string $dnString;
|
||||
private string $searchDn;
|
||||
private string $searchPassword;
|
||||
private string $queryString;
|
||||
|
||||
public function __construct(AuthenticatorInterface $authenticator, string $ldapServiceId, string $dnString = '{user_identifier}', string $searchDn = '', string $searchPassword = '', string $queryString = '')
|
||||
{
|
||||
$this->authenticator = $authenticator;
|
||||
$this->ldapServiceId = $ldapServiceId;
|
||||
$this->dnString = $dnString;
|
||||
$this->searchDn = $searchDn;
|
||||
$this->searchPassword = $searchPassword;
|
||||
$this->queryString = $queryString;
|
||||
}
|
||||
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
return $this->authenticator->supports($request);
|
||||
}
|
||||
|
||||
public function authenticate(Request $request): Passport
|
||||
{
|
||||
$passport = $this->authenticator->authenticate($request);
|
||||
$passport->addBadge(new LdapBadge($this->ldapServiceId, $this->dnString, $this->searchDn, $this->searchPassword, $this->queryString));
|
||||
|
||||
return $passport;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function createAuthenticatedToken(PassportInterface $passport, string $firewallName): TokenInterface
|
||||
{
|
||||
throw new \BadMethodCallException(sprintf('The "%s()" method cannot be called.', __METHOD__));
|
||||
}
|
||||
|
||||
public function createToken(Passport $passport, string $firewallName): TokenInterface
|
||||
{
|
||||
return $this->authenticator->createToken($passport, $firewallName);
|
||||
}
|
||||
|
||||
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
|
||||
{
|
||||
return $this->authenticator->onAuthenticationSuccess($request, $token, $firewallName);
|
||||
}
|
||||
|
||||
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
|
||||
{
|
||||
return $this->authenticator->onAuthenticationFailure($request, $exception);
|
||||
}
|
||||
|
||||
public function start(Request $request, ?AuthenticationException $authException = null): Response
|
||||
{
|
||||
if (!$this->authenticator instanceof AuthenticationEntryPointInterface) {
|
||||
throw new NotAnEntryPointException(sprintf('Decorated authenticator "%s" does not implement interface "%s".', get_debug_type($this->authenticator), AuthenticationEntryPointInterface::class));
|
||||
}
|
||||
|
||||
return $this->authenticator->start($request, $authException);
|
||||
}
|
||||
|
||||
public function isInteractive(): bool
|
||||
{
|
||||
if ($this->authenticator instanceof InteractiveAuthenticatorInterface) {
|
||||
return $this->authenticator->isInteractive();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
85
plugins/simplesaml/lib/vendor/symfony/ldap/Security/LdapBadge.php
vendored
Normal file
85
plugins/simplesaml/lib/vendor/symfony/ldap/Security/LdapBadge.php
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Security;
|
||||
|
||||
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\BadgeInterface;
|
||||
|
||||
/**
|
||||
* A badge indicating that the credentials should be checked using LDAP.
|
||||
*
|
||||
* This badge must be used together with PasswordCredentials.
|
||||
*
|
||||
* @author Wouter de Jong <wouter@wouterj.nl>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class LdapBadge implements BadgeInterface
|
||||
{
|
||||
private bool $resolved = false;
|
||||
private string $ldapServiceId;
|
||||
private string $dnString;
|
||||
private string $searchDn;
|
||||
private string $searchPassword;
|
||||
private ?string $queryString;
|
||||
|
||||
public function __construct(string $ldapServiceId, string $dnString = '{user_identifier}', string $searchDn = '', string $searchPassword = '', ?string $queryString = null)
|
||||
{
|
||||
$this->ldapServiceId = $ldapServiceId;
|
||||
$dnString = str_replace('{username}', '{user_identifier}', $dnString, $replaceCount);
|
||||
if ($replaceCount > 0) {
|
||||
trigger_deprecation('symfony/ldap', '6.2', 'Using "{username}" parameter in LDAP configuration is deprecated, consider using "{user_identifier}" instead.');
|
||||
}
|
||||
$this->dnString = $dnString;
|
||||
$this->searchDn = $searchDn;
|
||||
$this->searchPassword = $searchPassword;
|
||||
$queryString = str_replace('{username}', '{user_identifier}', $queryString ?? '', $replaceCount);
|
||||
if ($replaceCount > 0) {
|
||||
trigger_deprecation('symfony/ldap', '6.2', 'Using "{username}" parameter in LDAP configuration is deprecated, consider using "{user_identifier}" instead.');
|
||||
}
|
||||
$this->queryString = $queryString;
|
||||
}
|
||||
|
||||
public function getLdapServiceId(): string
|
||||
{
|
||||
return $this->ldapServiceId;
|
||||
}
|
||||
|
||||
public function getDnString(): string
|
||||
{
|
||||
return $this->dnString;
|
||||
}
|
||||
|
||||
public function getSearchDn(): string
|
||||
{
|
||||
return $this->searchDn;
|
||||
}
|
||||
|
||||
public function getSearchPassword(): string
|
||||
{
|
||||
return $this->searchPassword;
|
||||
}
|
||||
|
||||
public function getQueryString(): ?string
|
||||
{
|
||||
return $this->queryString;
|
||||
}
|
||||
|
||||
public function markResolved(): void
|
||||
{
|
||||
$this->resolved = true;
|
||||
}
|
||||
|
||||
public function isResolved(): bool
|
||||
{
|
||||
return $this->resolved;
|
||||
}
|
||||
}
|
113
plugins/simplesaml/lib/vendor/symfony/ldap/Security/LdapUser.php
vendored
Normal file
113
plugins/simplesaml/lib/vendor/symfony/ldap/Security/LdapUser.php
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Security;
|
||||
|
||||
use Symfony\Component\Ldap\Entry;
|
||||
use Symfony\Component\Security\Core\User\EquatableInterface;
|
||||
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
|
||||
/**
|
||||
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class LdapUser implements UserInterface, PasswordAuthenticatedUserInterface, EquatableInterface
|
||||
{
|
||||
private Entry $entry;
|
||||
private string $identifier;
|
||||
private ?string $password;
|
||||
private array $roles;
|
||||
private array $extraFields;
|
||||
|
||||
public function __construct(Entry $entry, string $identifier, #[\SensitiveParameter] ?string $password, array $roles = [], array $extraFields = [])
|
||||
{
|
||||
if (!$identifier) {
|
||||
throw new \InvalidArgumentException('The username cannot be empty.');
|
||||
}
|
||||
|
||||
$this->entry = $entry;
|
||||
$this->identifier = $identifier;
|
||||
$this->password = $password;
|
||||
$this->roles = $roles;
|
||||
$this->extraFields = $extraFields;
|
||||
}
|
||||
|
||||
public function getEntry(): Entry
|
||||
{
|
||||
return $this->entry;
|
||||
}
|
||||
|
||||
public function getRoles(): array
|
||||
{
|
||||
return $this->roles;
|
||||
}
|
||||
|
||||
public function getPassword(): ?string
|
||||
{
|
||||
return $this->password;
|
||||
}
|
||||
|
||||
public function getSalt(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal for compatibility with Symfony 5.4
|
||||
*/
|
||||
public function getUsername(): string
|
||||
{
|
||||
return $this->getUserIdentifier();
|
||||
}
|
||||
|
||||
public function getUserIdentifier(): string
|
||||
{
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
public function eraseCredentials(): void
|
||||
{
|
||||
$this->password = null;
|
||||
}
|
||||
|
||||
public function getExtraFields(): array
|
||||
{
|
||||
return $this->extraFields;
|
||||
}
|
||||
|
||||
public function setPassword(#[\SensitiveParameter] string $password): void
|
||||
{
|
||||
$this->password = $password;
|
||||
}
|
||||
|
||||
public function isEqualTo(UserInterface $user): bool
|
||||
{
|
||||
if (!$user instanceof self) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->getPassword() !== $user->getPassword()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->getSalt() !== $user->getSalt()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->getUserIdentifier() !== $user->getUserIdentifier()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
189
plugins/simplesaml/lib/vendor/symfony/ldap/Security/LdapUserProvider.php
vendored
Normal file
189
plugins/simplesaml/lib/vendor/symfony/ldap/Security/LdapUserProvider.php
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Ldap\Security;
|
||||
|
||||
use Symfony\Component\Ldap\Entry;
|
||||
use Symfony\Component\Ldap\Exception\ExceptionInterface;
|
||||
use Symfony\Component\Ldap\Exception\InvalidCredentialsException;
|
||||
use Symfony\Component\Ldap\Exception\InvalidSearchCredentialsException;
|
||||
use Symfony\Component\Ldap\LdapInterface;
|
||||
use Symfony\Component\Security\Core\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
|
||||
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
|
||||
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||
use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
|
||||
/**
|
||||
* LdapUserProvider is a simple user provider on top of LDAP.
|
||||
*
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||
*
|
||||
* @template-implements UserProviderInterface<LdapUser>
|
||||
*/
|
||||
class LdapUserProvider implements UserProviderInterface, PasswordUpgraderInterface
|
||||
{
|
||||
private LdapInterface $ldap;
|
||||
private string $baseDn;
|
||||
private ?string $searchDn;
|
||||
private ?string $searchPassword;
|
||||
private array $defaultRoles;
|
||||
private ?string $uidKey;
|
||||
private string $defaultSearch;
|
||||
private ?string $passwordAttribute;
|
||||
private array $extraFields;
|
||||
|
||||
public function __construct(LdapInterface $ldap, string $baseDn, ?string $searchDn = null, #[\SensitiveParameter] ?string $searchPassword = null, array $defaultRoles = [], ?string $uidKey = null, ?string $filter = null, ?string $passwordAttribute = null, array $extraFields = [])
|
||||
{
|
||||
$uidKey ??= 'sAMAccountName';
|
||||
$filter ??= '({uid_key}={user_identifier})';
|
||||
|
||||
$this->ldap = $ldap;
|
||||
$this->baseDn = $baseDn;
|
||||
$this->searchDn = $searchDn;
|
||||
$this->searchPassword = $searchPassword;
|
||||
$this->defaultRoles = $defaultRoles;
|
||||
$this->uidKey = $uidKey;
|
||||
$this->defaultSearch = str_replace('{uid_key}', $uidKey, $filter);
|
||||
$this->passwordAttribute = $passwordAttribute;
|
||||
$this->extraFields = $extraFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal for compatibility with Symfony 5.4
|
||||
*/
|
||||
public function loadUserByUsername(string $username): UserInterface
|
||||
{
|
||||
return $this->loadUserByIdentifier($username);
|
||||
}
|
||||
|
||||
public function loadUserByIdentifier(string $identifier): UserInterface
|
||||
{
|
||||
try {
|
||||
$this->ldap->bind($this->searchDn, $this->searchPassword);
|
||||
} catch (InvalidCredentialsException) {
|
||||
throw new InvalidSearchCredentialsException();
|
||||
}
|
||||
|
||||
$identifier = $this->ldap->escape($identifier, '', LdapInterface::ESCAPE_FILTER);
|
||||
$query = str_replace('{username}', '{user_identifier}', $this->defaultSearch, $replaceCount);
|
||||
if ($replaceCount > 0) {
|
||||
trigger_deprecation('symfony/ldap', '6.2', 'Using "{username}" parameter in LDAP configuration is deprecated, consider using "{user_identifier}" instead.');
|
||||
}
|
||||
$query = str_replace('{user_identifier}', $identifier, $query);
|
||||
$search = $this->ldap->query($this->baseDn, $query, ['filter' => 0 == \count($this->extraFields) ? '*' : $this->extraFields]);
|
||||
|
||||
$entries = $search->execute();
|
||||
$count = \count($entries);
|
||||
|
||||
if (!$count) {
|
||||
$e = new UserNotFoundException(sprintf('User "%s" not found.', $identifier));
|
||||
$e->setUserIdentifier($identifier);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if ($count > 1) {
|
||||
$e = new UserNotFoundException('More than one user found.');
|
||||
$e->setUserIdentifier($identifier);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$entry = $entries[0];
|
||||
|
||||
try {
|
||||
if (null !== $this->uidKey) {
|
||||
$identifier = $this->getAttributeValue($entry, $this->uidKey);
|
||||
}
|
||||
} catch (InvalidArgumentException) {
|
||||
}
|
||||
|
||||
return $this->loadUser($identifier, $entry);
|
||||
}
|
||||
|
||||
public function refreshUser(UserInterface $user): UserInterface
|
||||
{
|
||||
if (!$user instanceof LdapUser) {
|
||||
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_debug_type($user)));
|
||||
}
|
||||
|
||||
return new LdapUser($user->getEntry(), $user->getUserIdentifier(), $user->getPassword(), $user->getRoles(), $user->getExtraFields());
|
||||
}
|
||||
|
||||
/**
|
||||
* @final
|
||||
*/
|
||||
public function upgradePassword(PasswordAuthenticatedUserInterface $user, string $newHashedPassword): void
|
||||
{
|
||||
if (!$user instanceof LdapUser) {
|
||||
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_debug_type($user)));
|
||||
}
|
||||
|
||||
if (null === $this->passwordAttribute) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$user->getEntry()->setAttribute($this->passwordAttribute, [$newHashedPassword]);
|
||||
$this->ldap->getEntryManager()->update($user->getEntry());
|
||||
$user->setPassword($newHashedPassword);
|
||||
} catch (ExceptionInterface) {
|
||||
// ignore failed password upgrades
|
||||
}
|
||||
}
|
||||
|
||||
public function supportsClass(string $class): bool
|
||||
{
|
||||
return LdapUser::class === $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a user from an LDAP entry.
|
||||
*/
|
||||
protected function loadUser(string $identifier, Entry $entry): UserInterface
|
||||
{
|
||||
$password = null;
|
||||
$extraFields = [];
|
||||
|
||||
if (null !== $this->passwordAttribute) {
|
||||
$password = $this->getAttributeValue($entry, $this->passwordAttribute);
|
||||
}
|
||||
|
||||
foreach ($this->extraFields as $field) {
|
||||
$extraFields[$field] = $this->getAttributeValue($entry, $field);
|
||||
}
|
||||
|
||||
return new LdapUser($entry, $identifier, $password, $this->defaultRoles, $extraFields);
|
||||
}
|
||||
|
||||
private function getAttributeValue(Entry $entry, string $attribute): mixed
|
||||
{
|
||||
if (!$entry->hasAttribute($attribute)) {
|
||||
throw new InvalidArgumentException(sprintf('Missing attribute "%s" for user "%s".', $attribute, $entry->getDn()));
|
||||
}
|
||||
|
||||
$values = $entry->getAttribute($attribute);
|
||||
if (!\in_array($attribute, [$this->uidKey, $this->passwordAttribute])) {
|
||||
return $values;
|
||||
}
|
||||
|
||||
if (1 !== \count($values)) {
|
||||
throw new InvalidArgumentException(sprintf('Attribute "%s" has multiple values.', $attribute));
|
||||
}
|
||||
|
||||
return $values[0];
|
||||
}
|
||||
}
|
39
plugins/simplesaml/lib/vendor/symfony/ldap/composer.json
vendored
Normal file
39
plugins/simplesaml/lib/vendor/symfony/ldap/composer.json
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "symfony/ldap",
|
||||
"type": "library",
|
||||
"description": "Provides a LDAP client for PHP on top of PHP's ldap extension",
|
||||
"keywords": ["ldap", "active-directory"],
|
||||
"homepage": "https://symfony.com",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Charles Sarrazin",
|
||||
"email": "charles@sarraz.in"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.1",
|
||||
"ext-ldap": "*",
|
||||
"symfony/deprecation-contracts": "^2.5|^3",
|
||||
"symfony/options-resolver": "^5.4|^6.0|^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/security-core": "^5.4|^6.0|^7.0",
|
||||
"symfony/security-http": "^5.4|^6.0|^7.0"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/options-resolver": "<5.4",
|
||||
"symfony/security-core": "<5.4"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "Symfony\\Component\\Ldap\\": "" },
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"minimum-stability": "dev"
|
||||
}
|
Reference in New Issue
Block a user