From 098c6e98d9e5177b62747772f3b7518c596939a0 Mon Sep 17 00:00:00 2001
From: Tim van Dijen <tvdijen@gmail.com>
Date: Wed, 15 May 2019 12:54:42 +0200
Subject: [PATCH] Externalize ldap (#1075)

* Externalize ldap

* Remove tests for LDAP-module

* Redirect old LDAP-class to ldap-module for backwards compatibility
---
 bin/build-release.sh                          |   1 +
 composer.json                                 |   1 +
 lib/SimpleSAML/Auth/LDAP.php                  | 874 +-----------------
 modules/ldap/default-enable                   |   3 -
 modules/ldap/docs/ldap.md                     | 581 ------------
 .../lib/Auth/Process/AttributeAddFromLDAP.php | 228 -----
 .../Auth/Process/AttributeAddUsersGroups.php  | 376 --------
 modules/ldap/lib/Auth/Process/BaseFilter.php  | 325 -------
 modules/ldap/lib/Auth/Source/LDAP.php         |  60 --
 modules/ldap/lib/Auth/Source/LDAPMulti.php    | 131 ---
 modules/ldap/lib/ConfigHelper.php             | 329 -------
 .../ldap/lib/Auth/Process/BaseFilterTest.php  |  27 -
 12 files changed, 28 insertions(+), 2908 deletions(-)
 delete mode 100644 modules/ldap/default-enable
 delete mode 100644 modules/ldap/docs/ldap.md
 delete mode 100644 modules/ldap/lib/Auth/Process/AttributeAddFromLDAP.php
 delete mode 100644 modules/ldap/lib/Auth/Process/AttributeAddUsersGroups.php
 delete mode 100644 modules/ldap/lib/Auth/Process/BaseFilter.php
 delete mode 100644 modules/ldap/lib/Auth/Source/LDAP.php
 delete mode 100644 modules/ldap/lib/Auth/Source/LDAPMulti.php
 delete mode 100644 modules/ldap/lib/ConfigHelper.php
 delete mode 100644 tests/modules/ldap/lib/Auth/Process/BaseFilterTest.php

diff --git a/bin/build-release.sh b/bin/build-release.sh
index 944878ed3..efe9cc8e0 100755
--- a/bin/build-release.sh
+++ b/bin/build-release.sh
@@ -57,6 +57,7 @@ php "$TARGET/composer.phar" require --update-no-dev simplesamlphp/simplesamlphp-
 php "$TARGET/composer.phar" require --update-no-dev simplesamlphp/simplesamlphp-module-cdc
 php "$TARGET/composer.phar" require --update-no-dev simplesamlphp/simplesamlphp-module-consent
 php "$TARGET/composer.phar" require --update-no-dev simplesamlphp/simplesamlphp-module-consentadmin
+php "$TARGET/composer.phar" require --update-no-dev simplesamlphp/simplesamlphp-module-ldap
 php "$TARGET/composer.phar" require --update-no-dev simplesamlphp/simplesamlphp-module-memcookie
 php "$TARGET/composer.phar" require --update-no-dev simplesamlphp/simplesamlphp-module-memcachemonitor
 php "$TARGET/composer.phar" require --update-no-dev simplesamlphp/simplesamlphp-module-negotiate
diff --git a/composer.json b/composer.json
index 90dfe66bf..5d77900a6 100644
--- a/composer.json
+++ b/composer.json
@@ -57,6 +57,7 @@
         "simplesamlphp/simplesamlphp-module-cdc": "^1.0",
         "simplesamlphp/simplesamlphp-module-consent": "^1.0",
         "simplesamlphp/simplesamlphp-module-consentadmin": "^1.0",
+        "simplesamlphp/simplesamlphp-module-ldap": "^1.0",
         "simplesamlphp/simplesamlphp-module-memcookie": "^1.2",
         "simplesamlphp/simplesamlphp-module-memcachemonitor": "^1.0",
         "simplesamlphp/simplesamlphp-module-negotiate": "^1.0",
diff --git a/lib/SimpleSAML/Auth/LDAP.php b/lib/SimpleSAML/Auth/LDAP.php
index 375c9f698..4124f2e46 100644
--- a/lib/SimpleSAML/Auth/LDAP.php
+++ b/lib/SimpleSAML/Auth/LDAP.php
@@ -2,858 +2,36 @@
 
 namespace SimpleSAML\Auth;
 
-use SimpleSAML\Error;
-use SimpleSAML\Logger;
+@trigger_error(sprintf('Using the "SimpleSAML\Auth\LDAP" class is deprecated, use "SimpleSAML\Module\ldap\Auth\Ldap" instead.'), E_USER_DEPRECATED);
 
 /**
- * Constants defining possible errors
+ * @deprecated To be removed in 2.0
  */
-
-define('ERR_INTERNAL', 1);
-define('ERR_NO_USER', 2);
-define('ERR_WRONG_PW', 3);
-define('ERR_AS_DATA_INCONSIST', 4);
-define('ERR_AS_INTERNAL', 5);
-define('ERR_AS_ATTRIBUTE', 6);
-
-// not defined in earlier PHP versions
-if (!defined('LDAP_OPT_DIAGNOSTIC_MESSAGE')) {
-    define('LDAP_OPT_DIAGNOSTIC_MESSAGE', 0x0032);
-}
-
-/**
- * The LDAP class holds helper functions to access an LDAP database.
- *
- * @author Andreas Aakre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
- * @author Anders Lund, UNINETT AS. <anders.lund@uninett.no>
- * @package SimpleSAMLphp
- */
-
-class LDAP
-{
-    /**
-     * LDAP link identifier.
-     *
-     * @var resource|null
-     */
-    protected $ldap = null;
-
-    /**
-     * LDAP user: authz_id if SASL is in use, binding dn otherwise
-     *
-     * @var string|null
-     */
-    protected $authz_id = null;
-
-    /**
-     * Timeout value, in seconds.
-     *
-     * @var int
-     */
-    protected $timeout = 0;
-
-    /**
-     * Private constructor restricts instantiation to getInstance().
-     *
-     * @param string $hostname
-     * @param bool $enable_tls
-     * @param bool $debug
-     * @param int $timeout
-     * @param int $port
-     * @param bool $referrals
-     * @psalm-suppress NullArgument
-     */
-    public function __construct(
-        $hostname,
-        $enable_tls = true,
-        $debug = false,
-        $timeout = 0,
-        $port = 389,
-        $referrals = true
-    ) {
-        // Debug
-        Logger::debug('Library - LDAP __construct(): Setup LDAP with '.
-            'host=\''.$hostname.
-            '\', tls='.var_export($enable_tls, true).
-            ', debug='.var_export($debug, true).
-            ', timeout='.var_export($timeout, true).
-            ', referrals='.var_export($referrals, true));
-
-        /*
-         * Set debug level before calling connect. Note that this passes
-         * NULL to ldap_set_option, which is an undocumented feature.
-         *
-         * OpenLDAP 2.x.x or Netscape Directory SDK x.x needed for this option.
-         */
-        if ($debug && !ldap_set_option(null, LDAP_OPT_DEBUG_LEVEL, 7)) {
-            Logger::warning('Library - LDAP __construct(): Unable to set debug level (LDAP_OPT_DEBUG_LEVEL) to 7');
-        }
-
-        /*
-         * Prepare a connection for to this LDAP server. Note that this function
-         * doesn't actually connect to the server.
-         */
-        $resource = @ldap_connect($hostname, $port);
-        if ($resource === false) {
-            throw $this->makeException(
-                'Library - LDAP __construct(): Unable to connect to \''.$hostname.'\'',
-                ERR_INTERNAL
-            );
-        }
-        $this->ldap = $resource;
-
-        // Enable LDAP protocol version 3
-        if (!@ldap_set_option($this->ldap, LDAP_OPT_PROTOCOL_VERSION, 3)) {
-            throw $this->makeException(
-                'Library - LDAP __construct(): Failed to set LDAP Protocol version (LDAP_OPT_PROTOCOL_VERSION) to 3',
-                ERR_INTERNAL
-            );
-        }
-
-        // Set referral option
-        if (!@ldap_set_option($this->ldap, LDAP_OPT_REFERRALS, $referrals)) {
-            throw $this->makeException(
-                'Library - LDAP __construct(): Failed to set LDAP Referrals (LDAP_OPT_REFERRALS) to '.$referrals,
-                ERR_INTERNAL
-            );
-        }
-
-        // Set timeouts, if supported
-        // (OpenLDAP 2.x.x or Netscape Directory SDK x.x needed)
-        $this->timeout = $timeout;
-        if ($timeout > 0) {
-            if (!@ldap_set_option($this->ldap, LDAP_OPT_NETWORK_TIMEOUT, $timeout)) {
-                Logger::warning(
-                    'Library - LDAP __construct(): Unable to set timeouts (LDAP_OPT_NETWORK_TIMEOUT) to '.$timeout
-                );
-            }
-            if (!@ldap_set_option($this->ldap, LDAP_OPT_TIMELIMIT, $timeout)) {
-                Logger::warning(
-                    'Library - LDAP __construct(): Unable to set timeouts (LDAP_OPT_TIMELIMIT) to '.$timeout
-                );
-            }
-        }
-
-        // Enable TLS, if needed
-        if (stripos($hostname, "ldaps:") === false && $enable_tls) {
-            if (!@ldap_start_tls($this->ldap)) {
-                throw $this->makeException('Library - LDAP __construct():'.
-                    ' Unable to force TLS', ERR_INTERNAL);
-            }
-        }
-    }
-
-
-    /**
-     * Convenience method to create an LDAPException as well as log the
-     * description.
-     *
-     * @param string $description The exception's description
-     * @param int|null $type The exception's type
-     * @return \Exception
-     */
-    private function makeException($description, $type = null)
-    {
-        $errNo = 0x00;
-
-        // Log LDAP code and description, if possible
-        if (empty($this->ldap)) {
-            Logger::error($description);
-        } else {
-            $errNo = @ldap_errno($this->ldap);
-        }
-
-        // Decide exception type and return
-        if ($type) {
-            if ($errNo !== 0) {
-                // Only log real LDAP errors; not success
-                Logger::error($description.'; cause: \''.ldap_error($this->ldap).'\' (0x'.dechex($errNo).')');
-            } else {
-                Logger::error($description);
-            }
-
-            switch ($type) {
-                case ERR_INTERNAL:// 1 - ExInternal
-                    return new Error\Exception($description, $errNo);
-                case ERR_NO_USER:// 2 - ExUserNotFound
-                    return new Error\UserNotFound($description, $errNo);
-                case ERR_WRONG_PW:// 3 - ExInvalidCredential
-                    return new Error\InvalidCredential($description, $errNo);
-                case ERR_AS_DATA_INCONSIST:// 4 - ExAsDataInconsist
-                    return new Error\AuthSource('ldap', $description);
-                case ERR_AS_INTERNAL:// 5 - ExAsInternal
-                    return new Error\AuthSource('ldap', $description);
-            }
-        } else {
-            if ($errNo !== 0) {
-                $description .= '; cause: \''.ldap_error($this->ldap).'\' (0x'.dechex($errNo).')';
-                if (@ldap_get_option($this->ldap, LDAP_OPT_DIAGNOSTIC_MESSAGE, $extendedError)
-                    && !empty($extendedError)
-                ) {
-                    $description .= '; additional: \''.$extendedError.'\'';
-                }
-            }
-            switch ($errNo) {
-                case 0x20://LDAP_NO_SUCH_OBJECT
-                    Logger::warning($description);
-                    return new Error\UserNotFound($description, $errNo);
-                case 0x31://LDAP_INVALID_CREDENTIALS
-                    Logger::info($description);
-                    return new Error\InvalidCredential($description, $errNo);
-                case -1://NO_SERVER_CONNECTION
-                    Logger::error($description);
-                    return new Error\AuthSource('ldap', $description);
-                default:
-                    Logger::error($description);
-                    return new Error\AuthSource('ldap', $description);
-            }
-        }
-        return new \Exception('Unknown LDAP error.');
-    }
-
-
-    /**
-     * Search for DN from a single base.
-     *
-     * @param string $base
-     * Indication of root of subtree to search
-     * @param string|array $attribute
-     * The attribute name(s) to search for.
-     * @param string $value
-     * The attribute value to search for.
-     * Additional search filter
-     * @param string|null $searchFilter
-     * The scope of the search
-     * @param string $scope
-     * @return string
-     * The DN of the resulting found element.
-     * @throws Error\Exception if:
-     * - Attribute parameter is wrong type
-     * @throws Error\AuthSource if:
-     * - Not able to connect to LDAP server
-     * - False search result
-     * - Count return false
-     * - Searche found more than one result
-     * - Failed to get first entry from result
-     * - Failed to get DN for entry
-     * @throws Error\UserNotFound if:
-     * - Zero entries were found
-     * @psalm-suppress TypeDoesNotContainType
-     */
-    private function search($base, $attribute, $value, $searchFilter = null, $scope = "subtree")
-    {
-        // Create the search filter
-        $attribute = self::escape_filter_value($attribute, false);
-        $value = self::escape_filter_value($value, true);
-        $filter = '';
-        foreach ($attribute as $attr) {
-            $filter .= '('.$attr.'='.$value.')';
-        }
-        $filter = '(|'.$filter.')';
-
-        // Append LDAP filters if defined
-        if ($searchFilter !== null) {
-            $filter = "(&".$filter."".$searchFilter.")";
-        }
-
-        // Search using generated filter
-        Logger::debug('Library - LDAP search(): Searching base ('.$scope.') \''.$base.'\' for \''.$filter.'\'');
-        if ($scope === 'base') {
-            $result = @ldap_read($this->ldap, $base, $filter, [], 0, 0, $this->timeout, LDAP_DEREF_NEVER);
-        } elseif ($scope === 'onelevel') {
-            $result = @ldap_list($this->ldap, $base, $filter, [], 0, 0, $this->timeout, LDAP_DEREF_NEVER);
-        } else {
-            $result = @ldap_search($this->ldap, $base, $filter, [], 0, 0, $this->timeout, LDAP_DEREF_NEVER);
-        }
-
-        if ($result === false) {
-            throw $this->makeException(
-                'Library - LDAP search(): Failed search on base \''.$base.'\' for \''.$filter.'\''
-            );
-        }
-
-        // Sanity checks on search results
-        $count = @ldap_count_entries($this->ldap, $result);
-        if ($count === false) {
-            throw $this->makeException('Library - LDAP search(): Failed to get number of entries returned');
-        } elseif ($count > 1) {
-            // More than one entry is found. External error
-            throw $this->makeException(
-                'Library - LDAP search(): Found '.$count.' entries searching base \''.$base.'\' for \''.$filter.'\'',
-                ERR_AS_DATA_INCONSIST
-            );
-        } elseif ($count === 0) {
-            // No entry is fond => wrong username is given (or not registered in the catalogue). User error
-            throw $this->makeException(
-                'Library - LDAP search(): Found no entries searching base \''.$base.'\' for \''.$filter.'\'',
-                ERR_NO_USER
-            );
-        }
-
-
-        // Resolve the DN from the search result
-        $entry = @ldap_first_entry($this->ldap, $result);
-        if ($entry === false) {
-            throw $this->makeException(
-                'Library - LDAP search(): Unable to retrieve result after searching base \''.
-                    $base.'\' for \''.$filter.'\''
-            );
-        }
-        $dn = @ldap_get_dn($this->ldap, $entry);
-        if ($dn === false) {
-            throw $this->makeException(
-                'Library - LDAP search(): Unable to get DN after searching base \''.$base.'\' for \''.$filter.'\''
-            );
-        }
-        return $dn;
-    }
-
-
-    /**
-     * Search for a DN.
-     *
-     * @param string|array $base
-     * The base, or bases, which to search from.
-     * @param string|array $attribute
-     * The attribute name(s) searched for.
-     * @param string $value
-     * The attribute value searched for.
-     * @param bool $allowZeroHits
-     * Determines if the method will throw an exception if no hits are found.
-     * Defaults to FALSE.
-     * @param string|null $searchFilter
-     * Additional searchFilter to be added to the (attribute=value) filter
-     * @param string $scope
-     * The scope of the search
-     * @return string|null
-     * The DN of the matching element, if found. If no element was found and
-     * $allowZeroHits is set to FALSE, an exception will be thrown; otherwise
-     * NULL will be returned.
-     * @throws Error\AuthSource if:
-     * - LDAP search encounter some problems when searching cataloge
-     * - Not able to connect to LDAP server
-     * @throws Error\UserNotFound if:
-     * - $allowZeroHits is FALSE and no result is found
-     *
-     */
-    public function searchfordn(
-        $base,
-        $attribute,
-        $value,
-        $allowZeroHits = false,
-        $searchFilter = null,
-        $scope = 'subtree'
-    ) {
-        // Traverse all search bases, returning DN if found
-        $bases = \SimpleSAML\Utils\Arrays::arrayize($base);
-        foreach ($bases as $current) {
-            try {
-                // Single base search
-                $result = $this->search($current, $attribute, $value, $searchFilter, $scope);
-
-                // We don't hawe to look any futher if user is found
-                if (!empty($result)) {
-                    return $result;
-                }
-                // If search failed, attempt the other base DNs
-            } catch (Error\UserNotFound $e) {
-                // Just continue searching
-            }
-        }
-        // Decide what to do for zero entries
-        Logger::debug('Library - LDAP searchfordn(): No entries found');
-        if ($allowZeroHits) {
-            // Zero hits allowed
-            return null;
-        } else {
-            // Zero hits not allowed
-            throw $this->makeException('Library - LDAP searchfordn(): LDAP search returned zero entries for'.
-                ' filter \'('.join(' | ', $attribute).' = '.$value.')\' on base(s) \'('.join(' & ', $bases).')\'', 2);
-        }
-    }
-
-
-    /**
-     * This method was created specifically for the ldap:AttributeAddUsersGroups->searchActiveDirectory()
-     * method, but could be used for other LDAP search needs. It will search LDAP and return all the entries.
-     *
-     * @throws \Exception
-     * @param string|array $bases
-     * @param string|array $filters Array of 'attribute' => 'values' to be combined into the filter,
-     *     or a raw filter string
-     * @param string|array $attributes Array of attributes requested from LDAP
-     * @param bool $and If multiple filters defined, then either bind them with & or |
-     * @param bool $escape Weather to escape the filter values or not
-     * @param string $scope The scope of the search
-     * @return array
-     */
-    public function searchformultiple(
-        $bases,
-        $filters,
-        $attributes = [],
-        $and = true,
-        $escape = true,
-        $scope = 'subtree'
-    ) {
-        // Escape the filter values, if requested
-        if ($escape) {
-            $filters = $this->escape_filter_value($filters, false);
-        }
-
-        // Build search filter
-        $filter = '';
-        if (is_array($filters)) {
-            foreach ($filters as $attribute => $value) {
-                $filter .= "($attribute=$value)";
-            }
-            if (count($filters) > 1) {
-                $filter = ($and ? '(&' : '(|').$filter.')';
-            }
-        } elseif (is_string($filters)) {
-            $filter = $filters;
-        }
-
-        // Verify filter was created
-        if ($filter == '' || $filter == '(=)') {
-            throw $this->makeException('ldap:LdapConnection->search_manual : No search filters defined', ERR_INTERNAL);
-        }
-
-        // Verify at least one base was passed
-        $bases = (array) $bases;
-        if (empty($bases)) {
-            throw $this->makeException('ldap:LdapConnection->search_manual : No base DNs were passed', ERR_INTERNAL);
-        }
-
-        $attributes = \SimpleSAML\Utils\Arrays::arrayize($attributes);
-
-        // Search each base until result is found
-        $result = false;
-        foreach ($bases as $base) {
-            if ($scope === 'base') {
-                $result = @ldap_read($this->ldap, $base, $filter, $attributes, 0, 0, $this->timeout);
-            } elseif ($scope === 'onelevel') {
-                $result = @ldap_list($this->ldap, $base, $filter, $attributes, 0, 0, $this->timeout);
-            } else {
-                $result = @ldap_search($this->ldap, $base, $filter, $attributes, 0, 0, $this->timeout);
-            }
-
-            if ($result !== false && @ldap_count_entries($this->ldap, $result) > 0) {
-                break;
-            }
-        }
-
-        // Verify that a result was found in one of the bases
-        if ($result === false) {
-            throw $this->makeException(
-                'ldap:LdapConnection->search_manual : Failed to search LDAP using base(s) ['.
-                implode('; ', $bases).'] with filter ['.$filter.']. LDAP error ['.
-                ldap_error($this->ldap).']'
-            );
-        } elseif (@ldap_count_entries($this->ldap, $result) < 1) {
-            throw $this->makeException(
-                'ldap:LdapConnection->search_manual : No entries found in LDAP using base(s) ['.
-                implode('; ', $bases).'] with filter ['.$filter.']',
-                ERR_NO_USER
-            );
-        }
-
-        // Get all results
-        $results = ldap_get_entries($this->ldap, $result);
-        if ($results === false) {
-            throw $this->makeException(
-                'ldap:LdapConnection->search_manual : Unable to retrieve entries from search results'
-            );
-        }
-
-        // parse each entry and process its attributes
-        for ($i = 0; $i < $results['count']; $i++) {
-            $entry = $results[$i];
-
-            // iterate over the attributes of the entry
-            for ($j = 0; $j < $entry['count']; $j++) {
-                $name = $entry[$j];
-                $attribute = $entry[$name];
-
-                // decide whether to base64 encode or not
-                for ($k = 0; $k < $attribute['count']; $k++) {
-                    // base64 encode binary attributes
-                    if (strtolower($name) === 'jpegphoto' || strtolower($name) === 'objectguid') {
-                        $results[$i][$name][$k] = base64_encode($attribute[$k]);
-                    }
-                }
-            }
-        }
-
-        // Remove the count and return
-        unset($results['count']);
-        return $results;
-    }
-
-
-    /**
-     * Bind to LDAP with a specific DN and password. Simple wrapper around
-     * ldap_bind() with some additional logging.
-     *
-     * @param string $dn
-     * The DN used.
-     * @param string $password
-     * The password used.
-     * @param array $sasl_args
-     * Array of SASL options for SASL bind
-     * @return bool
-     * Returns TRUE if successful, FALSE if
-     * LDAP_INVALID_CREDENTIALS, LDAP_X_PROXY_AUTHZ_FAILURE,
-     * LDAP_INAPPROPRIATE_AUTH, LDAP_INSUFFICIENT_ACCESS
-     * @throws Error\Exception on other errors
-     */
-    public function bind($dn, $password, array $sasl_args = null)
-    {
-        if ($sasl_args != null) {
-            if (!function_exists('ldap_sasl_bind')) {
-                $ex_msg = 'Library - missing SASL support';
-                throw $this->makeException($ex_msg);
-            }
-
-            // SASL Bind, with error handling
-            $authz_id = $sasl_args['authz_id'];
-            $error = @ldap_sasl_bind(
-                $this->ldap,
-                $dn,
-                $password,
-                $sasl_args['mech'],
-                $sasl_args['realm'],
-                $sasl_args['authc_id'],
-                $sasl_args['authz_id'],
-                $sasl_args['props']
-            );
-        } else {
-            // Simple Bind, with error handling
-            $authz_id = $dn;
-            $error = @ldap_bind($this->ldap, $dn, $password);
-        }
-
-        if ($error === true) {
-            // Good
-            $this->authz_id = $authz_id;
-            Logger::debug('Library - LDAP bind(): Bind successful with DN \''.$dn.'\'');
-            return true;
-        }
-
-        /* Handle errors
-         * LDAP_INVALID_CREDENTIALS
-         * LDAP_INSUFFICIENT_ACCESS */
-        switch (ldap_errno($this->ldap)) {
-            case 32: // LDAP_NO_SUCH_OBJECT
-                // no break
-            case 47: // LDAP_X_PROXY_AUTHZ_FAILURE
-                // no break
-            case 48: // LDAP_INAPPROPRIATE_AUTH
-                // no break
-            case 49: // LDAP_INVALID_CREDENTIALS
-                // no break
-            case 50: // LDAP_INSUFFICIENT_ACCESS
-                return false;
-            default:
-                break;
-        }
-
-        // Bad
-        throw $this->makeException('Library - LDAP bind(): Bind failed with DN \''.$dn.'\'');
-    }
-
-
-    /**
-     * Applies an LDAP option to the current connection.
-     *
-     * @throws Exception
-     * @param mixed $option
-     * @param mixed $value
-     * @return void
-     */
-    public function setOption($option, $value)
-    {
-        // Attempt to set the LDAP option
-        if (!@ldap_set_option($this->ldap, $option, $value)) {
-            throw $this->makeException(
-                'ldap:LdapConnection->setOption : Failed to set LDAP option ['.
-                $option.'] with the value ['.$value.'] error: '.ldap_error($this->ldap),
-                ERR_INTERNAL
-            );
-        }
-
-        // Log debug message
-        Logger::debug(
-            'ldap:LdapConnection->setOption : Set the LDAP option ['.
-            $option.'] with the value ['.$value.']'
-        );
-    }
-
-
-    /**
-     * Search a given DN for attributes, and return the resulting associative
-     * array.
-     *
-     * @param string $dn
-     * The DN of an element.
-     * @param string|array $attributes
-     * The names of the attribute(s) to retrieve. Defaults to NULL; that is,
-     * all available attributes. Note that this is not very effective.
-     * @param int $maxsize
-     * The maximum size of any attribute's value(s). If exceeded, the attribute
-     * will not be returned.
-     * @return array
-     * The array of attributes and their values.
-     * @see http://no.php.net/manual/en/function.ldap-read.php
-     */
-    public function getAttributes($dn, $attributes = null, $maxsize = null)
-    {
-        // Preparations, including a pretty debug message...
-        $description = 'all attributes';
-        if (is_array($attributes)) {
-            $description = '\''.join(',', $attributes).'\'';
-        } else {
-            // Get all attributes...
-            // TODO: Verify that this originally was the intended behaviour. Could $attributes be a string?
-            $attributes = [];
-        }
-        Logger::debug('Library - LDAP getAttributes(): Getting '.$description.' from DN \''.$dn.'\'');
-
-        // Attempt to get attributes
-        // TODO: Should aliases be dereferenced?
-        /** @var array $attributes */
-        $result = @ldap_read($this->ldap, $dn, 'objectClass=*', $attributes, 0, 0, $this->timeout);
-        if ($result === false) {
-            throw $this->makeException('Library - LDAP getAttributes(): Failed to get attributes from DN \''.$dn.'\'');
-        }
-        $entry = @ldap_first_entry($this->ldap, $result);
-        if ($entry === false) {
-            throw $this->makeException('Library - LDAP getAttributes(): Could not get first entry from DN \''.$dn.'\'');
-        }
-        $attributes = @ldap_get_attributes($this->ldap, $entry); // Recycling $attributes... Possibly bad practice.
-        if ($attributes === false) {
-            throw $this->makeException(
-                'Library - LDAP getAttributes(): Could not get attributes of first entry from DN \''.$dn.'\''
-            );
-        }
-
-        // Parsing each found attribute into our result set
-        $result = []; // Recycling $result... Possibly bad practice.
-        for ($i = 0; $i < $attributes['count']; $i++) {
-            // Ignore attributes that exceed the maximum allowed size
-            $name = $attributes[$i];
-            $attribute = $attributes[$name];
-
-            // Deciding whether to base64 encode
-            $values = [];
-            for ($j = 0; $j < $attribute['count']; $j++) {
-                $value = $attribute[$j];
-
-                if (!empty($maxsize) && strlen($value) > $maxsize) {
-                    // Ignoring and warning
-                    Logger::warning('Library - LDAP getAttributes(): Attribute \''.
-                        $name.'\' exceeded maximum allowed size by '.(strlen($value) - $maxsize));
-                    continue;
-                }
-
-                // Base64 encode binary attributes
-                if (strtolower($name) === 'jpegphoto'
-                    || strtolower($name) === 'objectguid'
-                    || strtolower($name) === 'ms-ds-consistencyguid'
-                ) {
-                    $values[] = base64_encode($value);
-                } else {
-                    $values[] = $value;
-                }
-            }
-
-            // Adding
-            $result[$name] = $values;
-        }
-
-        // We're done
-        Logger::debug('Library - LDAP getAttributes(): Found attributes \'('.join(',', array_keys($result)).')\'');
-        return $result;
-    }
-
-
-    /**
-     * Enter description here...
-     *
-     * @param array $config
-     * @param string $username
-     * @param string $password
-     * @return array|false
-     */
-    public function validate($config, $username, $password = null)
+if (class_exists('\SimpleSAML\Module\ldap\Auth\Ldap')) {
+    class LDAP extends \SimpleSAML\Module\ldap\Auth\Ldap
     {
         /**
-         * Escape any characters with a special meaning in LDAP. The following
-         * characters have a special meaning (according to RFC 2253):
-         * ',', '+', '"', '\', '<', '>', ';', '*'
-         * These characters are escaped by prefixing them with '\'.
-         */
-        $username = addcslashes($username, ',+"\\<>;*');
-
-        if (isset($config['priv_user_dn'])) {
-            $this->bind($config['priv_user_dn'], $config['priv_user_pw']);
-        }
-        if (isset($config['dnpattern'])) {
-            $dn = str_replace('%username%', $username, $config['dnpattern']);
-        } else {
-            $dn = $this->searchfordn($config['searchbase'], $config['searchattributes'], $username);
-        }
-
-        if ($password !== null) {
-            // checking users credentials ... assuming below that she may read her own attributes ...
-            // escape characters with a special meaning, also in the password
-            $password = addcslashes($password, ',+"\\<>;*');
-            if (!$this->bind($dn, $password)) {
-                Logger::info(
-                    'Library - LDAP validate(): Failed to authenticate \''.$username.'\' using DN \''.$dn.'\''
-                );
-                return false;
-            }
-        }
-
-        /**
-         * Retrieve attributes from LDAP
+         * Private constructor restricts instantiation to getInstance().
+         *
+         * @param string $hostname
+         * @param bool $enable_tls
+         * @param bool $debug
+         * @param int $timeout
+         * @param int $port
+         * @param bool $referrals
+         * @psalm-suppress NullArgument
          */
-        $attributes = $this->getAttributes($dn, $config['attributes']);
-        return $attributes;
-    }
-
-
-    /**
-     * Borrowed function from PEAR:LDAP.
-     *
-     * Escapes the given VALUES according to RFC 2254 so that they can be safely used in LDAP filters.
-     *
-     * Any control characters with an ACII code < 32 as well as the characters with special meaning in
-     * LDAP filters "*", "(", ")", and "\" (the backslash) are converted into the representation of a
-     * backslash followed by two hex digits representing the hexadecimal value of the character.
-     *
-     * @static
-     * @param string|array $values Array of values to escape
-     * @param bool $singleValue
-     * @return array Array $values, but escaped
-     */
-    public static function escape_filter_value($values = [], $singleValue = true)
-    {
-        // Parameter validation
-        $values = \SimpleSAML\Utils\Arrays::arrayize($values);
-
-        foreach ($values as $key => $val) {
-            if ($val === null) {
-                $val = '\0'; // apply escaped "null" if string is empty
-            } else {
-                // Escaping of filter meta characters
-                $val = str_replace('\\', '\5c', $val);
-                $val = str_replace('*', '\2a', $val);
-                $val = str_replace('(', '\28', $val);
-                $val = str_replace(')', '\29', $val);
-
-                // ASCII < 32 escaping
-                $val = self::asc2hex32($val);
-            }
-
-            $values[$key] = $val;
-        }
-        if ($singleValue) {
-            return $values[0];
-        }
-        return $values;
-    }
-
-
-    /**
-     * Borrowed function from PEAR:LDAP.
-     *
-     * Converts all ASCII chars < 32 to "\HEX"
-     *
-     * @param string $string String to convert
-     *
-     * @static
-     * @return string
-     */
-    public static function asc2hex32($string)
-    {
-        for ($i = 0; $i < strlen($string); $i++) {
-            $char = substr($string, $i, 1);
-            if (ord($char) < 32) {
-                $hex = dechex(ord($char));
-                if (strlen($hex) == 1) {
-                    $hex = '0'.$hex;
-                }
-                $string = str_replace($char, '\\'.$hex, $string);
-            }
-        }
-        return $string;
-    }
-
-    /**
-     * Convert SASL authz_id into a DN
-     *
-     * @param string $searchBase
-     * @param array $searchAttributes
-     * @param string $authz_id
-     * @return string|null
-     */
-    private function authzidToDn($searchBase, $searchAttributes, $authz_id)
-    {
-        if (preg_match("/^dn:/", $authz_id)) {
-            return preg_replace("/^dn:/", "", $authz_id);
-        }
-
-        if (preg_match("/^u:/", $authz_id)) {
-            return $this->searchfordn(
-                $searchBase,
-                $searchAttributes,
-                preg_replace("/^u:/", "", $authz_id)
-            );
-        }
-        return $authz_id;
-    }
-
-    /**
-     * ldap_exop_whoami accessor, if available. Use requested authz_id
-     * otherwise.
-     *
-     * ldap_exop_whoami() has been provided as a third party patch that
-     * waited several years to get its way upstream:
-     * http://cvsweb.netbsd.org/bsdweb.cgi/pkgsrc/databases/php-ldap/files
-     *
-     * When it was integrated into PHP repository, the function prototype
-     * was changed, The new prototype was used in third party patch for
-     * PHP 7.0 and 7.1, hence the version test below.
-     *
-     * @param string $searchBase
-     * @param array $searchAttributes
-     * @throws \Exception
-     * @return string|null
-     */
-    public function whoami($searchBase, $searchAttributes)
-    {
-        $authz_id = '';
-        if (function_exists('ldap_exop_whoami')) {
-            if (version_compare(phpversion(), '7', '<')) {
-                if (ldap_exop_whoami($this->ldap, $authz_id) !== true) {
-                    throw $this->makeException('LDAP whoami exop failure');
-                }
-            } else {
-                if (($authz_id = ldap_exop_whoami($this->ldap)) === false) {
-                    throw $this->makeException('LDAP whoami exop failure');
-                }
-            }
-        } else {
-            $authz_id = $this->authz_id;
-        }
-
-        $dn = $this->authzidToDn($searchBase, $searchAttributes, $authz_id);
-
-        if (!isset($dn) || ($dn == '')) {
-            throw $this->makeException('Cannot figure userID');
-        }
-
-        return $dn;
-    }
+        public function __construct(
+            $hostname,
+            $enable_tls = true,
+            $debug = false,
+            $timeout = 0,
+            $port = 389,
+            $referrals = true
+        ) {
+            parent::__construct($hostname, $enable_tls, $debug, $timeout, $port, $referrals);
+        }
+    }
+} else {
+    throw new \Exception('Missing ldap-module');
 }
diff --git a/modules/ldap/default-enable b/modules/ldap/default-enable
deleted file mode 100644
index 25615cb47..000000000
--- a/modules/ldap/default-enable
+++ /dev/null
@@ -1,3 +0,0 @@
-This file indicates that the default state of this module
-is enabled. To disable, create a file named disable in the
-same directory as this file.
diff --git a/modules/ldap/docs/ldap.md b/modules/ldap/docs/ldap.md
deleted file mode 100644
index 1bad69582..000000000
--- a/modules/ldap/docs/ldap.md
+++ /dev/null
@@ -1,581 +0,0 @@
-LDAP module
-===========
-
-The LDAP module provides a method for authenticating users against an
-LDAP server. There are two separate authentication modules and two
-authentication processing filters:
-
-
-`ldap:LDAP`
-: Authenticate the user against a single LDAP server.
-
-`ldap:LDAPMulti`
-: Allow the user to chose one LDAP server to authenticate against.
-
-`ldap:AttributeAddFromLDAP`
-: Adds an attribute value from LDAP to the request
-
-`ldap:AttributeAddUsersGroups`
-: Add an attribute to the request with all the user's group memberships
-
-`ldap:LDAP`
------------
-
-This module is used when you have an organization with a single LDAP
-server with all the users. To create an LDAP authentication source, open
-`config/authsources.php` in a text editor, and add an entry for the
-authentication source:
-
-	'example-ldap' => array(
-		'ldap:LDAP',
-
-		/* The hostname of the LDAP server. */
-		'hostname' => 'ldap.example.org',
-
-		/* Whether SSL/TLS should be used when contacting the LDAP server. */
-		'enable_tls' => FALSE,
-
-		/*
-		 * Which attributes should be retrieved from the LDAP server.
-		 * This can be an array of attribute names, or NULL, in which case
-		 * all attributes are fetched.
-		 */
-		'attributes' => NULL,
-
-		/*
-		 * The pattern which should be used to create the user's DN given the username.
-		 * %username% in this pattern will be replaced with the user's username.
-		 *
-		 * This option is not used if the search.enable option is set to TRUE.
-		 */
-		'dnpattern' => 'uid=%username%,ou=people,dc=example,dc=org',
-
-		/*
-		 * As an alternative to specifying a pattern for the users DN, it is possible to
-		 * search for the username in a set of attributes. This is enabled by this option.
-		 */
-		'search.enable' => FALSE,
-
-		/*
-		 * The DN which will be used as a base for the search.
-		 * This can be a single string, in which case only that DN is searched, or an
-		 * array of strings, in which case they will be searched in the order given.
-		 */
-		'search.base' => 'ou=people,dc=example,dc=org',
-
-                /*
-                 * The scope of the search. Valid values are 'subtree' and 'onelevel' and 'base',
-                 * first one being the default if no value is set.
-                 */
-                'search.scope' => 'subtree',
-
-		/*
-		 * The attribute(s) the username should match against.
-		 *
-		 * This is an array with one or more attribute names. Any of the attributes in
-		 * the array may match the value the username.
-		 */
-		'search.attributes' => array('uid', 'mail'),
-
-		/*
-		 * Additional filters that must match for the entire LDAP search to be TRUE
-		 *
-		 * This should be a single string conforming to (RFC 1960, 2544)
-		 * The string is appended to the search attributes
-		 */
-		'search.filter' => '(&(objectClass=Person)(|(sn=Doe)(cn=John *)))',
-
-		/*
-		 * The username & password where SimpleSAMLphp should bind to before searching. If
-		 * this is left NULL, no bind will be performed before searching.
-		 */
-		'search.username' => NULL,
-		'search.password' => NULL,
-	),
-
-
-You should update the name of this authentication source
-(`example-ldap`) to have a name which makes sense to your organization.
-You also need to update the `hostname` and `dnpattern` options. The
-`hostname` should be the hostname of your LDAP server, and the
-`dnpattern` should be a pattern which can be used to generate the `dn`
-of a user with a given username.
--
-All other options have default values, and are not required.
-
-### Searching for a user ###
-
-Sometimes you cannot generate the user's `dn` from the username, or you
-may want to allow the user to authenticate with for example their email
-address as the username. In this case, you can configure the LDAP
-module to search for the users `dn` by searching for the username in
-one or more attributes.
-
-To enable searching, you must set the `search.enable` option to `TRUE`.
-You must then configure the `search.base` and the `search.attributes`
-options. The `search.base`-option must be the `dn` which should be used
-as the base/root of the search. The `search.attributes`-option is an
-array with attributes the username should be matched against.
-
-You can also append the `search.filter` option to further limit your search.
-The `search.filter` field is optional and need not be included in your
-configuration file.
-
-The `dnpattern` option will not be used if searching is enabled.
-
-Some LDAP servers may require authentication before a search can be
-performed. In this case, you should configure the `search.username`
-and `search.password` options. The `search.username` option is a `dn`
-which can be used to perform a search, and the `search.password` option
-is the password for that `dn`.
-
-### Configuring failover ###
-
-You can configure multiple LDAP servers in the hostname option by separating the individual hosts with a space.
-This enables the builtin LDAP failover in OpenLDAP.
-
-Note that OpenLDAP waits for a timeout from the first server before attempting to connect to the other.
-To avoid a very long wait, it is recommended to change the timeouts.
-This can be done in the system-wide ldap configuration file.
-
-    NETWORK_TIMEOUT 10
-    TIMELIMIT       15
-    TIMEOUT         20
-
-In this case, if we are unable to connect to the first LDAP server within 10 seconds, we will attempt the next.
-(Note: the NETWORK_TIMEOUT option was introduced with OpenLDAP version 2.4.)
-
-#### Example ####
-
-    /* Configuration that uses two ldap servers. */
-    'example-ldap' => array(
-        'ldap:LDAP',
-        /* The hostname of the LDAP server. */
-        'hostname' => 'ldaps://ldap1.example.org ldaps://ldap2.example.org',
-        'dnpattern' => 'uid=%username%,ou=people,dc=example,dc=org',
-    ),
-
-
-`ldap:LDAPMulti`
-----------------
-
-This module can be used if your organization has separate groups with
-separate LDAP servers or separate LDAP configurations. To use this
-authentication module, open `config/authsources.php` in a text editor,
-and add an entry which uses this module:
-
-	'example-ldapmulti' => array(
-		'ldap:LDAPMulti',
-
-		/*
-		 * The way the organization as part of the username should be handled.
-		 * Three possible values:
-		 * - 'none':   No handling of the organization. Allows '@' to be part
-		 *             of the username.
-		 * - 'allow':  Will allow users to type 'username@organization'.
-		 * - 'force':  Force users to type 'username@organization'. The dropdown
-		 *             list will be hidden.
-		 *
-		 * The default is 'none'.
-		 */
-		'username_organization_method' => 'none',
-
-		/*
-		 * Whether the organization should be included as part of the username
-		 * when authenticating. If this is set to TRUE, the username will be on
-		 * the form <username>@<organization identifier>. If this is FALSE, the
-		 * username will be used as the user enters it.
-		 *
-		 * The default is FALSE.
-		 */
-		'include_organization_in_username' => FALSE,
-
-		/*
-		 * A list of available LDAP servers.
-		 *
-		 * The index is an identifier for the organization/group. When
-		 * 'username_organization_method' is set to something other than 'none',
-		 * the organization-part of the username is matched against the index.
-		 *
-		 * The value of each element is an array in the same format as an LDAP
-		 * authentication source.
-		 */
-		'employees' => array(
-			/*
-			 * A short name/description for this group. Will be shown in a dropdown list
-			 * when the user logs on.
-			 *
-			 * This option can be a string or an array with language => text mappings.
-			 */
-			'description' => 'Employees',
-
-			/*
-			 * The rest of the options are the same as those available for
-			 * the LDAP authentication source.
-			 */
-			'hostname' => 'ldap.employees.example.org',
-			'dnpattern' => 'uid=%username%,ou=employees,dc=example,dc=org',
-		),
-
-		'students' => array(
-			'description' => 'Students',
-
-			'hostname' => 'ldap.students.example.org',
-			'dnpattern' => 'uid=%username%,ou=students,dc=example,dc=org',
-		),
-
-	),
-
-The name of the authentication source (`example-ldapmulti`) should be
-changed to something that makes sense for your organization. Each entry
-in the configuration represents the configuration for one group of
-users. The `description`-option in each group is the name of the group,
-and will be shown to the user in a dropdown list on the login page.
-
-The `description`-option can also be an array with descriptions in
-different languages:
-
-	'description' => array(
-		'en' => 'Employees',
-		'no' => 'Ansatte',
-	),
-
-All options from the `ldap:LDAP` configuration can be used in each
-group, and you should refer to the documentation for that module for
-more information about available options.
-
-
-`ldap:AttributeAddFromLDAP`
----------------------------
-
-Filter to add attributes to the identity by executing a query against
-an LDAP directory. In addition to all the configuration options available
-in the ldap:AttributeAddUsersGroups filter (below), these are the filter
-specific configuration options:
-
-
-	50 = array(
-		'class' => 'ldap:AttributeAddFromLDAP',
-
-		/**
-		 * The attributes to search for and their mappings. This must be an array,
-		 * and keys can be skipped. If you skip a key, then the attribute will be
-		 * exported with the same name as the LDAP attribute.
-		 *
-		 * Default: NULL
-		 * Required: Yes
-		 */
-		'attributes' => array('mail', 'jpegPhoto' => 'jpegphoto'),
-
-		/**
-		 * The attribute policy that defines what to do with attributes that are
-		 * already part of the attributes of the user. Can be one of:
-		 *
-		 * - add: blindly add the values. If the attribute already exists and has
-		 * the same value, the result of the filter will be two equal values.
-		 *
-		 * - merge: carefully merge the values. If a value is already part of
-		 * the attribute, do not add a duplicate.
-		 *
-		 * - replace: if the attribute is present before running the filter,
-		 * replace its values with the ones obtained at this point.
-		 *
-		 * Default: merge
-		 * Required: No
-		 */
-		'attribute.policy' => 'merge',
-
-		/**
-		 * The search filter to find the user in LDAP.
-		 *
-		 * Note: Variable substitution will be performed on this option.
-		 *       Any attribute in the identity can be substituted by surrounding
-		 *       it with percent symbols (%). For instance %cn% would be replaced
-		 *       with the CN of the user.
-		 *
-		 * Default: NULL
-		 * Required: Yes
-		 */
-		'search.filter' => '(uid=%uid%)',
-	);
-
-
-### Backwards Compatibility ###
-
-Previous versions of this filter allowed just one attribute to be fetched from the
-LDAP at a time. The options 'attribute.new' and 'search.attribute' were used instead
-of the new option 'attributes'. Fortunately, the filter is backwards compatible, so
-your old configuration will still work, but keep in mind that the old configuration
-style is deprecated now and will be removed in 2.0.
-
-
-### Example ###
-
-This is the most basic configuration possible. It will look at the
-authsource for all LDAP connection information and queries LDAP for
-the specific attributes requested.
-
-	50 => array(
-		'class' => 'ldap:AttributeAddFromLDAP',
-		'authsource' => 'example-ldap',
-		'attributes' => array('displayName' => 'cn', 'jpegPhoto'),
-		'search.filter' => '(uid=%uid%)',
-	)
-
-If no authsource is available then you can specify the connection info
-using the filter configuration. Note: Not all of the options below are
-required, see the config options for ldap:AttributeAddFromLDAP above.
-
-	50 => array(
-		'class' => 'ldap:AttributeAddFromLDAP',
-		'ldap.hostname' => 'ldap.example.org',
-		'ldap.username' => 'CN=LDAP User,CN=Users,DC=example,DC=org',
-		'ldap.password' => 'Abc123',
-		'ldap.basedn' => 'DC=example,DC=org',
-		'attributes' => array('displayName' => 'cn', 'jpegPhoto'),
-		'search.filter' => '(uid=%uid%)',
-	)
-
-
-
-
-`ldap:AttributeAddUsersGroups`
-------------------------------
-
-This filter will add the logged in user's LDAP group memberships to
-a specified request attribute. Although most LDAP products have a
-memberOf attribute which only lists the direct membership relations,
-this filter checks those relation for "sub" groups, recursively
-checking the hierarchy for all groups the user would technically be
-a member of. This can be helpful for other filters to know. Below is
-a listing of all configuration options and their details.
-
-
-	50 => array(
-		'class' => 'ldap:AttributeAddUsersGroups',
-
-
-		/**
-		 * LDAP connection settings can be retrieved from an ldap:LDAP
-		 * authsource. Specify the authsource name here to pull that
-		 * data from the authsources.php file in the config folder.
-		 *
-		 * Note: ldap:LDAPMulti is not supported as the SimpleSAMLphp
-		 *       framework does not pass any information about which
-		 *       LDAP source the user selected.
-		 *
-		 * Default: NULL
-		 * Require: No
-		 */
-		'authsource' => NULL,
-		'authsource' => 'example-ldap',
-
-
-		/**
-		 * This is the attribute name which the users groups will be
-		 * added to. If the attribute exists in the request then the
-		 * filter will attempt to add them.
-		 *
-		 * Default: 'groups'
-		 * Required: No
-		 */
-		'attribute.groups' => 'groups',
-
-
-		/**
-		 * The base DN used to search LDAP. May not be needed if searching
-		 * LDAP using the standard method, meaning that no Product is specified.
-		 * Can be listed as a single string for one base, else an array of
-		 * strings for multiple bases.
-		 *
-		 * Default: ''
-		 * Required: No
-		 * AuthSource: search.base
-		 */
-		'ldap.basedn' => '',
-		'ldap.basedn' => 'DC=example,DC=org',
-		'ldap.basedn' => array(
-			'OU=Staff,DC=example,DC=org',
-			'OU=Students,DC=example,DC=org'
-		),
-
-
-		/**
-		 * Set to TRUE to enable LDAP debug level. Passed to
-		 * the LDAP connection class.
-		 *
-		 * Default: FALSE
-		 * Required: No
-		 * AuthSource: debug
-		 */
-		'ldap.debug' => FALSE,
-		'ldap.debug' => TRUE,
-
-
-		/**
-		 * Set to TRUE to force the LDAP connection to use TLS.
-		 *
-		 * Note: If ldaps:// is specified in the hostname then it
-		 *       will automatically use TLS.
-		 *
-		 * Default: FALSE
-		 * Required: No
-		 * AuthSource: enable_tls
-		 */
-		'ldap.enable_tls' => FALSE,
-		'ldap.enable_tls' => TRUE,
-
-
-		/**
-		 * This is the hostname string of LDAP server(s) to try
-		 * and connect to. It should be the same format as the
-		 * LDAP authsource hostname as it is passed to that class.
-		 *
-		 * Note: Multiple servers are separated by a space.
-		 *
-		 * Default: NULL
-		 * Required: Yes, unless authsource is used
-		 * AuthSource: hostname
-		 */
-		'ldap.hostname' => 'ldap.example.org',
-		'ldap.hostname' => 'ad1.example.org ad2.example.org',
-
-
-		/**
-		 * This is the port where the LDAP server(s) listen for
-		 * connections.
-		 *
-		 * Default: 389
-		 * Required: No
-		 * AuthSource: port
-		 */
-		'ldap.port' => 389,
-
-
-		/**
-		 * This is the password used to bind to LDAP.
-		 *
-		 * Default: NULL
-		 * Required: No, only if required for binding.
-		 * AuthSource: search.password OR priv.password
-		 */
-		'ldap.password' => 'Abc123',
-
-
-		/**
-		 * By specifying the directory service product name, the number
-		 * of LDAP queries can be dramatically reduced. The reason is
-		 * that most products have a special query to recursively search
-		 * group membership.
-		 *
-		 * Note: Only ActiveDirectory is currently supported 
-		 * (OpenLDAP is implemented but not supported, see example below).
-		 *
-		 * Default: ''
-		 * Required: No
-		 */
-		'ldap.product' => '',
-		'ldap.product' => 'ActiveDirectory',
-		'ldap.product' => 'OpenLDAP',
-
-
-		/**
-		 * The LDAP timeout value passed to the LDAP connection class.
-		 *
-		 * Default: 0
-		 * Required: No
-		 * AuthSource: timeout
-		 */
-		'ldap.timeout' => 0,
-		'ldap.timeout' => 30,
-
-
-		/**
-		 * This is the username used to bind to LDAP with.
-		 * More than likely will need to be in the DN of
-		 * user binding to LDAP.
-		 *
-		 * Default: NULL
-		 * Required: No, only if required for binding.
-		 * AuthSource: search.username OR priv.username
-		 */
-		'ldap.username' => 'CN=LDAP User,CN=Users,DC=example,DC=org',
-
-
-		/**
-		 * The following attribute.* and type.* configuration options
-		 * define the LDAP schema and should only be defined/modified
-		 * if the schema has been modified or the LDAP product used
-		 * uses other attribute names. By default, the schema is setup
-		 * for ActiveDirectory.
-		 *
-		 * Defaults: Listed Below
-		 * Required: No
-		 */
-		'attribute.dn' => 'distinguishedName',
-		'attribute.groups' => 'groups', // Also noted above
-		'attribute.member' => 'member',
-		'attribute.memberof' => 'memberOf',
-		'attribute.groupname' => 'name',
-		'attribute.type' => 'objectClass',
-		'attribute.username' => 'sAMAccountName',
-
-
-		/**
-		 * As mentioned above, these can be changed if the LDAP schema
-		 * has been modified. These list the Object/Entry Type for a given
-		 * DN, in relation to the 'attribute.type' config option above.
-		 * These are used to determine the type of entry.
-		 *
-		 * Defaults: Listed Below
-		 * Required: No
-		 */
-		'type.group' => 'group',
-		'type.user' => 'user',
-	)
-
-
-### Example ###
-
-This is the most basic configuration possible. It will look at the
-authsource for all LDAP connection information and manually search
-the hierarchy for the users group memberships.
-
-	50 => array(
-		'class' => 'ldap:AttributeAddUsersGroups',
-		'authsource' => 'example-ldap'
-	)
-
-By making one small change we can optimize the filter to use better
-group search methods and eliminate un-needed LDAP queries.
-
-	50 => array(
-		'class' => 'ldap:AttributeAddUsersGroups',
-		'authsource' => 'example-ldap',
-		'ldap.product' => 'ActiveDirectory'
-	)
-
-If no authsource is available then you can specify the connection info
-using the filter configuration. Note: Not all of the options below are
-required, see the config info above for details.
-
-	50 => array(
-		'class' => 'ldap:AttributeAddUsersGroups',
-		'ldap.hostname' => 'ldap.example.org',
-		'ldap.username' => 'CN=LDAP User,CN=Users,DC=example,DC=org',
-		'ldap.password' => 'Abc123',
-		'ldap.basedn' => 'DC=example,DC=org'
-	)
-
-Example for unsupported OpenLDAP usage. 
-Intention is to filter in `ou=groups,dc=example,dc=com` for
-`(memberUid = <UID>)` and take only the attribute `cn` (=name of the group).
-
-    50 => array(
-        'class' => 'ldap:AttributeAddUsersGroups',
-        'ldap.product' => 'OpenLDAP',
-        'ldap.basedn' => 'ou=groups,dc=example,dc=org',
-        'attribute.username' => 'uid',
-        'attribute.member' => 'cn',
-        'attribute.memberof' => 'memberUid',
-    ),
diff --git a/modules/ldap/lib/Auth/Process/AttributeAddFromLDAP.php b/modules/ldap/lib/Auth/Process/AttributeAddFromLDAP.php
deleted file mode 100644
index 99ca6c0cc..000000000
--- a/modules/ldap/lib/Auth/Process/AttributeAddFromLDAP.php
+++ /dev/null
@@ -1,228 +0,0 @@
-<?php
-
-namespace SimpleSAML\Module\ldap\Auth\Process;
-
-/**
- * Filter to add attributes to the identity by executing a query against an LDAP directory
- *
- * Original Author: Steve Moitozo II <steve_moitozo@jaars.org>
- * Created: 20100513
- * Updated: 20100920 Steve Moitozo II
- *          - incorporated feedback from Olav Morken to prep code for inclusion in SimpleSAMLphp distro
- *          - moved call to ldap_set_options() inside test for $ds
- *          - added the output of ldap_error() to the exceptions
- *          - reduced some of the nested ifs
- *          - added support for multiple values
- *          - added support for anonymous binds
- *          - added escaping of search filter and attribute
- * Updated: 20111118 Ryan Panning
- *          - Updated the class to use BaseFilter which reuses LDAP connection features
- *          - Added conversion of original filter option names for backwards-compatibility
- *          - Updated the constructor to use the new config method
- *          - Updated the process method to use the new config variable names
- * Updated: 20131119 Yørn de Jong / Jaime Perez
- *          - Added support for retrieving multiple values at once from LDAP
- *          - Don't crash but fail silently on LDAP errors; the plugin is to complement attributes
- * Updated: 20161223 Remy Blom <remy.blom@hku.nl>
- *          - Adjusted the silent fail so it does show a warning in log when $this->getLdap() fails
- *
- * @author Yørn de Jong
- * @author Jaime Perez
- * @author Steve Moitozo
- * @author JAARS, Inc.
- * @author Ryan Panning
- * @author Remy Blom <remy.blom@hku.nl>
- * @package SimpleSAMLphp
- */
-class AttributeAddFromLDAP extends BaseFilter
-{
-    /**
-     * LDAP attributes to add to the request attributes
-     *
-     * @var array
-     */
-    protected $search_attributes;
-
-
-    /**
-     * LDAP search filter to use in the LDAP query
-     *
-     * @var string
-     */
-    protected $search_filter;
-
-
-    /**
-     * What to do with attributes when the target already exists. Either replace, merge or add.
-     *
-     * @var string
-     */
-    protected $attr_policy;
-
-
-    /**
-     * Initialize this filter.
-     *
-     * @param array $config Configuration information about this filter.
-     * @param mixed $reserved For future use.
-     */
-    public function __construct($config, $reserved)
-    {
-        /*
-         * For backwards compatibility, check for old config names
-         * @TODO Remove after 2.0
-         */
-        if (isset($config['ldap_host'])) {
-            $config['ldap.hostname'] = $config['ldap_host'];
-        }
-        if (isset($config['ldap_port'])) {
-            $config['ldap.port'] = $config['ldap_port'];
-        }
-        if (isset($config['ldap_bind_user'])) {
-            $config['ldap.username'] = $config['ldap_bind_user'];
-        }
-        if (isset($config['ldap_bind_pwd'])) {
-            $config['ldap.password'] = $config['ldap_bind_pwd'];
-        }
-        if (isset($config['userid_attribute'])) {
-            $config['attribute.username'] = $config['userid_attribute'];
-        }
-        if (isset($config['ldap_search_base_dn'])) {
-            $config['ldap.basedn'] = $config['ldap_search_base_dn'];
-        }
-        if (isset($config['ldap_search_filter'])) {
-            $config['search.filter'] = $config['ldap_search_filter'];
-        }
-        if (isset($config['ldap_search_attribute'])) {
-            $config['search.attribute'] = $config['ldap_search_attribute'];
-        }
-        if (isset($config['new_attribute_name'])) {
-            $config['attribute.new'] = $config['new_attribute_name'];
-        }
-
-        /*
-         * Remove the old config names
-         * @TODO Remove after 2.0
-         */
-        unset(
-            $config['ldap_host'],
-            $config['ldap_port'],
-            $config['ldap_bind_user'],
-            $config['ldap_bind_pwd'],
-            $config['userid_attribute'],
-            $config['ldap_search_base_dn'],
-            $config['ldap_search_filter'],
-            $config['ldap_search_attribute'],
-            $config['new_attribute_name']
-        );
-
-        // Now that we checked for BC, run the parent constructor
-        parent::__construct($config, $reserved);
-
-        // Get filter specific config options
-        $this->search_attributes = $this->config->getArrayize('attributes', []);
-        if (empty($this->search_attributes)) {
-            $new_attribute = $this->config->getString('attribute.new', '');
-            $this->search_attributes[$new_attribute] = $this->config->getString('search.attribute');
-        }
-        $this->search_filter = $this->config->getString('search.filter');
-
-        // get the attribute policy
-        $this->attr_policy = $this->config->getString('attribute.policy', 'merge');
-    }
-
-
-    /**
-     * Add attributes from an LDAP server.
-     *
-     * @param array &$request The current request
-     * @return void
-     */
-    public function process(&$request)
-    {
-        assert(is_array($request));
-        assert(array_key_exists('Attributes', $request));
-
-        $attributes = &$request['Attributes'];
-
-        // perform a merge on the ldap_search_filter
-        // loop over the attributes and build the search and replace arrays
-        $arrSearch = [];
-        $arrReplace = [];
-        foreach ($attributes as $attr => $val) {
-            $arrSearch[] = '%'.$attr.'%';
-
-            if (strlen($val[0]) > 0) {
-                $arrReplace[] = \SimpleSAML\Auth\LDAP::escape_filter_value($val[0]);
-            } else {
-                $arrReplace[] = '';
-            }
-        }
-
-        // merge the attributes into the ldap_search_filter
-        $filter = str_replace($arrSearch, $arrReplace, $this->search_filter);
-
-        if (strpos($filter, '%') !== false) {
-            \SimpleSAML\Logger::info('AttributeAddFromLDAP: There are non-existing attributes in the search filter. ('.
-                $this->search_filter.')');
-            return;
-        }
-
-        if (!in_array($this->attr_policy, ['merge', 'replace', 'add'], true)) {
-            \SimpleSAML\Logger::warning("AttributeAddFromLDAP: 'attribute.policy' must be one of 'merge',".
-                "'replace' or 'add'.");
-            return;
-        }
-
-        // getLdap
-        try {
-            $ldap = $this->getLdap();
-        } catch (\Exception $e) {
-            // Added this warning in case $this->getLdap() fails
-            \SimpleSAML\Logger::warning("AttributeAddFromLDAP: exception = ".$e);
-            return;
-        }
-        // search for matching entries
-        try {
-            $entries = $ldap->searchformultiple(
-                $this->base_dn,
-                $filter,
-                array_values($this->search_attributes),
-                true,
-                false
-            );
-        } catch (\Exception $e) {
-            return; // silent fail, error is still logged by LDAP search
-        }
-
-        // handle [multiple] values
-        foreach ($entries as $entry) {
-            foreach ($this->search_attributes as $target => $name) {
-                if (is_numeric($target)) {
-                    $target = $name;
-                }
-
-                if (isset($attributes[$target]) && $this->attr_policy === 'replace') {
-                    unset($attributes[$target]);
-                }
-                $name = strtolower($name);
-                if (isset($entry[$name])) {
-                    unset($entry[$name]['count']);
-                    if (isset($attributes[$target])) {
-                        foreach (array_values($entry[$name]) as $value) {
-                            if ($this->attr_policy === 'merge') {
-                                if (!in_array($value, $attributes[$target], true)) {
-                                    $attributes[$target][] = $value;
-                                }
-                            } else {
-                                $attributes[$target][] = $value;
-                            }
-                        }
-                    } else {
-                        $attributes[$target] = array_values($entry[$name]);
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/modules/ldap/lib/Auth/Process/AttributeAddUsersGroups.php b/modules/ldap/lib/Auth/Process/AttributeAddUsersGroups.php
deleted file mode 100644
index 2f50a7af9..000000000
--- a/modules/ldap/lib/Auth/Process/AttributeAddUsersGroups.php
+++ /dev/null
@@ -1,376 +0,0 @@
-<?php
-
-namespace SimpleSAML\Module\ldap\Auth\Process;
-
-/**
- * Does a reverse membership lookup on the logged in user,
- * looking for groups it is a member of and adds them to
- * a defined attribute, in DN format.
- *
- * @author Ryan Panning <panman@traileyes.com>
- * @package SimpleSAMLphp
- */
-class AttributeAddUsersGroups extends BaseFilter
-{
-    /**
-     * This is run when the filter is processed by SimpleSAML.
-     * It will attempt to find the current users groups using
-     * the best method possible for the LDAP product. The groups
-     * are then added to the request attributes.
-     *
-     * @throws \SimpleSAML\Error\Exception
-     * @param $request
-     * @return void
-     */
-    public function process(&$request)
-    {
-        assert(is_array($request));
-        assert(array_key_exists('Attributes', $request));
-
-        // Log the process
-        \SimpleSAML\Logger::debug(
-            $this->title.'Attempting to get the users groups...'
-        );
-
-        // Reference the attributes, just to make the names shorter
-        $attributes = &$request['Attributes'];
-        $map = &$this->attribute_map;
-
-        // Get the users groups from LDAP
-        $groups = $this->getGroups($attributes);
-
-        // Make the array if it is not set already
-        if (!isset($attributes[$map['groups']])) {
-            $attributes[$map['groups']] = [];
-        }
-
-        // Must be an array, else cannot merge groups
-        if (!is_array($attributes[$map['groups']])) {
-            throw new \SimpleSAML\Error\Exception(
-                $this->title.'The group attribute ['.$map['groups'].
-                '] is not an array of group DNs. '.$this->var_export($attributes[$map['groups']])
-            );
-        }
-
-        // Add the users group(s)
-        $group_attribute = &$attributes[$map['groups']];
-        $group_attribute = array_merge($group_attribute, $groups);
-        $group_attribute = array_unique($group_attribute);
-
-        // All done
-        \SimpleSAML\Logger::debug(
-            $this->title.'Added users groups to the group attribute ['.
-            $map['groups'].']: '.implode('; ', $groups)
-        );
-    }
-
-
-    /**
-     * This section of code was broken out because the child
-     * filter AuthorizeByGroup can use this method as well.
-     * Based on the LDAP product, it will do an optimized search
-     * using the required attribute values from the user to
-     * get their group membership, recursively.
-     *
-     * @throws \SimpleSAML\Error\Exception
-     * @param array $attributes
-     * @return array
-     */
-    protected function getGroups($attributes)
-    {
-        // Log the request
-        \SimpleSAML\Logger::debug(
-            $this->title.'Checking for groups based on the best method for the LDAP product.'
-        );
-
-        // Based on the directory service, search LDAP for groups
-        // If any attributes are needed, prepare them before calling search method
-        switch ($this->product) {
-            case 'ACTIVEDIRECTORY':
-                $groups = $this->getGroupsActiveDirectory($attributes);
-                break;
-            case 'OPENLDAP':
-                $groups = $this->getGroupsOpenLdap($attributes);
-                break;
-            default:
-                // Reference the map, just to make the name shorter
-                $map = &$this->attribute_map;
-
-                // Log the general search
-                \SimpleSAML\Logger::debug(
-                    $this->title.'Searching LDAP using the default search method.'
-                );
-
-                // Make sure the defined memberOf attribute exists
-                if (!isset($attributes[$map['memberof']])) {
-                    throw new \SimpleSAML\Error\Exception(
-                        $this->title.'The memberof attribute ['.$map['memberof'].
-                        '] is not defined in the user\'s Attributes: '.implode(', ', array_keys($attributes))
-                    );
-                }
-
-                // MemberOf must be an array of group DN's
-                if (!is_array($attributes[$map['memberof']])) {
-                    throw new \SimpleSAML\Error\Exception(
-                        $this->title.'The memberof attribute ['.$map['memberof'].
-                        '] is not an array of group DNs. '.$this->var_export($attributes[$map['memberof']])
-                    );
-                }
-
-                // Search for the users group membership, recursively
-                $groups = $this->search($attributes[$map['memberof']]);
-        }
-
-        // All done
-        \SimpleSAML\Logger::debug(
-            $this->title.'User found to be a member of the groups:'.implode('; ', $groups)
-        );
-        return $groups;
-    }
-
-
-    /**
-     * OpenLDAP optimized search
-     * using the required attribute values from the user to
-     * get their group membership, recursively.
-     *
-     * @throws \SimpleSAML\Error\Exception
-     * @param array $attributes
-     * @return array
-     */
-    protected function getGroupsOpenLdap($attributes)
-    {
-        // Log the OpenLDAP specific search
-        \SimpleSAML\Logger::debug(
-            $this->title.'Searching LDAP using OpenLDAP specific method.'
-        );
-
-        // Reference the map, just to make the name shorter
-        $map = &$this->attribute_map;
-
-        // Print group search string and search for all group names
-        $openldap_base = $this->config->getString('ldap.basedn', 'ou=groups,dc=example,dc=com');
-        \SimpleSAML\Logger::debug(
-            $this->title."Searching for groups in ldap.basedn ".$openldap_base." with filter (".$map['memberof'].
-            "=".$attributes[$map['username']][0].") and attributes ".$map['member']
-        );
-
-        $groups = [];
-        try {
-            /* Intention is to filter in 'ou=groups,dc=example,dc=com' for
-             * '(memberUid = <value of attribute.username>)' and take only the attributes 'cn' (=name of the group)
-             */
-            $all_groups = $this->getLdap()->searchformultiple(
-                $openldap_base,
-                [$map['memberof'] => $attributes[$map['username']][0]],
-                [$map['member']]
-            );
-        } catch (\SimpleSAML\Error\UserNotFound $e) {
-            return $groups; // if no groups found return with empty (still just initialized) groups array
-        }
-
-        // run through all groups and add each to our groups array
-        foreach ($all_groups as $group_entry) {
-            $groups[] = $group_entry[$map['member']][0];
-        }
-
-        return $groups;
-    }
-
-
-    /**
-     * Active Directory optimized search
-     * using the required attribute values from the user to
-     * get their group membership, recursively.
-     *
-     * @throws \SimpleSAML\Error\Exception
-     * @param array $attributes
-     * @return array
-     */
-    protected function getGroupsActiveDirectory($attributes)
-    {
-        // Log the AD specific search
-        \SimpleSAML\Logger::debug(
-            $this->title.'Searching LDAP using ActiveDirectory specific method.'
-        );
-
-        // Reference the map, just to make the name shorter
-        $map = &$this->attribute_map;
-
-        // Make sure the defined dn attribute exists
-        if (!isset($attributes[$map['dn']])) {
-            throw new \SimpleSAML\Error\Exception(
-                $this->title.'The DN attribute ['.$map['dn'].
-                '] is not defined in the user\'s Attributes: '.implode(', ', array_keys($attributes))
-            );
-        }
-
-        // DN attribute must have a value
-        if (!isset($attributes[$map['dn']][0]) || !$attributes[$map['dn']][0]) {
-            throw new \SimpleSAML\Error\Exception(
-                $this->title.'The DN attribute ['.$map['dn'].
-                '] does not have a [0] value defined. '.$this->var_export($attributes[$map['dn']])
-            );
-        }
-
-        // Pass to the AD specific search
-        return $this->searchActiveDirectory($attributes[$map['dn']][0]);
-    }
-
-    /**
-     * Looks for groups from the list of DN's passed. Also
-     * recursively searches groups for further membership.
-     * Avoids loops by only searching a DN once. Returns
-     * the list of groups found.
-     *
-     * @param array $memberof
-     * @return array
-     */
-    protected function search($memberof)
-    {
-        assert(is_array($memberof));
-
-        // Used to determine what DN's have already been searched
-        static $searched = [];
-
-        // Init the groups variable
-        $groups = [];
-
-        // Shorten the variable name
-        $map = &$this->attribute_map;
-
-        // Log the search
-        \SimpleSAML\Logger::debug(
-            $this->title.'Checking DNs for groups.'.
-            ' DNs: '.implode('; ', $memberof).
-            ' Attributes: '.$map['memberof'].', '.$map['type'].
-            ' Group Type: '.$this->type_map['group']
-        );
-
-        // Work out what attributes to get for a group
-        $use_group_name = false;
-        $get_attributes = [$map['memberof'], $map['type']];
-        if (isset($map['name']) && $map['name']) {
-            $get_attributes[] = $map['name'];
-            $use_group_name = true;
-        }
-
-        // Check each DN of the passed memberOf
-        foreach ($memberof as $dn) {
-            // Avoid infinite loops, only need to check a DN once
-            if (isset($searched[$dn])) {
-                continue;
-            }
-
-            // Track all DN's that are searched
-            // Use DN for key as well, isset() is faster than in_[]
-            $searched[$dn] = $dn;
-
-            // Query LDAP for the attribute values for the DN
-            try {
-                $attributes = $this->getLdap()->getAttributes($dn, $get_attributes);
-            } catch (\SimpleSAML\Error\AuthSource $e) {
-                continue; // DN must not exist, just continue. Logged by the LDAP object
-            }
-
-            // Only look for groups
-            if (!in_array($this->type_map['group'], $attributes[$map['type']], true)) {
-                continue;
-            }
-
-            // Add to found groups array
-            if ($use_group_name && isset($attributes[$map['name']]) && is_array($attributes[$map['name']])) {
-                $groups[] = $attributes[$map['name']][0];
-            } else {
-                $groups[] = $dn;
-            }
-
-            // Recursively search "sub" groups
-            if (!empty($attributes[$map['memberof']])) {
-                $groups = array_merge($groups, $this->search($attributes[$map['memberof']]));
-            }
-        }
-
-        // Return only the unique group names
-        return array_unique($groups);
-    }
-
-
-    /**
-     * Searches LDAP using a ActiveDirectory specific filter,
-     * looking for group membership for the users DN. Returns
-     * the list of group DNs retrieved.
-     *
-     * @param string $dn
-     * @return array
-     */
-    protected function searchActiveDirectory($dn)
-    {
-        assert(is_string($dn) && $dn != '');
-
-        // Shorten the variable name
-        $map = &$this->attribute_map;
-
-        // Log the search
-        \SimpleSAML\Logger::debug(
-            $this->title.'Searching ActiveDirectory group membership.'.
-            ' DN: '.$dn.
-            ' DN Attribute: '.$map['dn'].
-            ' Member Attribute: '.$map['member'].
-            ' Type Attribute: '.$map['type'].
-            ' Type Value: '.$this->type_map['group'].
-            ' Base: '.implode('; ', $this->base_dn)
-        );
-
-        // AD connections should have this set
-        $this->getLdap()->setOption(LDAP_OPT_REFERRALS, 0);
-
-        // Search AD with the specific recursive flag
-        try {
-            $entries = $this->getLdap()->searchformultiple(
-                $this->base_dn,
-                [$map['type'] => $this->type_map['group'], $map['member'].':1.2.840.113556.1.4.1941:' => $dn],
-                [$map['dn']]
-            );
-
-        // The search may throw an exception if no entries
-        // are found, unlikely but possible.
-        } catch (\SimpleSAML\Error\UserNotFound $e) {
-            return [];
-        }
-
-        //Init the groups
-        $groups = [];
-
-        // Check each entry..
-        foreach ($entries as $entry) {
-            // Check for the DN using the original attribute name
-            if (isset($entry[$map['dn']][0])) {
-                $groups[] = $entry[$map['dn']][0];
-                continue;
-            }
-
-            // Sometimes the returned attribute names are lowercase
-            if (isset($entry[strtolower($map['dn'])][0])) {
-                $groups[] = $entry[strtolower($map['dn'])][0];
-                continue;
-            }
-
-            // AD queries also seem to return the objects dn by default
-            if (isset($entry['dn'])) {
-                $groups[] = $entry['dn'];
-                continue;
-            }
-
-            // Could not find DN, log and continue
-            \SimpleSAML\Logger::notice(
-                $this->title.'The DN attribute ['.
-                implode(', ', [$map['dn'], strtolower($map['dn']), 'dn']).
-                '] could not be found in the entry. '.$this->var_export($entry)
-            );
-        }
-
-        // All done
-        return $groups;
-    }
-}
diff --git a/modules/ldap/lib/Auth/Process/BaseFilter.php b/modules/ldap/lib/Auth/Process/BaseFilter.php
deleted file mode 100644
index 4c1d9d002..000000000
--- a/modules/ldap/lib/Auth/Process/BaseFilter.php
+++ /dev/null
@@ -1,325 +0,0 @@
-<?php
-
-namespace SimpleSAML\Module\ldap\Auth\Process;
-
-/**
- * This base LDAP filter class can be extended to enable real
- * filter classes direct access to the authsource ldap config
- * and connects to the ldap server.
- *
- * Updated: 20161223 Remy Blom
- *          - Wrapped the building of authsource config with issets
- *
- * @author Ryan Panning <panman@traileyes.com>
- * @author Remy Blom <remy.blom@hku.nl>
- * @package SimpleSAMLphp
- */
-abstract class BaseFilter extends \SimpleSAML\Auth\ProcessingFilter
-{
-    /**
-     * List of attribute "alias's" linked to the real attribute
-     * name. Used for abstraction / configuration of the LDAP
-     * attribute names, which may change between dir service.
-     *
-     * @var array
-     */
-    protected $attribute_map;
-
-
-    /**
-     * The base DN of the LDAP connection. Used when searching
-     * the LDAP server.
-     *
-     * @var string|array
-     */
-    protected $base_dn;
-
-
-    /**
-     * The construct method will change the filter config into
-     * a \SimpleSAML\Configuration object and store it here for
-     * later use, if needed.
-     *
-     * @var \SimpleSAML\Configuration
-     */
-    protected $config;
-
-
-    /**
-     * Instance, object of the ldap connection. Stored here to
-     * be access later during processing.
-     *
-     * @var \SimpleSAML\Auth\LDAP
-     */
-    private $ldap;
-
-
-    /**
-     * Many times a LDAP product specific query can be used to
-     * speed up or reduce the filter process. This helps the
-     * child classes determine the product used to optimize
-     * those queries.
-     *
-     * @var string
-     */
-    protected $product;
-
-
-    /**
-     * The class "title" used in logging and exception messages.
-     * This should be prepended to the beginning of the message.
-     *
-     * @var string
-     */
-    protected $title = 'ldap:BaseFilter : ';
-
-
-    /**
-     * List of LDAP object types, used to determine the type of
-     * object that a DN references.
-     *
-     * @var array
-     */
-    protected $type_map;
-
-
-    /**
-     * Checks the authsource, if defined, for configuration values
-     * to the LDAP server. Then sets up the LDAP connection for the
-     * instance/object and stores everything in class members.
-     *
-     * @throws \SimpleSAML\Error\Exception
-     * @param array &$config
-     * @param mixed $reserved
-     */
-    public function __construct(&$config, $reserved)
-    {
-        parent::__construct($config, $reserved);
-
-        // Change the class $title to match it's true name
-        // This way if the class is extended the proper name is used
-        $classname = get_class($this);
-        $classname = explode('_', $classname);
-        $this->title = 'ldap:'.end($classname).' : ';
-
-        // Log the construction
-        \SimpleSAML\Logger::debug(
-            $this->title.'Creating and configuring the filter.'
-        );
-
-        // If an authsource was defined (an not empty string)...
-        if (isset($config['authsource']) && $config['authsource']) {
-            // Log the authsource request
-            \SimpleSAML\Logger::debug(
-                $this->title.'Attempting to get configuration values from authsource ['.
-                $config['authsource'].']'
-            );
-
-            // Get the authsources file, which should contain the config
-            $authsource = \SimpleSAML\Configuration::getConfig('authsources.php');
-
-            // Verify that the authsource config exists
-            if (!$authsource->hasValue($config['authsource'])) {
-                throw new \SimpleSAML\Error\Exception(
-                    $this->title.'Authsource ['.$config['authsource'].
-                    '] defined in filter parameters not found in authsources.php'
-                );
-            }
-
-            // Get just the specified authsource config values
-            $authsource = $authsource->getConfigItem($config['authsource']);
-            $authsource = $authsource->toArray();
-
-            // Make sure it is an ldap source
-            // TODO: Support ldap:LDAPMulti, if possible
-            if (@$authsource[0] != 'ldap:LDAP') {
-                throw new \SimpleSAML\Error\Exception(
-                    $this->title.'Authsource ['.$config['authsource'].
-                    '] specified in filter parameters is not an ldap:LDAP type'
-                );
-            }
-
-            // Build the authsource config
-            $authconfig = [];
-            if (isset($authsource['hostname'])) {
-                $authconfig['ldap.hostname']   = $authsource['hostname'];
-            }
-            if (isset($authsource['enable_tls'])) {
-                $authconfig['ldap.enable_tls'] = $authsource['enable_tls'];
-            }
-            if (isset($authsource['port'])) {
-                $authconfig['ldap.port']       = $authsource['port'];
-            }
-            if (isset($authsource['timeout'])) {
-                $authconfig['ldap.timeout']    = $authsource['timeout'];
-            }
-            if (isset($authsource['debug'])) {
-                $authconfig['ldap.debug']      = $authsource['debug'];
-            }
-            if (isset($authsource['referrals'])) {
-                $authconfig['ldap.referrals']  = $authsource['referrals'];
-            }
-            // only set when search.enabled = true
-            if (isset($authsource['search.enable']) && $authsource['search.enable']) {
-                if (isset($authsource['search.base'])) {
-                    $authconfig['ldap.basedn'] = $authsource['search.base'];
-                }
-                if (isset($authsource['search.scope'])) {
-                    $authconfig['ldap.scope'] = $authsource['search.scope'];
-                }
-                if (isset($authsource['search.username'])) {
-                    $authconfig['ldap.username']   = $authsource['search.username'];
-                }
-                if (isset($authsource['search.password'])) {
-                    $authconfig['ldap.password']   = $authsource['search.password'];
-                }
-                // Only set the username attribute if the authsource specifies one attribute
-                if (isset($authsource['search.attributes']) && is_array($authsource['search.attributes'])
-                     && count($authsource['search.attributes']) == 1) {
-                    $authconfig['attribute.username'] = reset($authsource['search.attributes']);
-                }
-            }
-            // only set when priv.read = true
-            if (isset($authsource['priv.read']) && $authsource['priv.read']) {
-                if (isset($authsource['priv.username'])) {
-                    $authconfig['ldap.username']   = $authsource['priv.username'];
-                }
-                if (isset($authsource['priv.password'])) {
-                    $authconfig['ldap.password']   = $authsource['priv.password'];
-                }
-            }
-
-            // Merge the authsource config with the filter config,
-            // but have the filter config override the authsource config
-            $config = array_merge($authconfig, $config);
-
-            // Authsource complete
-            \SimpleSAML\Logger::debug(
-                $this->title.'Retrieved authsource ['.$config['authsource'].
-                '] configuration values: '.$this->var_export($authconfig)
-            );
-        }
-
-        // Convert the config array to a config class,
-        // that way we can verify type and define defaults.
-        // Store in the instance in-case needed later, by a child class.
-        $this->config = \SimpleSAML\Configuration::loadFromArray($config, 'ldap:AuthProcess');
-
-        // Set all the filter values, setting defaults if needed
-        $this->base_dn = $this->config->getArrayizeString('ldap.basedn', '');
-        $this->product = $this->config->getString('ldap.product', '');
-
-        // Cleanup the directory service, so that it is easier for
-        // child classes to determine service name consistently
-        $this->product = trim($this->product);
-        $this->product = strtoupper($this->product);
-
-        // Log the member values retrieved above
-        \SimpleSAML\Logger::debug(
-            $this->title.'Configuration values retrieved;'.
-            ' BaseDN: '.$this->var_export($this->base_dn).
-            ' Product: '.$this->var_export($this->product)
-        );
-
-        // Setup the attribute map which will be used to search LDAP
-        $this->attribute_map = [
-            'dn'       => $this->config->getString('attribute.dn', 'distinguishedName'),
-            'groups'   => $this->config->getString('attribute.groups', 'groups'),
-            'member'   => $this->config->getString('attribute.member', 'member'),
-            'memberof' => $this->config->getString('attribute.memberof', 'memberOf'),
-            'name'     => $this->config->getString('attribute.groupname', 'name'),
-            'type'     => $this->config->getString('attribute.type', 'objectClass'),
-            'username' => $this->config->getString('attribute.username', 'sAMAccountName')
-        ];
-
-        // Log the attribute map
-        \SimpleSAML\Logger::debug(
-            $this->title.'Attribute map created: '.$this->var_export($this->attribute_map)
-        );
-
-        // Setup the object type map which is used to determine a DNs' type
-        $this->type_map = [
-            'group' => $this->config->getString('type.group', 'group'),
-            'user'  => $this->config->getString('type.user', 'user')
-        ];
-
-        // Log the type map
-        \SimpleSAML\Logger::debug(
-            $this->title.'Type map created: '.$this->var_export($this->type_map)
-        );
-    }
-
-    /**
-     * Getter for the LDAP connection object. Created this getter
-     * rather than setting in the constructor to avoid unnecessarily
-     * connecting to LDAP when it might not be needed.
-     *
-     * @return \SimpleSAML\Auth\LDAP
-     */
-    protected function getLdap()
-    {
-        // Check if already connected
-        if (isset($this->ldap)) {
-            return $this->ldap;
-        }
-
-        // Get the connection specific options
-        $hostname   = $this->config->getString('ldap.hostname');
-        $port       = $this->config->getInteger('ldap.port', 389);
-        $enable_tls = $this->config->getBoolean('ldap.enable_tls', false);
-        $debug      = $this->config->getBoolean('ldap.debug', false);
-        $referrals  = $this->config->getBoolean('ldap.referrals', true);
-        $timeout    = $this->config->getInteger('ldap.timeout', 0);
-        $username   = $this->config->getString('ldap.username', null);
-        $password   = $this->config->getString('ldap.password', null);
-
-        // Log the LDAP connection
-        \SimpleSAML\Logger::debug(
-            $this->title.'Connecting to LDAP server;'.
-            ' Hostname: '.$hostname.
-            ' Port: '.$port.
-            ' Enable TLS: '.($enable_tls ? 'Yes' : 'No').
-            ' Debug: '.($debug ? 'Yes' : 'No').
-            ' Referrals: '.($referrals ? 'Yes' : 'No').
-            ' Timeout: '.$timeout.
-            ' Username: '.$username.
-            ' Password: '.(empty($password) ? '' : '********')
-        );
-
-        // Connect to the LDAP server to be queried during processing
-        $this->ldap = new \SimpleSAML\Auth\LDAP($hostname, $enable_tls, $debug, $timeout, $port, $referrals);
-        $this->ldap->bind($username, $password);
-
-        // All done
-        return $this->ldap;
-    }
-
-    /**
-     * Local utility function to get details about a variable,
-     * basically converting it to a string to be used in a log
-     * message. The var_export() function returns several lines
-     * so this will remove the new lines and trim each line.
-     *
-     * @param mixed $value
-     * @return string
-     */
-    protected function var_export($value)
-    {
-        if (is_array($value)) {
-            // remove sensitive data
-            foreach ($value as $key => &$val) {
-                if ($key === 'ldap.password') {
-                    $val = empty($val) ? '' : '********';
-                }
-            }
-            unset($val);
-        }
-
-        $export = var_export($value, true);
-        $lines = explode("\n", $export);
-        foreach ($lines as &$line) {
-            $line = trim($line);
-        }
-        return implode(' ', $lines);
-    }
-}
diff --git a/modules/ldap/lib/Auth/Source/LDAP.php b/modules/ldap/lib/Auth/Source/LDAP.php
deleted file mode 100644
index 4757a3bb2..000000000
--- a/modules/ldap/lib/Auth/Source/LDAP.php
+++ /dev/null
@@ -1,60 +0,0 @@
-<?php
-
-namespace SimpleSAML\Module\ldap\Auth\Source;
-
-/**
- * LDAP authentication source.
- *
- * See the ldap-entry in config-templates/authsources.php for information about
- * configuration of this authentication source.
- *
- * This class is based on www/auth/login.php.
- *
- * @package SimpleSAMLphp
- */
-
-class LDAP extends \SimpleSAML\Module\core\Auth\UserPassBase
-{
-    /**
-     * A LDAP configuration object.
-     */
-    private $ldapConfig;
-
-
-    /**
-     * Constructor for this authentication source.
-     *
-     * @param array $info  Information about this authentication source.
-     * @param array $config  Configuration.
-     */
-    public function __construct($info, $config)
-    {
-        assert(is_array($info));
-        assert(is_array($config));
-
-        // Call the parent constructor first, as required by the interface
-        parent::__construct($info, $config);
-
-        $this->ldapConfig = new \SimpleSAML\Module\ldap\ConfigHelper(
-            $config,
-            'Authentication source '.var_export($this->authId, true)
-        );
-    }
-
-
-    /**
-     * Attempt to log in using the given username and password.
-     *
-     * @param string $username  The username the user wrote.
-     * @param string $password  The password the user wrote.
-     * param array $sasl_arg  Associative array of SASL options
-     * @return array  Associative array with the users attributes.
-     */
-    protected function login($username, $password, array $sasl_args = null)
-    {
-        assert(is_string($username));
-        assert(is_string($password));
-
-        return $this->ldapConfig->login($username, $password, $sasl_args);
-    }
-}
diff --git a/modules/ldap/lib/Auth/Source/LDAPMulti.php b/modules/ldap/lib/Auth/Source/LDAPMulti.php
deleted file mode 100644
index c923e9846..000000000
--- a/modules/ldap/lib/Auth/Source/LDAPMulti.php
+++ /dev/null
@@ -1,131 +0,0 @@
-<?php
-
-namespace SimpleSAML\Module\ldap\Auth\Source;
-
-/**
- * LDAP authentication source.
- *
- * See the ldap-entry in config-templates/authsources.php for information about
- * configuration of this authentication source.
- *
- * This class is based on www/auth/login.php.
- *
- * @package SimpleSAMLphp
- */
-
-class LDAPMulti extends \SimpleSAML\Module\core\Auth\UserPassOrgBase
-{
-    /**
-     * An array with descriptions for organizations.
-     */
-    private $orgs;
-
-    /**
-     * An array of organization IDs to LDAP configuration objects.
-     */
-    private $ldapOrgs;
-
-    /**
-     * Whether we should include the organization as part of the username.
-     */
-    private $includeOrgInUsername;
-
-
-    /**
-     * Constructor for this authentication source.
-     *
-     * @param array $info  Information about this authentication source.
-     * @param array $config  Configuration.
-     */
-    public function __construct($info, $config)
-    {
-        assert(is_array($info));
-        assert(is_array($config));
-
-        // Call the parent constructor first, as required by the interface
-        parent::__construct($info, $config);
-
-        $cfgHelper = \SimpleSAML\Configuration::loadFromArray(
-            $config,
-            'Authentication source '.var_export($this->authId, true)
-        );
-
-
-        $this->orgs = [];
-        $this->ldapOrgs = [];
-        foreach ($config as $name => $value) {
-            if ($name === 'username_organization_method') {
-                $usernameOrgMethod = $cfgHelper->getValueValidate(
-                    'username_organization_method',
-                    ['none', 'allow', 'force']
-                );
-                $this->setUsernameOrgMethod($usernameOrgMethod);
-                continue;
-            }
-
-            if ($name === 'include_organization_in_username') {
-                $this->includeOrgInUsername = $cfgHelper->getBoolean(
-                    'include_organization_in_username',
-                    false
-                );
-                continue;
-            }
-
-            $orgCfg = $cfgHelper->getArray($name);
-            $orgId = $name;
-
-            if (array_key_exists('description', $orgCfg)) {
-                $this->orgs[$orgId] = $orgCfg['description'];
-            } else {
-                $this->orgs[$orgId] = $orgId;
-            }
-
-            $orgCfg = new \SimpleSAML\Module\ldap\ConfigHelper(
-                $orgCfg,
-                'Authentication source '.var_export($this->authId, true).', organization '.var_export($orgId, true)
-            );
-            $this->ldapOrgs[$orgId] = $orgCfg;
-        }
-    }
-
-
-    /**
-     * Attempt to log in using the given username and password.
-     *
-     * @param string $username  The username the user wrote.
-     * @param string $password  The password the user wrote.
-     * @param string $org  The organization the user chose.
-     * @return array  Associative array with the users attributes.
-     */
-    protected function login($username, $password, $org, array $sasl_args = null)
-    {
-        assert(is_string($username));
-        assert(is_string($password));
-        assert(is_string($org));
-
-        if (!array_key_exists($org, $this->ldapOrgs)) {
-            // The user has selected an organization which doesn't exist anymore.
-            \SimpleSAML\Logger::warning('Authentication source '.var_export($this->authId, true).
-                ': Organization seems to have disappeared while the user logged in.'.
-                ' Organization was '.var_export($org, true));
-            throw new \SimpleSAML\Error\Error('WRONGUSERPASS');
-        }
-
-        if ($this->includeOrgInUsername) {
-            $username = $username.'@'.$org;
-        }
-
-        return $this->ldapOrgs[$org]->login($username, $password, $sasl_args);
-    }
-
-
-    /**
-     * Retrieve list of organizations.
-     *
-     * @return array  Associative array with the organizations.
-     */
-    protected function getOrganizations()
-    {
-        return $this->orgs;
-    }
-}
diff --git a/modules/ldap/lib/ConfigHelper.php b/modules/ldap/lib/ConfigHelper.php
deleted file mode 100644
index 6d862c5a0..000000000
--- a/modules/ldap/lib/ConfigHelper.php
+++ /dev/null
@@ -1,329 +0,0 @@
-<?php
-
-namespace SimpleSAML\Module\ldap;
-
-/**
- * LDAP authentication source configuration parser.
- *
- * See the ldap-entry in config-templates/authsources.php for information about
- * configuration of these options.
- *
- * @package SimpleSAMLphp
- */
-
-class ConfigHelper
-{
-    /**
-     * String with the location of this configuration.
-     * Used for error reporting.
-     */
-    private $location;
-
-    /**
-     * The hostname of the LDAP server.
-     */
-    private $hostname;
-
-    /**
-     * Whether we should use TLS/SSL when contacting the LDAP server.
-     */
-    private $enableTLS;
-
-    /**
-     * Whether debug output is enabled.
-     *
-     * @var bool
-     */
-    private $debug;
-
-    /**
-     * The timeout for accessing the LDAP server.
-     *
-     * @var int
-     */
-    private $timeout;
-
-    /**
-     * The port used when accessing the LDAP server.
-     *
-     * @var int
-     */
-    private $port;
-
-    /**
-     * Whether to follow referrals
-     */
-    private $referrals;
-
-    /**
-     * Whether we need to search for the users DN.
-     */
-    private $searchEnable;
-
-    /**
-     * The username we should bind with before we can search for the user.
-     */
-    private $searchUsername;
-
-    /**
-     * The password we should bind with before we can search for the user.
-     */
-    private $searchPassword;
-
-    /**
-     * Array with the base DN(s) for the search.
-     */
-    private $searchBase;
-
-    /**
-     * The scope of the search.
-     */
-    private $searchScope;
-
-    /**
-     * Additional LDAP filter fields for the search
-     */
-    private $searchFilter;
-
-    /**
-     * The attributes which should match the username.
-     */
-    private $searchAttributes;
-
-    /**
-     * The DN pattern we should use to create the DN from the username.
-     */
-    private $dnPattern;
-
-    /**
-     * The attributes we should fetch. Can be NULL in which case we will fetch all attributes.
-     */
-    private $attributes;
-
-    /**
-     * The user cannot get all attributes, privileged reader required
-     */
-    private $privRead;
-
-    /**
-     * The DN we should bind with before we can get the attributes.
-     */
-    private $privUsername;
-
-    /**
-     * The password we should bind with before we can get the attributes.
-     */
-    private $privPassword;
-
-
-    /**
-     * Constructor for this configuration parser.
-     *
-     * @param array $config  Configuration.
-     * @param string $location  The location of this configuration. Used for error reporting.
-     */
-    public function __construct($config, $location)
-    {
-        assert(is_array($config));
-        assert(is_string($location));
-
-        $this->location = $location;
-
-        // Parse configuration
-        $config = \SimpleSAML\Configuration::loadFromArray($config, $location);
-
-        $this->hostname = $config->getString('hostname');
-        $this->enableTLS = $config->getBoolean('enable_tls', false);
-        $this->debug = $config->getBoolean('debug', false);
-        $this->timeout = $config->getInteger('timeout', 0);
-        $this->port = $config->getInteger('port', 389);
-        $this->referrals = $config->getBoolean('referrals', true);
-        $this->searchEnable = $config->getBoolean('search.enable', false);
-        $this->privRead = $config->getBoolean('priv.read', false);
-
-        if ($this->searchEnable) {
-            $this->searchUsername = $config->getString('search.username', null);
-            if ($this->searchUsername !== null) {
-                $this->searchPassword = $config->getString('search.password');
-            }
-
-            $this->searchBase = $config->getArrayizeString('search.base');
-            $this->searchScope = $config->getString('search.scope', 'subtree');
-            $this->searchFilter = $config->getString('search.filter', null);
-            $this->searchAttributes = $config->getArray('search.attributes');
-        } else {
-            $this->dnPattern = $config->getString('dnpattern');
-        }
-
-        // Are privs needed to get to the attributes?
-        if ($this->privRead) {
-            $this->privUsername = $config->getString('priv.username');
-            $this->privPassword = $config->getString('priv.password');
-        }
-
-        $this->attributes = $config->getArray('attributes', null);
-    }
-
-
-    /**
-     * Attempt to log in using the given username and password.
-     *
-     * Will throw a \SimpleSAML\Error\Error('WRONGUSERPASS') if the username or password is wrong.
-     * If there is a configuration problem, an Exception will be thrown.
-     *
-     * @param string $username  The username the user wrote.
-     * @param string $password  The password the user wrote.
-     * @param array $sasl_args  Array of SASL options for LDAP bind.
-     * @return array  Associative array with the users attributes.
-     */
-    public function login($username, $password, array $sasl_args = null)
-    {
-        assert(is_string($username));
-        assert(is_string($password));
-
-        if (empty($password)) {
-            \SimpleSAML\Logger::info($this->location.': Login with empty password disallowed.');
-            throw new \SimpleSAML\Error\Error('WRONGUSERPASS');
-        }
-
-        $ldap = new \SimpleSAML\Auth\LDAP(
-            $this->hostname,
-            $this->enableTLS,
-            $this->debug,
-            $this->timeout,
-            $this->port,
-            $this->referrals
-        );
-
-        if (!$this->searchEnable) {
-            $ldapusername = addcslashes($username, ',+"\\<>;*');
-            $dn = str_replace('%username%', $ldapusername, $this->dnPattern);
-        } else {
-            if ($this->searchUsername !== null) {
-                if (!$ldap->bind($this->searchUsername, $this->searchPassword)) {
-                    throw new \Exception('Error authenticating using search username & password.');
-                }
-            }
-
-            $dn = $ldap->searchfordn(
-                $this->searchBase,
-                $this->searchAttributes,
-                $username,
-                true,
-                $this->searchFilter,
-                $this->searchScope
-            );
-            if ($dn === null) {
-                /* User not found with search. */
-                \SimpleSAML\Logger::info($this->location.': Unable to find users DN. username=\''.$username.'\'');
-                throw new \SimpleSAML\Error\Error('WRONGUSERPASS');
-            }
-        }
-
-        if (!$ldap->bind($dn, $password, $sasl_args)) {
-            \SimpleSAML\Logger::info($this->location.': '.$username.' failed to authenticate. DN='.$dn);
-            throw new \SimpleSAML\Error\Error('WRONGUSERPASS');
-        }
-
-        // In case of SASL bind, authenticated and authorized DN may differ
-        if (isset($sasl_args)) {
-            $dn = $ldap->whoami($this->searchBase, $this->searchAttributes);
-        }
-
-        // Are privs needed to get the attributes?
-        if ($this->privRead) {
-            // Yes, rebind with privs
-            if (!$ldap->bind($this->privUsername, $this->privPassword)) {
-                throw new \Exception('Error authenticating using privileged DN & password.');
-            }
-        }
-
-        return $ldap->getAttributes($dn, $this->attributes);
-    }
-
-
-    /**
-     * Search for a DN.
-     *
-     * @param string|array $attribute
-     * The attribute name(s) searched for. If set to NULL, values from
-     * configuration is used.
-     * @param string $value
-     * The attribute value searched for.
-     * @param bool $allowZeroHits
-     * Determines if the method will throw an exception if no
-     * hits are found. Defaults to FALSE.
-     * @return string|null
-     * The DN of the matching element, if found. If no element was
-     * found and $allowZeroHits is set to FALSE, an exception will
-     * be thrown; otherwise NULL will be returned.
-     * @throws \SimpleSAML\Error\AuthSource if:
-     * - LDAP search encounter some problems when searching cataloge
-     * - Not able to connect to LDAP server
-     * @throws \SimpleSAML\Error\UserNotFound if:
-     * - $allowZeroHits is FALSE and no result is found
-     *
-     */
-    public function searchfordn($attribute, $value, $allowZeroHits)
-    {
-        $ldap = new \SimpleSAML\Auth\LDAP(
-            $this->hostname,
-            $this->enableTLS,
-            $this->debug,
-            $this->timeout,
-            $this->port,
-            $this->referrals
-        );
-
-        if ($attribute == null) {
-            $attribute = $this->searchAttributes;
-        }
-
-        if ($this->searchUsername !== null) {
-            if (!$ldap->bind($this->searchUsername, $this->searchPassword)) {
-                throw new \Exception('Error authenticating using search username & password.');
-            }
-        }
-
-        return $ldap->searchfordn(
-            $this->searchBase,
-            $attribute,
-            $value,
-            $allowZeroHits,
-            $this->searchFilter,
-            $this->searchScope
-        );
-    }
-
-
-    /**
-     * @param string $dn
-     * @param array|null $attributes
-     * @return array
-     * @throws \Exception
-     */
-    public function getAttributes($dn, $attributes = null)
-    {
-        if ($attributes == null) {
-            $attributes = $this->attributes;
-        }
-
-        $ldap = new \SimpleSAML\Auth\LDAP(
-            $this->hostname,
-            $this->enableTLS,
-            $this->debug,
-            $this->timeout,
-            $this->port,
-            $this->referrals
-        );
-
-        // Are privs needed to get the attributes?
-        if ($this->privRead) {
-            // Yes, rebind with privs
-            if (!$ldap->bind($this->privUsername, $this->privPassword)) {
-                throw new \Exception('Error authenticating using privileged DN & password.');
-            }
-        }
-        return $ldap->getAttributes($dn, $attributes);
-    }
-}
diff --git a/tests/modules/ldap/lib/Auth/Process/BaseFilterTest.php b/tests/modules/ldap/lib/Auth/Process/BaseFilterTest.php
deleted file mode 100644
index 05f808ee5..000000000
--- a/tests/modules/ldap/lib/Auth/Process/BaseFilterTest.php
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php
-
-namespace SimpleSAML\Test\Module\ldap\Auth\Process;
-
-use PHPUnit\Framework\TestCase;
-
-class BaseFilterTest extends TestCase
-{
-    public function testVarExportHidesLdapPassword()
-    {
-        $stub = $this->getMockBuilder('\SimpleSAML\Module\ldap\Auth\Process\BaseFilter')
-            ->disableOriginalConstructor()
-            ->getMockForAbstractClass();
-        $class = new \ReflectionClass($stub);
-        $method = $class->getMethod('var_export');
-        $method->setAccessible(true);
-
-        $this->assertEquals(
-            "array ( 'ldap.hostname' => 'ldap://172.17.101.32', 'ldap.port' => 389, 'ldap.password' => '********', )",
-            $method->invokeArgs($stub, [[
-                'ldap.hostname' => 'ldap://172.17.101.32',
-                'ldap.port' => 389,
-                'ldap.password' => 'password',
-            ]])
-        );
-    }
-}
-- 
GitLab