From 052743ea8af72f77eb971c2f2ae21f85fef4f69a Mon Sep 17 00:00:00 2001 From: Lai Power Date: Sun, 22 Oct 2023 22:20:57 +0000 Subject: [PATCH] updated plugin `AuthLDAP` version 2.5.9 --- wp-content/plugins/authldap/.phive/phars.xml | 6 + wp-content/plugins/authldap/README.md | 4 +- wp-content/plugins/authldap/SECURITY.md | 18 + wp-content/plugins/authldap/authLdap.php | 1242 +++++++++-------- wp-content/plugins/authldap/ldap.php | 275 ---- wp-content/plugins/authldap/phpcs.xml | 22 + wp-content/plugins/authldap/readme.txt | 32 +- wp-content/plugins/authldap/security.txt | 6 + .../plugins/authldap/src/Exception/Error.php | 4 +- .../authldap/src/Exception/InvalidLdapUri.php | 67 +- .../Exception/MissingValidLdapConnection.php | 23 + .../src/Exception/SearchUnsuccessfull.php | 24 + wp-content/plugins/authldap/src/LdapList.php | 13 +- wp-content/plugins/authldap/src/LdapUri.php | 169 ++- .../plugins/authldap/src/Manager/Ldap.php | 164 +++ .../plugins/authldap/src/UserRoleHandler.php | 54 + .../plugins/authldap/src/Wrapper/Ldap.php | 92 ++ .../authldap/src/Wrapper/LdapFactory.php | 24 + .../authldap/src/Wrapper/LdapInterface.php | 39 + wp-content/plugins/authldap/view/admin.phtml | 3 +- 20 files changed, 1368 insertions(+), 913 deletions(-) create mode 100644 wp-content/plugins/authldap/.phive/phars.xml create mode 100644 wp-content/plugins/authldap/SECURITY.md delete mode 100644 wp-content/plugins/authldap/ldap.php create mode 100644 wp-content/plugins/authldap/phpcs.xml create mode 100644 wp-content/plugins/authldap/security.txt create mode 100644 wp-content/plugins/authldap/src/Exception/MissingValidLdapConnection.php create mode 100644 wp-content/plugins/authldap/src/Exception/SearchUnsuccessfull.php create mode 100644 wp-content/plugins/authldap/src/Manager/Ldap.php create mode 100644 wp-content/plugins/authldap/src/UserRoleHandler.php create mode 100644 wp-content/plugins/authldap/src/Wrapper/Ldap.php create mode 100644 wp-content/plugins/authldap/src/Wrapper/LdapFactory.php create mode 100644 wp-content/plugins/authldap/src/Wrapper/LdapInterface.php diff --git a/wp-content/plugins/authldap/.phive/phars.xml b/wp-content/plugins/authldap/.phive/phars.xml new file mode 100644 index 00000000..2825dbbc --- /dev/null +++ b/wp-content/plugins/authldap/.phive/phars.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/wp-content/plugins/authldap/README.md b/wp-content/plugins/authldap/README.md index 325544e7..db54d089 100644 --- a/wp-content/plugins/authldap/README.md +++ b/wp-content/plugins/authldap/README.md @@ -4,12 +4,12 @@ Use your existing LDAP as authentication-backend for your wordpress! -[![Build Status](https://travis-ci.org/heiglandreas/authLdap.svg?branch=master)](https://travis-ci.org/heiglandreas/authLdap) +[![Build Status](https://github.com/heiglandreas/authLdap/actions/workflows/tests.yml/badge.svg)](https://github.com/heiglandreas/authLdap/actions/workflows/tests.yml) [![WordPress Stats](https://img.shields.io/wordpress/plugin/dt/authldap.svg)](https://wordpress.org/plugins/authldap/stats/) [![WordPress Version](https://img.shields.io/wordpress/plugin/v/authldap.svg)](https://wordpress.org/plugins/authldap/) [![WordPress testet](https://img.shields.io/wordpress/v/authldap.svg)](https://wordpress.org/plugins/authldap/) [![Code Climate](https://codeclimate.com/github/heiglandreas/authLdap/badges/gpa.svg)](https://codeclimate.com/github/heiglandreas/authLdap) -[![Test Coverage](https://codeclimate.com/github/heiglandreas/authLdap/badges/coverage.svg)](https://codeclimate.com/github/heiglandreas/authLdap) +[![codecov](https://codecov.io/gh/heiglandreas/authLdap/branch/master/graph/badge.svg?token=AYAhEeWtRQ)](https://codecov.io/gh/heiglandreas/authLdap) So what are the differences to other Wordpress-LDAP-Authentication-Plugins? diff --git a/wp-content/plugins/authldap/SECURITY.md b/wp-content/plugins/authldap/SECURITY.md new file mode 100644 index 00000000..ef57848c --- /dev/null +++ b/wp-content/plugins/authldap/SECURITY.md @@ -0,0 +1,18 @@ +# Security-Policy + +## Supported Versions + +| Version | Supported | +| ------- |--------------------| +| 2.x | :white_check_mark: | +| 1.x | :x: | + +## Reporting a Vulnerability + +* Check our security.txt file for details on how to contact us +* Contact us before publicly disclosing the issue anywhere else + +This plugin is developed as OpenSource under the MIT licence. +There is no money earned from it. Therefore we are not able to +provide any bug-bounties whatsoever. You will be mentioned in the +release notes of a fix-release though. diff --git a/wp-content/plugins/authldap/authLdap.php b/wp-content/plugins/authldap/authLdap.php index 4e09bce8..542ea85e 100644 --- a/wp-content/plugins/authldap/authLdap.php +++ b/wp-content/plugins/authldap/authLdap.php @@ -1,9 +1,10 @@ Author URI: http://andreas.heigl.org License: MIT @@ -12,128 +13,148 @@ License URI: https://opensource.org/licenses/MIT // phpcs:disable PSR1.Files.SideEffects +use Org_Heigl\AuthLdap\LdapList; use Org_Heigl\AuthLdap\LdapUri; +use Org_Heigl\AuthLdap\Manager\Ldap; +use Org_Heigl\AuthLdap\UserRoleHandler; +use Org_Heigl\AuthLdap\Wrapper\LdapFactory; -require_once dirname(__FILE__) . '/ldap.php'; -require_once __DIR__ . '/src/LdapUri.php'; +require_once __DIR__ . '/src/Wrapper/LdapInterface.php'; require_once __DIR__ . '/src/Exception/Error.php'; require_once __DIR__ . '/src/Exception/InvalidLdapUri.php'; +require_once __DIR__ . '/src/Exception/Error.php'; +require_once __DIR__ . '/src/Exception/InvalidLdapUri.php'; +require_once __DIR__ . '/src/Exception/MissingValidLdapConnection.php'; +require_once __DIR__ . '/src/Exception/SearchUnsuccessfull.php'; +require_once __DIR__ . '/src/Manager/Ldap.php'; +require_once __DIR__ . '/src/Wrapper/Ldap.php'; +require_once __DIR__ . '/src/Wrapper/LdapFactory.php'; +require_once __DIR__ . '/src/LdapList.php'; +require_once __DIR__ . '/src/LdapUri.php'; +require_once __DIR__ . '/src/UserRoleHandler.php'; function authLdap_debug($message) { - if (authLdap_get_option('Debug')) { - error_log('[AuthLDAP] ' . $message, 0); - } + if (authLdap_get_option('Debug')) { + error_log('[AuthLDAP] ' . $message, 0); + } } function authLdap_addmenu() { - if (! is_multisite()) { - add_options_page( - 'AuthLDAP', - 'AuthLDAP', - 'manage_options', - basename(__FILE__), - 'authLdap_options_panel' - ); - } else { - add_submenu_page( - 'settings.php', - 'AuthLDAP', - 'AuthLDAP', - 'manage_options', - 'authldap', - 'authLdap_options_panel' - ); - } + if (!is_multisite()) { + add_options_page( + 'AuthLDAP', + 'AuthLDAP', + 'manage_options', + basename(__FILE__), + 'authLdap_options_panel' + ); + } else { + add_submenu_page( + 'settings.php', + 'AuthLDAP', + 'AuthLDAP', + 'manage_options', + 'authldap', + 'authLdap_options_panel' + ); + } } function authLdap_get_post($name, $default = '') { - return isset($_POST[$name]) ? $_POST[$name] : $default; + return isset($_POST[$name]) ? $_POST[$name] : $default; } function authLdap_options_panel() { - // inclusde style sheet - wp_enqueue_style('authLdap-style', plugin_dir_url(__FILE__) . 'authLdap.css'); + // inclusde style sheet + wp_enqueue_style('authLdap-style', plugin_dir_url(__FILE__) . 'authLdap.css'); - if (($_SERVER['REQUEST_METHOD'] == 'POST') && array_key_exists('ldapOptionsSave', $_POST)) { - $new_options = array( - 'Enabled' => authLdap_get_post('authLDAPAuth', false), - 'CachePW' => authLdap_get_post('authLDAPCachePW', false), - 'URI' => authLdap_get_post('authLDAPURI'), - 'URISeparator' => authLdap_get_post('authLDAPURISeparator'), - 'StartTLS' => authLdap_get_post('authLDAPStartTLS', false), - 'Filter' => authLdap_get_post('authLDAPFilter'), - 'NameAttr' => authLdap_get_post('authLDAPNameAttr'), - 'SecName' => authLdap_get_post('authLDAPSecName'), - 'UidAttr' => authLdap_get_post('authLDAPUidAttr'), - 'MailAttr' => authLdap_get_post('authLDAPMailAttr'), - 'WebAttr' => authLdap_get_post('authLDAPWebAttr'), - 'Groups' => authLdap_get_post('authLDAPGroups', array()), - 'GroupSeparator'=> authLdap_get_post('authLDAPGroupSeparator', ','), - 'Debug' => authLdap_get_post('authLDAPDebug', false), - 'GroupBase' => authLdap_get_post('authLDAPGroupBase'), - 'GroupAttr' => authLdap_get_post('authLDAPGroupAttr'), - 'GroupFilter' => authLdap_get_post('authLDAPGroupFilter'), - 'DefaultRole' => authLdap_get_post('authLDAPDefaultRole'), - 'GroupEnable' => authLdap_get_post('authLDAPGroupEnable', false), - 'GroupOverUser' => authLdap_get_post('authLDAPGroupOverUser', false), - 'DoNotOverwriteNonLdapUsers' => authLdap_get_post('authLDAPDoNotOverwriteNonLdapUsers', false), + if (($_SERVER['REQUEST_METHOD'] == 'POST') && array_key_exists('ldapOptionsSave', $_POST)) { + if (!isset($_POST['authLdapNonce'])) { + die("Go away!"); + } + if (!wp_verify_nonce($_POST['authLdapNonce'],'authLdapNonce')) { + die("Go away!"); + } + + $new_options = [ + 'Enabled' => authLdap_get_post('authLDAPAuth', false), + 'CachePW' => authLdap_get_post('authLDAPCachePW', false), + 'URI' => authLdap_get_post('authLDAPURI'), + 'URISeparator' => authLdap_get_post('authLDAPURISeparator'), + 'StartTLS' => authLdap_get_post('authLDAPStartTLS', false), + 'Filter' => authLdap_get_post('authLDAPFilter'), + 'NameAttr' => authLdap_get_post('authLDAPNameAttr'), + 'SecName' => authLdap_get_post('authLDAPSecName'), + 'UidAttr' => authLdap_get_post('authLDAPUidAttr'), + 'MailAttr' => authLdap_get_post('authLDAPMailAttr'), + 'WebAttr' => authLdap_get_post('authLDAPWebAttr'), + 'Groups' => authLdap_get_post('authLDAPGroups', []), + 'GroupSeparator' => authLdap_get_post('authLDAPGroupSeparator', ','), + 'Debug' => authLdap_get_post('authLDAPDebug', false), + 'GroupBase' => authLdap_get_post('authLDAPGroupBase'), + 'GroupAttr' => authLdap_get_post('authLDAPGroupAttr'), + 'GroupFilter' => authLdap_get_post('authLDAPGroupFilter'), + 'DefaultRole' => authLdap_get_post('authLDAPDefaultRole'), + 'GroupEnable' => authLdap_get_post('authLDAPGroupEnable', false), + 'GroupOverUser' => authLdap_get_post('authLDAPGroupOverUser', false), + 'DoNotOverwriteNonLdapUsers' => authLdap_get_post('authLDAPDoNotOverwriteNonLdapUsers', false), 'UserRead' => authLdap_get_post('authLDAPUseUserAccount', false), - ); - if (authLdap_set_options($new_options)) { - echo "

Saved Options!

"; - } else { - echo "

Could not save Options!

"; - } - } + ]; + if (authLdap_set_options($new_options)) { + echo "

Saved Options!

"; + } else { + echo "

Could not save Options!

"; + } + } - // Do some initialization for the admin-view - $authLDAP = authLdap_get_option('Enabled'); - $authLDAPCachePW = authLdap_get_option('CachePW'); - $authLDAPURI = authLdap_get_option('URI'); - $authLDAPURISeparator = authLdap_get_option('URISeparator'); - $authLDAPStartTLS = authLdap_get_option('StartTLS'); - $authLDAPFilter = authLdap_get_option('Filter'); - $authLDAPNameAttr = authLdap_get_option('NameAttr'); - $authLDAPSecName = authLdap_get_option('SecName'); - $authLDAPMailAttr = authLdap_get_option('MailAttr'); - $authLDAPUidAttr = authLdap_get_option('UidAttr'); - $authLDAPWebAttr = authLdap_get_option('WebAttr'); - $authLDAPGroups = authLdap_get_option('Groups'); - $authLDAPGroupSeparator= authLdap_get_option('GroupSeparator'); - $authLDAPDebug = authLdap_get_option('Debug'); - $authLDAPGroupBase = authLdap_get_option('GroupBase'); - $authLDAPGroupAttr = authLdap_get_option('GroupAttr'); - $authLDAPGroupFilter = authLdap_get_option('GroupFilter'); - $authLDAPDefaultRole = authLdap_get_option('DefaultRole'); - $authLDAPGroupEnable = authLdap_get_option('GroupEnable'); - $authLDAPGroupOverUser = authLdap_get_option('GroupOverUser'); - $authLDAPDoNotOverwriteNonLdapUsers = authLdap_get_option('DoNotOverwriteNonLdapUsers'); - $authLDAPUseUserAccount= authLdap_get_option('UserRead'); + // Do some initialization for the admin-view + $authLDAP = authLdap_get_option('Enabled'); + $authLDAPCachePW = authLdap_get_option('CachePW'); + $authLDAPURI = authLdap_get_option('URI'); + $authLDAPURISeparator = authLdap_get_option('URISeparator'); + $authLDAPStartTLS = authLdap_get_option('StartTLS'); + $authLDAPFilter = authLdap_get_option('Filter'); + $authLDAPNameAttr = authLdap_get_option('NameAttr'); + $authLDAPSecName = authLdap_get_option('SecName'); + $authLDAPMailAttr = authLdap_get_option('MailAttr'); + $authLDAPUidAttr = authLdap_get_option('UidAttr'); + $authLDAPWebAttr = authLdap_get_option('WebAttr'); + $authLDAPGroups = authLdap_get_option('Groups'); + $authLDAPGroupSeparator = authLdap_get_option('GroupSeparator'); + $authLDAPDebug = authLdap_get_option('Debug'); + $authLDAPGroupBase = authLdap_get_option('GroupBase'); + $authLDAPGroupAttr = authLdap_get_option('GroupAttr'); + $authLDAPGroupFilter = authLdap_get_option('GroupFilter'); + $authLDAPDefaultRole = authLdap_get_option('DefaultRole'); + $authLDAPGroupEnable = authLdap_get_option('GroupEnable'); + $authLDAPGroupOverUser = authLdap_get_option('GroupOverUser'); + $authLDAPDoNotOverwriteNonLdapUsers = authLdap_get_option('DoNotOverwriteNonLdapUsers'); + $authLDAPUseUserAccount = authLdap_get_option('UserRead'); - $tChecked = ($authLDAP) ? ' checked="checked"' : ''; - $tDebugChecked = ($authLDAPDebug) ? ' checked="checked"' : ''; - $tPWChecked = ($authLDAPCachePW) ? ' checked="checked"' : ''; - $tGroupChecked = ($authLDAPGroupEnable) ? ' checked="checked"' : ''; - $tGroupOverUserChecked = ($authLDAPGroupOverUser) ? ' checked="checked"' : ''; - $tStartTLSChecked = ($authLDAPStartTLS) ? ' checked="checked"' : ''; - $tDoNotOverwriteNonLdapUsers = ($authLDAPDoNotOverwriteNonLdapUsers) ? ' checked="checked"' : ''; - $tUserRead = ($authLDAPUseUserAccount) ? ' checked="checked"' : ''; + $tChecked = ($authLDAP) ? ' checked="checked"' : ''; + $tDebugChecked = ($authLDAPDebug) ? ' checked="checked"' : ''; + $tPWChecked = ($authLDAPCachePW) ? ' checked="checked"' : ''; + $tGroupChecked = ($authLDAPGroupEnable) ? ' checked="checked"' : ''; + $tGroupOverUserChecked = ($authLDAPGroupOverUser) ? ' checked="checked"' : ''; + $tStartTLSChecked = ($authLDAPStartTLS) ? ' checked="checked"' : ''; + $tDoNotOverwriteNonLdapUsers = ($authLDAPDoNotOverwriteNonLdapUsers) ? ' checked="checked"' : ''; + $tUserRead = ($authLDAPUseUserAccount) ? ' checked="checked"' : ''; - $roles = new WP_Roles(); + $roles = new WP_Roles(); - $action = $_SERVER['REQUEST_URI']; - if (! extension_loaded('ldap')) { - echo '
The LDAP-Extension is not available on your ' - . 'WebServer. Therefore Everything you can alter here does not ' - . 'make any sense!
'; - } + $action = $_SERVER['REQUEST_URI']; + if (!extension_loaded('ldap')) { + echo '
The LDAP-Extension is not available on your ' + . 'WebServer. Therefore Everything you can alter here does not ' + . 'make any sense!
'; + } - include dirname(__FILE__) . '/view/admin.phtml'; + include dirname(__FILE__) . '/view/admin.phtml'; } /** @@ -148,28 +169,28 @@ function authLdap_options_panel() */ function authLdap_get_server() { - static $_ldapserver = null; - if (is_null($_ldapserver)) { - $authLDAPDebug = authLdap_get_option('Debug'); - $authLDAPURI = explode( - authLdap_get_option('URISeparator', ' '), - authLdap_get_option('URI') - ); - $authLDAPStartTLS = authLdap_get_option('StartTLS'); + static $_ldapserver = null; + if (is_null($_ldapserver)) { + $authLDAPDebug = authLdap_get_option('Debug'); + $authLDAPURI = explode( + authLdap_get_option('URISeparator', ' '), + authLdap_get_option('URI') + ); + $authLDAPStartTLS = authLdap_get_option('StartTLS'); - //$authLDAPURI = 'ldap:/foo:bar@server/trallala'; - authLdap_debug('connect to LDAP server'); - require_once dirname(__FILE__) . '/src/LdapList.php'; - $_ldapserver = new \Org_Heigl\AuthLdap\LdapList(); - foreach ($authLDAPURI as $uri) { - $_ldapserver->addLdap(new \Org_Heigl\AuthLdap\LDAP( - LdapUri::fromString($uri), - $authLDAPDebug, - $authLDAPStartTLS - )); - } - } - return $_ldapserver; + //$authLDAPURI = 'ldap:/foo:bar@server/trallala'; + authLdap_debug('connect to LDAP server'); + require_once dirname(__FILE__) . '/src/LdapList.php'; + $_ldapserver = new LdapList(); + foreach ($authLDAPURI as $uri) { + $_ldapserver->addLdap(new Ldap( + new LdapFactory(), + LdapUri::fromString($uri), + $authLDAPStartTLS + )); + } + } + return $_ldapserver; } @@ -198,281 +219,308 @@ function authLdap_get_server() */ function authLdap_login($user, $username, $password, $already_md5 = false) { - // don't do anything when authLDAP is disabled - if (! authLdap_get_option('Enabled')) { - authLdap_debug( - 'LDAP disabled in AuthLDAP plugin options (use the first option in the AuthLDAP options to enable it)' - ); - return $user; - } + // don't do anything when authLDAP is disabled + if (!authLdap_get_option('Enabled')) { + authLdap_debug( + 'LDAP disabled in AuthLDAP plugin options (use the first option in the AuthLDAP options to enable it)' + ); + return $user; + } - // If the user has already been authenticated (only in that case we get a - // WP_User-Object as $user) we skip LDAP-authentication and simply return - // the existing user-object - if ($user instanceof WP_User) { - authLdap_debug(sprintf( - 'User %s has already been authenticated - skipping LDAP-Authentication', - $user->get('nickname') - )); - return $user; - } + // If the user has already been authenticated (only in that case we get a + // WP_User-Object as $user) we skip LDAP-authentication and simply return + // the existing user-object + if ($user instanceof WP_User) { + authLdap_debug(sprintf( + 'User %s has already been authenticated - skipping LDAP-Authentication', + $user->get('nickname') + )); + return $user; + } - authLdap_debug("User '$username' logging in"); + authLdap_debug("User '$username' logging in"); - if ($username == 'admin') { - authLdap_debug('Doing nothing for possible local user admin'); - return $user; - } + if ($username == 'admin') { + authLdap_debug('Doing nothing for possible local user admin'); + return $user; + } - global $wpdb, $error; - try { - $authLDAP = authLdap_get_option('Enabled'); - $authLDAPFilter = authLdap_get_option('Filter'); - $authLDAPNameAttr = authLdap_get_option('NameAttr'); - $authLDAPSecName = authLdap_get_option('SecName'); - $authLDAPMailAttr = authLdap_get_option('MailAttr'); - $authLDAPUidAttr = authLdap_get_option('UidAttr'); - $authLDAPWebAttr = authLdap_get_option('WebAttr'); - $authLDAPDefaultRole = authLdap_get_option('DefaultRole'); - $authLDAPGroupEnable = authLdap_get_option('GroupEnable'); - $authLDAPGroupOverUser = authLdap_get_option('GroupOverUser'); + global $wpdb, $error; + try { + $authLDAP = authLdap_get_option('Enabled'); + $authLDAPFilter = authLdap_get_option('Filter'); + $authLDAPNameAttr = authLdap_get_option('NameAttr'); + $authLDAPSecName = authLdap_get_option('SecName'); + $authLDAPMailAttr = authLdap_get_option('MailAttr'); + $authLDAPUidAttr = authLdap_get_option('UidAttr'); + $authLDAPWebAttr = authLdap_get_option('WebAttr'); + $authLDAPDefaultRole = authLdap_get_option('DefaultRole'); + $authLDAPGroupEnable = authLdap_get_option('GroupEnable'); + $authLDAPGroupOverUser = authLdap_get_option('GroupOverUser'); $authLDAPUseUserAccount = authLdap_get_option('UserRead'); - if (! $username) { - authLdap_debug('Username not supplied: return false'); - return false; - } + if (!$username) { + authLdap_debug('Username not supplied: return false'); + return false; + } - if (! $password) { - authLdap_debug('Password not supplied: return false'); - $error = __('Error: The password field is empty.'); - return false; - } - // First check for valid values and set appropriate defaults - if (! $authLDAPFilter) { - $authLDAPFilter = '(uid=%s)'; - } - if (! $authLDAPNameAttr) { - $authLDAPNameAttr = 'name'; - } - if (! $authLDAPMailAttr) { - $authLDAPMailAttr = 'mail'; - } - if (! $authLDAPUidAttr) { - $authLDAPUidAttr = 'uid'; - } + if (!$password) { + authLdap_debug('Password not supplied: return false'); + $error = __('Error: The password field is empty.'); + return false; + } + // First check for valid values and set appropriate defaults + if (!$authLDAPFilter) { + $authLDAPFilter = '(uid=%s)'; + } + if (!$authLDAPNameAttr) { + $authLDAPNameAttr = 'name'; + } + if (!$authLDAPMailAttr) { + $authLDAPMailAttr = 'mail'; + } + if (!$authLDAPUidAttr) { + $authLDAPUidAttr = 'uid'; + } - // If already_md5 is TRUE, then we're getting the user/password from the cookie. As we don't want - // to store LDAP passwords in any - // form, we've already replaced the password with the hashed username and LDAP_COOKIE_MARKER - if ($already_md5) { - if ($password == md5($username).md5($ldapCookieMarker)) { - authLdap_debug('cookie authentication'); - return true; - } - } + // If already_md5 is TRUE, then we're getting the user/password from the cookie. As we don't want + // to store LDAP passwords in any + // form, we've already replaced the password with the hashed username and LDAP_COOKIE_MARKER + if ($already_md5) { + if ($password == md5($username) . md5($ldapCookieMarker)) { + authLdap_debug('cookie authentication'); + return true; + } + } - // Remove slashes as noted on https://github.com/heiglandreas/authLdap/issues/108 - $password = stripslashes_deep($password); + // Remove slashes as noted on https://github.com/heiglandreas/authLdap/issues/108 + $password = stripslashes_deep($password); - // No cookie, so have to authenticate them via LDAP - $result = false; - try { - authLdap_debug('about to do LDAP authentication'); - $result = authLdap_get_server()->Authenticate($username, $password, $authLDAPFilter); - } catch (Exception $e) { - authLdap_debug('LDAP authentication failed with exception: ' . $e->getMessage()); - return false; - } + // No cookie, so have to authenticate them via LDAP + $result = false; + try { + authLdap_debug('about to do LDAP authentication'); + $result = authLdap_get_server()->Authenticate($username, $password, $authLDAPFilter); + } catch (Exception $e) { + authLdap_debug('LDAP authentication failed with exception: ' . $e->getMessage()); + return false; + } // Make optional querying from the admin account #213 - if (! authLdap_get_option('UserRead')) { + if (!authLdap_get_option('UserRead')) { // Rebind with the default credentials after the user has been loged in // Otherwise the credentials of the user trying to login will be used // This fixes #55 authLdap_get_server()->bind(); } - if (true !== $result) { - authLdap_debug('LDAP authentication failed'); - // TODO what to return? WP_User object, true, false, even an WP_Error object... - // all seem to fall back to normal wp user authentication - return; - } + if (true !== $result) { + authLdap_debug('LDAP authentication failed'); + // TODO what to return? WP_User object, true, false, even an WP_Error object... + // all seem to fall back to normal wp user authentication + return; + } - authLdap_debug('LDAP authentication successful'); - $attributes = array_values( - array_filter( - apply_filters( - 'authLdap_filter_attributes', - array( - $authLDAPNameAttr, - $authLDAPSecName, - $authLDAPMailAttr, - $authLDAPWebAttr, - $authLDAPUidAttr - ) - ) - ) - ); + authLdap_debug('LDAP authentication successful'); + $attributes = array_values( + array_filter( + apply_filters( + 'authLdap_filter_attributes', + [ + $authLDAPNameAttr, + $authLDAPSecName, + $authLDAPMailAttr, + $authLDAPWebAttr, + $authLDAPUidAttr, + ] + ) + ) + ); - try { - $attribs = authLdap_get_server()->search( - sprintf($authLDAPFilter, $username), - $attributes - ); - // First get all the relevant group informations so we can see if - // whether have been changes in group association of the user - if (! isset($attribs[0]['dn'])) { - authLdap_debug('could not get user attributes from LDAP'); - throw new UnexpectedValueException('dn has not been returned'); - } - if (! isset($attribs[0][strtolower($authLDAPUidAttr)][0])) { - authLdap_debug('could not get user attributes from LDAP'); - throw new UnexpectedValueException('The user-ID attribute has not been returned'); - } + try { + $attribs = authLdap_get_server()->search( + sprintf($authLDAPFilter, $username), + $attributes + ); + // First get all the relevant group informations so we can see if + // whether have been changes in group association of the user + if (!isset($attribs[0]['dn'])) { + authLdap_debug('could not get user attributes from LDAP'); + throw new UnexpectedValueException('dn has not been returned'); + } + if (!isset($attribs[0][strtolower($authLDAPUidAttr)][0])) { + authLdap_debug('could not get user attributes from LDAP'); + throw new UnexpectedValueException('The user-ID attribute has not been returned'); + } - $dn = $attribs[0]['dn']; - $realuid = $attribs[0][strtolower($authLDAPUidAttr)][0]; - } catch (Exception $e) { - authLdap_debug('Exception getting LDAP user: ' . $e->getMessage()); - return false; - } + $dn = $attribs[0]['dn']; + $realuid = $attribs[0][strtolower($authLDAPUidAttr)][0]; + } catch (Exception $e) { + authLdap_debug('Exception getting LDAP user: ' . $e->getMessage()); + return false; + } - $uid = authLdap_get_uid($realuid); + $uid = authLdap_get_uid($realuid); - // This fixes #172 - if (true == authLdap_get_option('DoNotOverwriteNonLdapUsers', false)) { - if (! get_user_meta($uid, 'authLDAP')) { - return null; - } - } + // This fixes #172 + if (true == authLdap_get_option('DoNotOverwriteNonLdapUsers', false)) { + if (!get_user_meta($uid, 'authLDAP')) { + return null; + } + } - $role = ''; + $roles = []; - // we only need this if either LDAP groups are disabled or - // if the WordPress role of the user overrides LDAP groups - if (!$authLDAPGroupEnable || !$authLDAPGroupOverUser) { - $role = authLdap_user_role($uid); - } + // we only need this if either LDAP groups are disabled or + // if the WordPress role of the user overrides LDAP groups + if (!$authLDAPGroupEnable || !$authLDAPGroupOverUser) { + $role = authLdap_user_role($uid); + if ($role !== '') { + $roles[] = $role; + } + // TODO, this needs to be revised, it seems, like authldap is taking only the first role + // even if in WP there are assigned multiple. + } - // do LDAP group mapping if needed - // (if LDAP groups override worpress user role, $role is still empty) - if (empty($role) && $authLDAPGroupEnable) { - $role = authLdap_groupmap($realuid, $dn); - authLdap_debug('role from group mapping: ' . $role); - } + // do LDAP group mapping if needed + // (if LDAP groups override worpress user role, $role is still empty) + if (empty($roles) && $authLDAPGroupEnable) { + $mappedRoles = authLdap_groupmap($realuid, $dn); + if ($mappedRoles !== []) { + $roles = $mappedRoles; + authLdap_debug('role from group mapping: ' . json_encode($roles)); + } + } - // if we don't have a role yet, use default role - if (empty($role) && !empty($authLDAPDefaultRole)) { - authLdap_debug('no role yet, set default role'); - $role = $authLDAPDefaultRole; - } + // if we don't have a role yet, use default role + if (empty($roles) && !empty($authLDAPDefaultRole)) { + authLdap_debug('no role yet, set default role'); + $roles[] = $authLDAPDefaultRole; + } - if (empty($role)) { - // Sorry, but you are not in any group that is allowed access - trigger_error('no group found'); - authLdap_debug('user is not in any group that is allowed access'); - return false; - } else { - $roles = new WP_Roles(); - // not sure if this is needed, but it can't hurt - if (!$roles->is_role($role)) { - trigger_error('no group found'); - authLdap_debug('role is invalid'); - return false; - } - } + if (empty($roles)) { + // Sorry, but you are not in any group that is allowed access + trigger_error('no group found'); + authLdap_debug('user is not in any group that is allowed access'); + return false; + } else { + $wp_roles = new WP_Roles(); + // not sure if this is needed, but it can't hurt - // from here on, the user has access! - // now, lets update some user details - $user_info = array(); - $user_info['user_login'] = $realuid; - $user_info['role'] = $role; - $user_info['user_email'] = ''; - $user_info['user_nicename'] = ''; + // Get rid of unexisting roles. + foreach ($roles as $k => $v) { + if (!$wp_roles->is_role($v)) { + unset($k); + } + } - // first name - if (isset($attribs[0][strtolower($authLDAPNameAttr)][0])) { - $user_info['first_name'] = $attribs[0][strtolower($authLDAPNameAttr)][0]; - } + // check if single role or an empty array provided + if (empty($roles)) { + trigger_error('no group found'); + authLdap_debug('role is invalid'); + return false; + } + } - // last name - if (isset($attribs[0][strtolower($authLDAPSecName)][0])) { - $user_info['last_name'] = $attribs[0][strtolower($authLDAPSecName)][0]; - } + // from here on, the user has access! + // now, lets update some user details + $user_info = []; + $user_info['user_login'] = $realuid; + $user_info['user_email'] = ''; + $user_info['user_nicename'] = ''; - // mail address - if (isset($attribs[0][strtolower($authLDAPMailAttr)][0])) { - $user_info['user_email'] = $attribs[0][strtolower($authLDAPMailAttr)][0]; - } + // first name + if (isset($attribs[0][strtolower($authLDAPNameAttr)][0])) { + $user_info['first_name'] = $attribs[0][strtolower($authLDAPNameAttr)][0]; + } - // website - if (isset($attribs[0][strtolower($authLDAPWebAttr)][0])) { - $user_info['user_url'] = $attribs[0][strtolower($authLDAPWebAttr)][0]; - } - // display name, nickname, nicename - if (array_key_exists('first_name', $user_info)) { - $user_info['display_name'] = $user_info['first_name']; - $user_info['nickname'] = $user_info['first_name']; - $user_info['user_nicename'] = sanitize_title_with_dashes($user_info['first_name']); - if (array_key_exists('last_name', $user_info)) { - $user_info['display_name'] .= ' ' . $user_info['last_name']; - $user_info['nickname'] .= ' ' . $user_info['last_name']; - $user_info['user_nicename'] .= '_' . sanitize_title_with_dashes($user_info['last_name']); - } - } - $user_info['user_nicename'] = substr($user_info['user_nicename'], 0, 50); + // last name + if (isset($attribs[0][strtolower($authLDAPSecName)][0])) { + $user_info['last_name'] = $attribs[0][strtolower($authLDAPSecName)][0]; + } - // optionally store the password into the wordpress database - if (authLdap_get_option('CachePW')) { - // Password will be hashed inside wp_update_user or wp_insert_user - $user_info['user_pass'] = $password; - } else { - // clear the password - $user_info['user_pass'] = ''; - } + // mail address + if (isset($attribs[0][strtolower($authLDAPMailAttr)][0])) { + $user_info['user_email'] = $attribs[0][strtolower($authLDAPMailAttr)][0]; + } - // add uid if user exists - if ($uid) { - // found user in the database - authLdap_debug('The LDAP user has an entry in the WP-Database'); - $user_info['ID'] = $uid; - unset($user_info['display_name'], $user_info['nickname']); - $userid = wp_update_user($user_info); - } else { - // new wordpress account will be created - authLdap_debug('The LDAP user does not have an entry in the WP-Database, a new WP account will be created'); + // website + if (isset($attribs[0][strtolower($authLDAPWebAttr)][0])) { + $user_info['user_url'] = $attribs[0][strtolower($authLDAPWebAttr)][0]; + } + // display name, nickname, nicename + if (array_key_exists('first_name', $user_info)) { + $user_info['display_name'] = $user_info['first_name']; + $user_info['nickname'] = $user_info['first_name']; + $user_info['user_nicename'] = sanitize_title_with_dashes($user_info['first_name']); + if (array_key_exists('last_name', $user_info)) { + $user_info['display_name'] .= ' ' . $user_info['last_name']; + $user_info['nickname'] .= ' ' . $user_info['last_name']; + $user_info['user_nicename'] .= '_' . sanitize_title_with_dashes($user_info['last_name']); + } + } + $user_info['user_nicename'] = substr($user_info['user_nicename'], 0, 50); - $userid = wp_insert_user($user_info); - } + // optionally store the password into the wordpress database + if (authLdap_get_option('CachePW')) { + // Password will be hashed inside wp_update_user or wp_insert_user + $user_info['user_pass'] = $password; + } else { + // clear the password + $user_info['user_pass'] = ''; + } - // if the user exists, wp_insert_user will update the existing user record - if (is_wp_error($userid)) { - authLdap_debug('Error creating user : ' . $userid->get_error_message()); - trigger_error('Error creating user: ' . $userid->get_error_message()); - return $userid; - } + // add uid if user exists + if ($uid) { + // found user in the database + authLdap_debug('The LDAP user has an entry in the WP-Database'); + $user_info['ID'] = $uid; + unset($user_info['display_name'], $user_info['nickname']); + $userid = wp_update_user($user_info); + } else { + // new wordpress account will be created + authLdap_debug('The LDAP user does not have an entry in the WP-Database, a new WP account will be created'); - /** - * Add hook for custom updates - * - * @param int $userid User ID. - * @param array $attribs[0] Attributes retrieved from LDAP for the user. - */ - do_action('authLdap_login_successful', $userid, $attribs[0]); + $userid = wp_insert_user($user_info); + } - authLdap_debug('user id = ' . $userid); + // if the user exists, wp_insert_user will update the existing user record + if (is_wp_error($userid)) { + authLdap_debug('Error creating user : ' . $userid->get_error_message()); + trigger_error('Error creating user: ' . $userid->get_error_message()); + return $userid; + } - // flag the user as an ldap user so we can hide the password fields in the user profile - update_user_meta($userid, 'authLDAP', true); + // Update user roles. + $user = new \WP_User($userid); - // return a user object upon positive authorization - return new WP_User($userid); - } catch (Exception $e) { - authLdap_debug($e->getMessage() . '. Exception thrown in line ' . $e->getLine()); - trigger_error($e->getMessage() . '. Exception thrown in line ' . $e->getLine()); - } + /** + * Add hook for custom User-Role assignment + * + * @param WP_User $user This user-object will be returned. Can be modified as necessary in the actions. + * @param array $roles + */ + do_action('authldap_user_roles', $user, $roles); + + /** + * Add hook for custom updates + * + * @param int $userid User ID. + * @param array $attribs [0] Attributes retrieved from LDAP for the user. + */ + do_action('authLdap_login_successful', $userid, $attribs[0]); + + authLdap_debug('user id = ' . $userid); + + // flag the user as an ldap user so we can hide the password fields in the user profile + update_user_meta($userid, 'authLDAP', true); + + // return a user object upon positive authorization + return $user; + } catch (Exception $e) { + authLdap_debug($e->getMessage() . '. Exception thrown in line ' . $e->getLine()); + trigger_error($e->getMessage() . '. Exception thrown in line ' . $e->getLine()); + } } /** @@ -485,21 +533,21 @@ function authLdap_login($user, $username, $password, $already_md5 = false) */ function authLdap_get_uid($username) { - global $wpdb; + global $wpdb; - // find out whether the user is already present in the database - $uid = $wpdb->get_var( - $wpdb->prepare( - "SELECT ID FROM {$wpdb->users} WHERE user_login = %s", - $username - ) - ); - if ($uid) { - authLdap_debug("Existing user, uid = {$uid}"); - return $uid; - } else { - return null; - } + // find out whether the user is already present in the database + $uid = $wpdb->get_var( + $wpdb->prepare( + "SELECT ID FROM {$wpdb->users} WHERE user_login = %s", + $username + ) + ); + if ($uid) { + authLdap_debug("Existing user, uid = {$uid}"); + return $uid; + } else { + return null; + } } /** @@ -512,28 +560,28 @@ function authLdap_get_uid($username) */ function authLdap_user_role($uid) { - global $wpdb, $wp_roles; + global $wpdb, $wp_roles; - if (!$uid) { - return ''; - } + if (!$uid) { + return ''; + } - /** @var array $usercapabilities */ - $usercapabilities = get_user_meta( $uid, "{$wpdb->prefix}capabilities", true); - if ( ! is_array( $usercapabilities ) ) { - return ''; - } + /** @var array $usercapabilities */ + $usercapabilities = get_user_meta($uid, "{$wpdb->prefix}capabilities", true); + if (!is_array($usercapabilities)) { + return ''; + } - /** @var array} $editable_roles */ - $editable_roles = $wp_roles->roles; + /** @var array} $editable_roles */ + $editable_roles = $wp_roles->roles; - // By using this approach we are now using the order of the roles from the WP_Roles object - // and not from the capabilities any more. - $userroles = array_keys(array_intersect_key($editable_roles, $usercapabilities)); - $role = $userroles[0]; + // By using this approach we are now using the order of the roles from the WP_Roles object + // and not from the capabilities any more. + $userroles = array_keys(array_intersect_key($editable_roles, $usercapabilities)); + $role = ($userroles !== []) ? $userroles[0] : ''; - authLdap_debug("Existing user's role: {$role}"); - return $role; + authLdap_debug("Existing user's role: {$role}"); + return $role; } /** @@ -541,7 +589,7 @@ function authLdap_user_role($uid) * * @param string $username * @param string $dn - * @return string role, empty string if no mapping found, first found role otherwise + * @return array role, empty array if no mapping found, first or all role(s) found otherwise * @conf array authLDAPGroups, associative array, role => ldap_group * @conf string authLDAPGroupBase, base dn to look up groups * @conf string authLDAPGroupAttr, ldap attribute that holds name of group @@ -549,76 +597,86 @@ function authLdap_user_role($uid) */ function authLdap_groupmap($username, $dn) { - $authLDAPGroups = authLdap_sort_roles_by_capabilities( - authLdap_get_option('Groups') - ); - $authLDAPGroupBase = authLdap_get_option('GroupBase'); - $authLDAPGroupAttr = authLdap_get_option('GroupAttr'); - $authLDAPGroupFilter = authLdap_get_option('GroupFilter'); - $authLDAPGroupSeparator = authLdap_get_option('GroupSeparator'); - if (! $authLDAPGroupAttr) { - $authLDAPGroupAttr = 'gidNumber'; - } - if (! $authLDAPGroupFilter) { - $authLDAPGroupFilter = '(&(objectClass=posixGroup)(memberUid=%s))'; - } - if (! $authLDAPGroupSeparator) { - $authLDAPGroupSeparator = ','; - } + $authLDAPGroups = authLdap_sort_roles_by_capabilities( + authLdap_get_option('Groups') + ); + $authLDAPGroupBase = authLdap_get_option('GroupBase'); + $authLDAPGroupAttr = authLdap_get_option('GroupAttr'); + $authLDAPGroupFilter = authLdap_get_option('GroupFilter'); + $authLDAPGroupSeparator = authLdap_get_option('GroupSeparator'); + if (!$authLDAPGroupAttr) { + $authLDAPGroupAttr = 'gidNumber'; + } + if (!$authLDAPGroupFilter) { + $authLDAPGroupFilter = '(&(objectClass=posixGroup)(memberUid=%s))'; + } + if (!$authLDAPGroupSeparator) { + $authLDAPGroupSeparator = ','; + } - if (!is_array($authLDAPGroups) || count(array_filter(array_values($authLDAPGroups))) == 0) { - authLdap_debug('No group names defined'); - return ''; - } + if (!is_array($authLDAPGroups) || count(array_filter(array_values($authLDAPGroups))) == 0) { + authLdap_debug('No group names defined'); + return []; + } - try { - // To allow searches based on the DN instead of the uid, we replace the - // string %dn% with the users DN. - $authLDAPGroupFilter = str_replace( - '%dn%', - ldap_escape($dn, '', LDAP_ESCAPE_FILTER), - $authLDAPGroupFilter - ); - authLdap_debug('Group Filter: ' . json_encode($authLDAPGroupFilter)); - authLdap_debug('Group Base: ' . $authLDAPGroupBase); - $groups = authLdap_get_server()->search( - sprintf($authLDAPGroupFilter, ldap_escape($username, '', LDAP_ESCAPE_FILTER)), - array($authLDAPGroupAttr), - $authLDAPGroupBase - ); - } catch (Exception $e) { - authLdap_debug('Exception getting LDAP group attributes: ' . $e->getMessage()); - return ''; - } + try { + // To allow searches based on the DN instead of the uid, we replace the + // string %dn% with the users DN. + $authLDAPGroupFilter = str_replace( + '%dn%', + ldap_escape($dn, '', LDAP_ESCAPE_FILTER), + $authLDAPGroupFilter + ); + authLdap_debug('Group Filter: ' . json_encode($authLDAPGroupFilter)); + authLdap_debug('Group Base: ' . $authLDAPGroupBase); + $groups = authLdap_get_server()->search( + sprintf($authLDAPGroupFilter, ldap_escape($username, '', LDAP_ESCAPE_FILTER)), + [$authLDAPGroupAttr], + $authLDAPGroupBase + ); + } catch (Exception $e) { + authLdap_debug('Exception getting LDAP group attributes: ' . $e->getMessage()); + return []; + } - $grp = array(); - for ($i = 0; $i < $groups ['count']; $i++) { - for ($k = 0; $k < $groups[$i][strtolower($authLDAPGroupAttr)]['count']; $k++) { - $grp[] = $groups[$i][strtolower($authLDAPGroupAttr)][$k]; - } - } + $grp = []; + for ($i = 0; $i < $groups ['count']; $i++) { + if ($authLDAPGroupAttr == "dn") { + $grp[] = $groups[$i]['dn']; + } else { + for ($k = 0; $k < $groups[$i][strtolower($authLDAPGroupAttr)]['count']; $k++) { + $grp[] = $groups[$i][strtolower($authLDAPGroupAttr)][$k]; + } + } + } - authLdap_debug('LDAP groups: ' . json_encode($grp)); + authLdap_debug('LDAP groups: ' . json_encode($grp)); - // Check whether the user is member of one of the groups that are - // allowed acces to the blog. If the user is not member of one of - // The groups throw her out! ;-) - // If the user is member of more than one group only the first one - // will be taken into account! + // Check whether the user is member of one of the groups that are + // allowed acces to the blog. If the user is not member of one of + // The groups throw her out! ;-) + $roles = []; + foreach ($authLDAPGroups as $key => $val) { + $currentGroup = explode($authLDAPGroupSeparator, $val); + // Remove whitespaces around the group-ID + $currentGroup = array_map('trim', $currentGroup); + if (0 < count(array_intersect($currentGroup, $grp))) { + $roles[] = $key; + } + } - $role = ''; - foreach ($authLDAPGroups as $key => $val) { - $currentGroup = explode($authLDAPGroupSeparator, $val); - // Remove whitespaces around the group-ID - $currentGroup = array_map('trim', $currentGroup); - if (0 < count(array_intersect($currentGroup, $grp))) { - $role = $key; - break; - } - } + // Default: If the user is member of more than one group only the first one + // will be taken into account! + // This filter allows you to return multiple user roles. WordPress + // supports this functionality, but not natively via UI from Users + // overview (you need to use a plugin). However, it's still widely used, + // for example, by WooCommerce, etc. Use if you know what you're doing. + if (apply_filters('authLdap_allow_multiple_roles', false) === false && count($roles) > 1) { + $roles = array_slice($roles, 0, 1); + } - authLdap_debug("Role from LDAP group: {$role}"); - return $role; + authLdap_debug("Roles from LDAP group: " . json_encode($roles)); + return $roles; } /** @@ -637,15 +695,15 @@ function authLdap_groupmap($username, $dn) */ function authLdap_show_password_fields($return, $user) { - if (! $user) { - return true; - } + if (!$user) { + return true; + } - if (get_user_meta($user->ID, 'authLDAP')) { - return false; - } + if (get_user_meta($user->ID, 'authLDAP')) { + return false; + } - return $return; + return $return; } /** @@ -664,14 +722,14 @@ function authLdap_show_password_fields($return, $user) */ function authLdap_allow_password_reset($return, $userid) { - if (!(isset($userid))) { - return true; - } + if (!(isset($userid))) { + return true; + } - if (get_user_meta($userid, 'authLDAP')) { - return false; - } - return $return; + if (get_user_meta($userid, 'authLDAP')) { + return false; + } + return $return; } /** @@ -683,22 +741,22 @@ function authLdap_allow_password_reset($return, $userid) */ function authLdap_sort_roles_by_capabilities($roles) { - global $wpdb; - $myRoles = get_option($wpdb->get_blog_prefix() . 'user_roles'); + global $wpdb; + $myRoles = get_option($wpdb->get_blog_prefix() . 'user_roles'); - authLdap_debug(print_r($roles, true)); - uasort($myRoles, 'authLdap_sortByCapabilitycount'); + authLdap_debug(print_r($roles, true)); + uasort($myRoles, 'authLdap_sortByCapabilitycount'); - $return = array(); + $return = []; - foreach ($myRoles as $key => $role) { - if (isset($roles[$key])) { - $return[$key] = $roles[$key]; - } - } + foreach ($myRoles as $key => $role) { + if (isset($roles[$key])) { + $return[$key] = $roles[$key]; + } + } - authLdap_debug(print_r($return, true)); - return $return; + authLdap_debug(print_r($return, true)); + return $return; } /** @@ -709,14 +767,14 @@ function authLdap_sort_roles_by_capabilities($roles) */ function authLdap_sortByCapabilitycount($a, $b) { - if (count($a['capabilities']) > count($b['capabilities'])) { - return -1; - } - if (count($a['capabilities']) < count($b['capabilities'])) { - return 1; - } + if (count($a['capabilities']) > count($b['capabilities'])) { + return -1; + } + if (count($a['capabilities']) < count($b['capabilities'])) { + return 1; + } - return 0; + return 0; } /** @@ -726,89 +784,89 @@ function authLdap_sortByCapabilitycount($a, $b) */ function authLdap_load_options($reload = false) { - static $options = null; + static $options = null; - // the current version for options - $option_version_plugin = 1; + // the current version for options + $option_version_plugin = 1; - $optionFunction = 'get_option'; - if (is_multisite()) { - $optionFunction = 'get_site_option'; - } - if (is_null($options) || $reload) { - $options = $optionFunction('authLDAPOptions', array()); - } + $optionFunction = 'get_option'; + if (is_multisite()) { + $optionFunction = 'get_site_option'; + } + if (is_null($options) || $reload) { + $options = $optionFunction('authLDAPOptions', []); + } - // check if option version has changed (or if it's there at all) - if (!isset($options['Version']) || ($options['Version'] != $option_version_plugin)) { - // defaults for all options - $options_default = array( - 'Enabled' => false, - 'CachePW' => false, - 'URI' => '', - 'URISeparator' => ' ', - 'Filter' => '', // '(uid=%s)' - 'NameAttr' => '', // 'name' - 'SecName' => '', - 'UidAttr' => '', // 'uid' - 'MailAttr' => '', // 'mail' - 'WebAttr' => '', - 'Groups' => array(), - 'Debug' => false, - 'GroupAttr' => '', // 'gidNumber' - 'GroupFilter' => '', // '(&(objectClass=posixGroup)(memberUid=%s))' - 'DefaultRole' => '', - 'GroupEnable' => true, - 'GroupOverUser' => true, - 'Version' => $option_version_plugin, - 'DoNotOverwriteNonLdapUsers' => false, - ); + // check if option version has changed (or if it's there at all) + if (!isset($options['Version']) || ($options['Version'] != $option_version_plugin)) { + // defaults for all options + $options_default = [ + 'Enabled' => false, + 'CachePW' => false, + 'URI' => '', + 'URISeparator' => ' ', + 'Filter' => '', // '(uid=%s)' + 'NameAttr' => '', // 'name' + 'SecName' => '', + 'UidAttr' => '', // 'uid' + 'MailAttr' => '', // 'mail' + 'WebAttr' => '', + 'Groups' => [], + 'Debug' => false, + 'GroupAttr' => '', // 'gidNumber' + 'GroupFilter' => '', // '(&(objectClass=posixGroup)(memberUid=%s))' + 'DefaultRole' => '', + 'GroupEnable' => true, + 'GroupOverUser' => true, + 'Version' => $option_version_plugin, + 'DoNotOverwriteNonLdapUsers' => false, + ]; - // check if we got a version - if (!isset($options['Version'])) { - // we just changed to the new option format - // read old options, then delete them - $old_option_new_option = array( - 'authLDAP' => 'Enabled', - 'authLDAPCachePW' => 'CachePW', - 'authLDAPURI' => 'URI', - 'authLDAPFilter' => 'Filter', - 'authLDAPNameAttr' => 'NameAttr', - 'authLDAPSecName' => 'SecName', - 'authLDAPUidAttr' => 'UidAttr', - 'authLDAPMailAttr' => 'MailAttr', - 'authLDAPWebAttr' => 'WebAttr', - 'authLDAPGroups' => 'Groups', - 'authLDAPDebug' => 'Debug', - 'authLDAPGroupAttr' => 'GroupAttr', - 'authLDAPGroupFilter' => 'GroupFilter', - 'authLDAPDefaultRole' => 'DefaultRole', - 'authLDAPGroupEnable' => 'GroupEnable', - 'authLDAPGroupOverUser' => 'GroupOverUser', - ); - foreach ($old_option_new_option as $old_option => $new_option) { - $value = get_option($old_option, null); - if (!is_null($value)) { - $options[$new_option] = $value; - } - delete_option($old_option); - } - delete_option('authLDAPCookieMarker'); - delete_option('authLDAPCookierMarker'); - } + // check if we got a version + if (!isset($options['Version'])) { + // we just changed to the new option format + // read old options, then delete them + $old_option_new_option = [ + 'authLDAP' => 'Enabled', + 'authLDAPCachePW' => 'CachePW', + 'authLDAPURI' => 'URI', + 'authLDAPFilter' => 'Filter', + 'authLDAPNameAttr' => 'NameAttr', + 'authLDAPSecName' => 'SecName', + 'authLDAPUidAttr' => 'UidAttr', + 'authLDAPMailAttr' => 'MailAttr', + 'authLDAPWebAttr' => 'WebAttr', + 'authLDAPGroups' => 'Groups', + 'authLDAPDebug' => 'Debug', + 'authLDAPGroupAttr' => 'GroupAttr', + 'authLDAPGroupFilter' => 'GroupFilter', + 'authLDAPDefaultRole' => 'DefaultRole', + 'authLDAPGroupEnable' => 'GroupEnable', + 'authLDAPGroupOverUser' => 'GroupOverUser', + ]; + foreach ($old_option_new_option as $old_option => $new_option) { + $value = get_option($old_option, null); + if (!is_null($value)) { + $options[$new_option] = $value; + } + delete_option($old_option); + } + delete_option('authLDAPCookieMarker'); + delete_option('authLDAPCookierMarker'); + } - // set default for all options that are missing - foreach ($options_default as $key => $default) { - if (!isset($options[$key])) { - $options[$key] = $default; - } - } + // set default for all options that are missing + foreach ($options_default as $key => $default) { + if (!isset($options[$key])) { + $options[$key] = $default; + } + } - // set new version and save - $options['Version'] = $option_version_plugin; - update_option('authLDAPOptions', $options); - } - return $options; + // set new version and save + $options['Version'] = $option_version_plugin; + update_option('authLDAPOptions', $options); + } + return $options; } /** @@ -816,64 +874,64 @@ function authLdap_load_options($reload = false) */ function authLdap_get_option($optionname, $default = null) { - $options = authLdap_load_options(); - if (isset($options[$optionname]) && $options[$optionname]) { - return $options[$optionname]; - } + $options = authLdap_load_options(); + if (isset($options[$optionname]) && $options[$optionname]) { + return $options[$optionname]; + } - if (null !== $default) { - return $default; - } + if (null !== $default) { + return $default; + } - //authLdap_debug('option name invalid: ' . $optionname); - return null; + //authLdap_debug('option name invalid: ' . $optionname); + return null; } /** * Set new options */ -function authLdap_set_options($new_options = array()) +function authLdap_set_options($new_options = []) { - // initialize the options with what we currently have - $options = authLdap_load_options(); + // initialize the options with what we currently have + $options = authLdap_load_options(); - // set the new options supplied - foreach ($new_options as $key => $value) { - $options[$key] = $value; - } + // set the new options supplied + foreach ($new_options as $key => $value) { + $options[$key] = $value; + } - // store options - $optionFunction = 'update_option'; - if (is_multisite()) { - $optionFunction = 'update_site_option'; - } - if ($optionFunction('authLDAPOptions', $options)) { - // reload the option cache - authLdap_load_options(true); + // store options + $optionFunction = 'update_option'; + if (is_multisite()) { + $optionFunction = 'update_site_option'; + } + if ($optionFunction('authLDAPOptions', $options)) { + // reload the option cache + authLdap_load_options(true); - return true; - } + return true; + } - // could not set options - return false; + // could not set options + return false; } /** * Do not send an email after changing the password or the email of the user! * - * @param boolean $result The initial resturn value - * @param array $user The old userdata - * @param array $newUserData The changed userdata + * @param boolean $result The initial resturn value + * @param array $user The old userdata + * @param array $newUserData The changed userdata * * @return bool */ function authLdap_send_change_email($result, $user, $newUserData) { - if (get_user_meta($user['ID'], 'authLDAP')) { - return false; - } + if (get_user_meta($user['ID'], 'authLDAP')) { + return false; + } - return $result; + return $result; } $hook = is_multisite() ? 'network_' : ''; @@ -884,3 +942,5 @@ add_filter('authenticate', 'authLdap_login', 10, 3); /** This only works from WP 4.3.0 on */ add_filter('send_password_change_email', 'authLdap_send_change_email', 10, 3); add_filter('send_email_change_email', 'authLdap_send_change_email', 10, 3); +$handler = new UserRoleHandler(); +add_action('authldap_user_roles', [$handler, 'addRolesToUser'], 10, 2); diff --git a/wp-content/plugins/authldap/ldap.php b/wp-content/plugins/authldap/ldap.php deleted file mode 100644 index 68930179..00000000 --- a/wp-content/plugins/authldap/ldap.php +++ /dev/null @@ -1,275 +0,0 @@ - - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * This file handles the basic LDAP-Tasks - * - * @author Andreas Heigl - * @package authLdap - * @category authLdap - * @since 2008 - */ -namespace Org_Heigl\AuthLdap; - -use Exception; -use Org_Heigl\AuthLdap\Exception\Error; -use function ldap_escape; - -class LDAP -{ - private $server = ''; - - private $scheme = 'ldap'; - - private $port = 389; - - private $baseDn = ''; - - private $debug = false; - /** - * This property contains the connection handle to the ldap-server - * - * @var Ressource|Connection|null - */ - private $ch = null; - - private $username = ''; - - private $password = ''; - - private $starttls = false; - - public function __construct(LdapUri $URI, $debug = false, $starttls = false) - { - $this->debug=$debug; - $array = parse_url($URI->toString()); - if (! is_array($array)) { - throw new Exception($URI . ' seems not to be a valid URI'); - } - $url = array_map(function ($item) { - return urldecode($item); - }, $array); - - if (false === $url) { - throw new Exception($URI . ' is an invalid URL'); - } - if (! isset($url['scheme'])) { - throw new Exception($URI . ' does not provide a scheme'); - } - if (0 !== strpos($url['scheme'], 'ldap')) { - throw new Exception($URI . ' is an invalid LDAP-URI'); - } - if (! isset($url['host'])) { - throw new Exception($URI . ' does not provide a server'); - } - if (! isset($url['path'])) { - throw new Exception($URI . ' does not provide a search-base'); - } - if (1 == strlen($url['path'])) { - throw new Exception($URI . ' does not provide a valid search-base'); - } - $this -> server = $url['host']; - $this -> scheme = $url['scheme']; - $this -> baseDn = substr($url['path'], 1); - if (isset($url['user'])) { - $this -> username = $url['user']; - } - if ('' == trim($this -> username)) { - $this -> username = 'anonymous'; - } - if (isset($url['pass'])) { - $this -> password = $url['pass']; - } - if (isset($url['port'])) { - $this -> port = $url['port']; - } - $this->starttls = $starttls; - } - - /** - * Connect to the given LDAP-Server - * - * @return LDAP - * @throws Error - */ - public function connect() - { - $this -> disconnect(); - if ('ldaps' == $this->scheme && 389 == $this->port) { - $this->port = 636; - } - - $this->ch = @ldap_connect($this->scheme . '://' . $this->server . ':' . $this -> port); - if (false === $this->ch) { - $this->ch = null; - throw new Error('Could not connect to the server'); - } - ldap_set_option($this->ch, LDAP_OPT_PROTOCOL_VERSION, 3); - ldap_set_option($this->ch, LDAP_OPT_REFERRALS, 0); - //if configured try to upgrade encryption to tls for ldap connections - if ($this->starttls) { - ldap_start_tls($this->ch); - } - return $this; - } - - /** - * Disconnect from a resource if one is available - * - * @return LDAP - */ - public function disconnect() - { - if (null !== $this->ch ) { - @ldap_unbind($this->ch); - } - $this->ch = null; - return $this; - } - - /** - * Bind to an LDAP-Server with the given credentials - * - * @return LDAP - * @throw AuthLdap_Exception - */ - public function bind() - { - if (! $this->ch) { - $this->connect(); - } - if (null === $this->ch) { - throw new Error('No valid LDAP connection available'); - } - $bind = false; - if (( ( $this->username ) - && ( $this->username != 'anonymous') ) - && ( $this->password != '' )) { - $bind = @ldap_bind($this->ch, $this->username, $this->password); - } else { - $bind = @ldap_bind($this->ch); - } - if (! $bind) { - throw new Error('bind was not successfull: ' . ldap_error($this->ch)); - } - return $this; - } - - public function getErrorNumber() - { - return @ldap_errno($this->ch); - } - - public function getErrorText() - { - return @ldap_error($this->ch); - } - - /** - * This method does the actual ldap-serch. - * - * This is using the filter $filter for retrieving the attributes - * $attributes - * - * - * @param string $filter - * @param array $attributes - * @param string $base - * @return array - */ - public function search($filter, $attributes = array('uid'), $base = '') - { - if (null === $this->ch) { - throw new Error('No resource handle avbailable'); - } - if (! $base) { - $base = $this->baseDn; - } - $result = ldap_search($this->ch, $base, $filter, $attributes); - if ($result === false) { - throw new Error('no result found'); - } - $this->_info = @ldap_get_entries($this->ch, $result); - if ($this->_info === false) { - throw new Error('invalid results found'); - } - return $this -> _info; - } - - /** - * This method sets debugging to ON - */ - public function debugOn() - { - $this->debug = true; - return $this; - } - - /** - * This method sets debugging to OFF - */ - public function debugOff() - { - $this->debug = false; - return $this; - } - - /** - * This method authenticates the user $username using the - * password $password - * - * @param string $username - * @param string $password - * @param string $filter OPTIONAL This parameter defines the Filter to be used - * when searchin for the username. This MUST contain the string '%s' which - * will be replaced by the vaue given in $username - * @return boolean true or false depending on successfull authentication or not - */ - public function authenticate($username, $password, $filter = '(uid=%s)') - { - //return true; - $this->connect(); - $this->bind(); - $res = $this->search(sprintf($filter, ldap_escape($username, '', LDAP_ESCAPE_FILTER))); - if (! $res || ! is_array($res) || ( $res ['count'] != 1 )) { - return false; - } - $dn = $res[0]['dn']; - if ($username && $password) { - if (@ldap_bind($this->ch, $dn, $password)) { - return true; - } - } - return false; - } - /** - * $this method loggs errors if debugging is set to ON - */ - public function logError() - { - if ($this->debug) { - $_v = debug_backtrace(); - throw new Error( - '[LDAP_ERROR]' . ldap_errno($this->ch) . ':' . ldap_error($this->ch), - $_v[0]['line'] - ); - } - } -} diff --git a/wp-content/plugins/authldap/phpcs.xml b/wp-content/plugins/authldap/phpcs.xml new file mode 100644 index 00000000..e7a652c4 --- /dev/null +++ b/wp-content/plugins/authldap/phpcs.xml @@ -0,0 +1,22 @@ + + + authLdap codestyle + ./src + ./authLdap.php + ./tests + + + + + ./vendor/autoload.php + + + + + + + + + + + diff --git a/wp-content/plugins/authldap/readme.txt b/wp-content/plugins/authldap/readme.txt index e04dca51..1c6084da 100644 --- a/wp-content/plugins/authldap/readme.txt +++ b/wp-content/plugins/authldap/readme.txt @@ -2,8 +2,8 @@ Contributors: heiglandreas Tags: ldap, auth, authentication, active directory, AD, openLDAP, Open Directory Requires at least: 2.5.0 -Tested up to: 5.9.0 -Requires PHP: 7.2 +Tested up to: 6.3.0 +Requires PHP: 7.4 Stable tag: trunk License: MIT License URI: https://opensource.org/licenses/MIT @@ -39,8 +39,36 @@ Go to https://github.com/heiglandreas/authLdap Please use the issuetracker at https://github.com/heiglandreas/authLdap/issues += Where can I report sensitive security issues with the plugin? = + +In essence: Report a security vulnerability at https://github.com/heiglandreas/authLdap/security/advisories/new + +Please see https://github.com/heiglandreas/authLdap/blob/master/SECURITY.md for more details + == Changelog == += 2.5.9 = + +* Adds information about security-contacts +* Addresses CVE-2023-41655 + += 2.5.8 = + +* Fix regression from 2.5.7 + += 2.5.7 = + +* Fix regressions from 2.5.4 +* Fix CI system + += 2.5.4 = +* Update Tested up to + += 2.5.3 = +* Fix issue with broken role-assignement in combination with WooCommerce +* Fix spelling issue +* Allow DN as role-definition + = 2.5.0 = * Ignore the order of capabilities to tell the role. In addition the filter `editable_roles` can be used to limit the roles diff --git a/wp-content/plugins/authldap/security.txt b/wp-content/plugins/authldap/security.txt new file mode 100644 index 00000000..1d1f2736 --- /dev/null +++ b/wp-content/plugins/authldap/security.txt @@ -0,0 +1,6 @@ +Contact: mailto://andreas@heigl.net +Contact: https://github.com/heiglandreas/authLdap/security/advisories/new +Expires: 2026-09-07T10:00:00.000Z +Encryption: https://andreas.heigl.org/publickey/ +Encryption: https://heigl.org/.well-known/openpgpkey/hu/sfqdema7hgdj146cwzo4rxgsoujxis31 +Preferred-Languages: en,de diff --git a/wp-content/plugins/authldap/src/Exception/Error.php b/wp-content/plugins/authldap/src/Exception/Error.php index 416b80a1..42771c8e 100644 --- a/wp-content/plugins/authldap/src/Exception/Error.php +++ b/wp-content/plugins/authldap/src/Exception/Error.php @@ -1,13 +1,13 @@ * * Licenses under the MIT-license. For details see the included file LICENSE.md */ +declare(strict_types=1); + namespace Org_Heigl\AuthLdap\Exception; use Exception; diff --git a/wp-content/plugins/authldap/src/Exception/InvalidLdapUri.php b/wp-content/plugins/authldap/src/Exception/InvalidLdapUri.php index b4ace58d..da667b01 100644 --- a/wp-content/plugins/authldap/src/Exception/InvalidLdapUri.php +++ b/wp-content/plugins/authldap/src/Exception/InvalidLdapUri.php @@ -1,15 +1,74 @@ + * + * Licenses under the MIT-license. For details see the included file LICENSE.md + */ + declare(strict_types=1); namespace Org_Heigl\AuthLdap\Exception; use RuntimeException; +use function sprintf; + class InvalidLdapUri extends RuntimeException { - public static function fromLdapUriString(string $ldapUri): InvalidLdapUri - { - return new self('"%s" is not a valid LDAP-URI.'); - } + public static function cannotparse(string $ldapUri): self + { + return new self(sprintf( + '%1$s seems not to be a valid URI', + $ldapUri + )); + } + + public static function wrongSchema(string $uri): self + { + return new self(sprintf( + '%1$s does not start with a valid schema', + $uri + )); + } + + public static function noSchema(string $uri): self + { + return new self(sprintf( + '%1$s does not provide a schema', + $uri + )); + } + + public static function noEnvironmentVariableSet(string $uri): self + { + return new self(sprintf( + 'The environment variable %1$s does not provide a URI', + $uri + )); + } + + public static function noServerProvided(string $uri): self + { + return new self(sprintf( + 'The LDAP-URI %1$s does not provide a server', + $uri + )); + } + + public static function noSearchBaseProvided(string $uri): self + { + return new self(sprintf( + 'The LDAP-URI %1$s does not provide a search-base', + $uri + )); + } + + public static function invalidSearchBaseProvided(string $uri): self + { + return new self(sprintf( + 'The LDAP-URI %1$s does not provide a valid search-base', + $uri + )); + } } diff --git a/wp-content/plugins/authldap/src/Exception/MissingValidLdapConnection.php b/wp-content/plugins/authldap/src/Exception/MissingValidLdapConnection.php new file mode 100644 index 00000000..6c108f6a --- /dev/null +++ b/wp-content/plugins/authldap/src/Exception/MissingValidLdapConnection.php @@ -0,0 +1,23 @@ + + * + * Licenses under the MIT-license. For details see the included file LICENSE.md + */ + +declare(strict_types=1); + +namespace Org_Heigl\AuthLdap\Exception; + +use RuntimeException; + +class MissingValidLdapConnection extends Error +{ + public static function get(): self + { + return new self(sprintf( + 'No valid LDAP connection available' + )); + } +} diff --git a/wp-content/plugins/authldap/src/Exception/SearchUnsuccessfull.php b/wp-content/plugins/authldap/src/Exception/SearchUnsuccessfull.php new file mode 100644 index 00000000..1159f428 --- /dev/null +++ b/wp-content/plugins/authldap/src/Exception/SearchUnsuccessfull.php @@ -0,0 +1,24 @@ + + * + * Licenses under the MIT-license. For details see the included file LICENSE.md + */ + +declare(strict_types=1); + +namespace Org_Heigl\AuthLdap\Exception; + +use RuntimeException; + +class SearchUnsuccessfull extends RuntimeException +{ + public static function fromSearchFilter(string $filter): self + { + return new self(sprintf( + 'Search for %1$s was not successfull', + $filter + )); + } +} diff --git a/wp-content/plugins/authldap/src/LdapList.php b/wp-content/plugins/authldap/src/LdapList.php index 9e699bdd..bc24c33d 100644 --- a/wp-content/plugins/authldap/src/LdapList.php +++ b/wp-content/plugins/authldap/src/LdapList.php @@ -1,4 +1,5 @@ * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -26,23 +27,26 @@ namespace Org_Heigl\AuthLdap; +use Exception; use Org_Heigl\AuthLdap\Exception\Error; +use Org_Heigl\AuthLdap\Exception\SearchUnsuccessfull; +use Org_Heigl\AuthLdap\Manager\Ldap; class LdapList { /** - * @var \LDAP[] + * @var Ldap[] */ protected $items = []; - public function addLdap(LDAP $ldap) + public function addLdap(Ldap $ldap) { $this->items[] = $ldap; } public function authenticate($username, $password, $filter = '(uid=%s)') { - /** @var LDAP $item */ + /** @var Ldap $item */ foreach ($this->items as $key => $item) { if (! $item->authenticate($username, $password, $filter)) { unset($this->items[$key]); @@ -81,10 +85,9 @@ class LdapList $result = $item->search($filter, $attributes, $base); return $result; } catch (Exception $e) { - throw $e; } } - throw new \AuthLDAP_Exception('No Results found'); + throw SearchUnsuccessfull::fromSearchFilter($filter); } } diff --git a/wp-content/plugins/authldap/src/LdapUri.php b/wp-content/plugins/authldap/src/LdapUri.php index 4df151e8..2d2169fc 100644 --- a/wp-content/plugins/authldap/src/LdapUri.php +++ b/wp-content/plugins/authldap/src/LdapUri.php @@ -1,7 +1,5 @@ * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -27,46 +25,155 @@ declare(strict_types=1); * @link http://github.com/heiglandreas/authLDAP */ +declare(strict_types=1); + namespace Org_Heigl\AuthLdap; use Org_Heigl\AuthLdap\Exception\InvalidLdapUri; + +use function array_map; +use function error_get_last; use function getenv; -use function preg_replace; -use function urlencode; +use function is_array; +use function is_string; +use function parse_url; +use function preg_replace_callback; +use function rawurlencode; +use function strlen; +use function strpos; +use function substr; +use function trim; +use function urldecode; final class LdapUri { - private $uri; + private $server; - private function __construct(string $uri) - { - if (! preg_match('/^(ldap|ldaps|env)/', $uri)) { - throw InvalidLdapUri::fromLdapUriString($uri); - } - $this->uri = $uri; - } + private $scheme; - public static function fromString(string $uri): LdapUri - { - return new LdapUri($uri); - } + private $port = 389; - public function toString(): string - { - $uri = $this->uri; - if (0 === strpos($uri, 'env:')) { - $uri = getenv(substr($this->uri, 4)); - } + private string $baseDn; - $uri = preg_replace_callback('/%env:([^%]+)%/', function (array $matches) { - return rawurlencode(getenv($matches[1])); - }, $uri); + private $username = ''; - return $uri; - } + private $password = ''; - public function __toString() - { - return $this->toString(); - } + private function __construct(string $uri) + { + if (!preg_match('/^(ldap|ldaps|env)/', $uri)) { + throw InvalidLdapUri::wrongSchema($uri); + } + + if (strpos($uri, 'env:') === 0) { + $newUri = getenv(substr($uri, 4)); + if (false === $newUri) { + throw InvalidLdapUri::noEnvironmentVariableSet($uri); + } + $uri = (string) $newUri; + } + + $uri = $this->injectEnvironmentVariables($uri); + + $array = parse_url($uri); + if (!is_array($array)) { + throw InvalidLdapUri::cannotparse($uri); + } + + $url = array_map(static function ($item) { + if (is_int($item)) { + return $item; + } + return urldecode($item); + }, $array); + + + if (!isset($url['scheme'])) { + throw InvalidLdapUri::noSchema($uri); + } + if (0 !== strpos($url['scheme'], 'ldap')) { + throw InvalidLdapUri::wrongSchema($uri); + } + if (!isset($url['host'])) { + throw InvalidLdapUri::noServerProvided($uri); + } + if (!isset($url['path'])) { + throw InvalidLdapUri::noSearchBaseProvided($uri); + } + if (1 === strlen($url['path'])) { + throw InvalidLdapUri::invalidSearchBaseProvided($uri); + } + + $this->server = $url['host']; + $this->scheme = $url['scheme']; + $this->baseDn = substr($url['path'], 1); + if (isset($url['user'])) { + $this->username = $url['user']; + } + if ('' === trim($this->username)) { + $this->username = 'anonymous'; + } + if (isset($url['pass'])) { + $this->password = $url['pass']; + } + if ($this->scheme === 'ldaps' && $this->port = 389) { + $this->port = 636; + } + + // When someone sets the port in the URL we overwrite whatever is set. + // We have to assume they know what they are doing! + if (isset($url['port'])) { + $this->port = $url['port']; + } + } + + public static function fromString(string $uri): LdapUri + { + return new LdapUri($uri); + } + + private function injectEnvironmentVariables(string $base): string + { + return preg_replace_callback('/%env:([^%]+)%/', static function (array $matches) { + return rawurlencode(getenv($matches[1])); + }, $base); + } + + public function toString(): string + { + return $this->scheme . '://' . $this->server . ':' . $this->port; + } + + public function __toString() + { + return $this->toString(); + } + + public function getUsername(): string + { + return $this->username; + } + + public function getPassword(): string + { + return $this->password; + } + + public function getBaseDn(): string + { + return $this->baseDn; + } + + public function isAnonymous(): bool + { + if ($this->password === '') { + return true; + } + + if ($this->username === 'anonymous') { + return true; + } + + return false; + } } diff --git a/wp-content/plugins/authldap/src/Manager/Ldap.php b/wp-content/plugins/authldap/src/Manager/Ldap.php new file mode 100644 index 00000000..9b4c85ba --- /dev/null +++ b/wp-content/plugins/authldap/src/Manager/Ldap.php @@ -0,0 +1,164 @@ + + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * This file handles the basic LDAP-Tasks + * + * @author Andreas Heigl + * @package authLdap + * @category authLdap + * @since 2008 + */ + +namespace Org_Heigl\AuthLdap\Manager; + +use Org_Heigl\AuthLdap\Exception\Error; +use Org_Heigl\AuthLdap\Exception\MissingValidLdapConnection; +use Org_Heigl\AuthLdap\LdapUri; +use Org_Heigl\AuthLdap\Wrapper\LdapFactory; +use Org_Heigl\AuthLdap\Wrapper\LdapInterface; + +class Ldap +{ + /** + * This property contains the connection handle to the ldap-server + * + * @var LdapInterface|null + */ + private ?LdapInterface $connection; + + private LdapUri $uri; + + private LdapFactory $factory; + + private $starttls; + + public function __construct(LdapFactory $factory, LdapUri $uri, $starttls = false) + { + $this->starttls = $starttls; + $this->uri = $uri; + $this->factory = $factory; + $this->connection = null; + } + + /** + * Connect to the given LDAP-Server + */ + public function connect(): self + { + $this->disconnect(); + + $this->connection = $this->factory->createFromLdapUri($this->uri->toString()); + $this->connection->setOption(LDAP_OPT_PROTOCOL_VERSION, 3); + $this->connection->setOption(LDAP_OPT_REFERRALS, 0); + //if configured try to upgrade encryption to tls for ldap connections + if ($this->starttls) { + $this->connection->startTls(); + } + return $this; + } + + /** + * Disconnect from a resource if one is available + */ + public function disconnect(): self + { + if (null !== $this->connection) { + $this->connection->unbind(); + } + $this->connection = null; + return $this; + } + + /** + * Bind to an LDAP-Server with the given credentials + * + * @throws Error + */ + public function bind(): self + { + if (!$this->connection) { + $this->connect(); + } + if (null === $this->connection) { + throw MissingValidLdapConnection::get(); + } + if ($this->uri->isAnonymous()) { + $bind = $this->connection->bind(); + } else { + $bind = $this->connection->bind($this->uri->getUsername(), $this->uri->getPassword()); + } + if (!$bind) { + throw new Error('bind was not successfull: ' . $this->connection->error()); + } + return $this; + } + + /** + * This method does the actual ldap-serch. + * + * This is using the filter $filter for retrieving the attributes + * $attributes + * + * @return array + * @throws Error + */ + public function search(string $filter, array $attributes = ['uid'], ?string $base = ''): array + { + if (null === $this->connection) { + throw new Error('No resource handle available'); + } + if (!$base) { + $base = $this->uri->getBaseDn(); + } + $result = $this->connection->search($base, $filter, $attributes); + if ($result === false) { + throw new Error('no result found'); + } + $info = $this->connection->getEntries($result); + if ($info === false) { + throw new Error('invalid results found'); + } + return $info; + } + + /** + * This method authenticates the user $username using the + * password $password + * + * @param string $filter OPTIONAL This parameter defines the Filter to be used + * when searchin for the username. This MUST contain the string '%s' which + * will be replaced by the vaue given in $username + * @throws Error + */ + public function authenticate(string $username, string $password, string $filter = '(uid=%s)'): bool + { + $this->connect(); + $this->bind(); + $res = $this->search(sprintf($filter, $this->factory->escape($username, '', LDAP_ESCAPE_FILTER))); + if ($res ['count'] !== 1) { + return false; + } + + $dn = $res[0]['dn']; + return $username && $password && $this->connection->bind($dn, $password); + } +} diff --git a/wp-content/plugins/authldap/src/UserRoleHandler.php b/wp-content/plugins/authldap/src/UserRoleHandler.php new file mode 100644 index 00000000..8966980f --- /dev/null +++ b/wp-content/plugins/authldap/src/UserRoleHandler.php @@ -0,0 +1,54 @@ + + * + * Licenses under the MIT-license. For details see the included file LICENSE.md + */ + +declare(strict_types=1); + +namespace Org_Heigl\AuthLdap; + +use WP_User; + +use function array_search; +use function in_array; +use function var_dump; + +class UserRoleHandler +{ + /** + * @param WP_User $user + * @param string[] $roles + * @return void + */ + public function addRolesToUser(WP_User $user, $roles) : void + { + if ($roles === []) { + return; + } + + if ($user->roles == $roles) { + return; + } + + // Remove unused roles from existing. + foreach ($user->roles as $role) { + if (!in_array($role, $roles)) { + // Remove unused roles. + $user->remove_role($role); + continue; + } + // Remove the existing role from roles. + if (($key = array_search($role, $roles)) !== false) { + unset($roles[$key]); + } + } + + // Add new ones if not already assigned. + foreach ($roles as $role) { + $user->add_role($role); + } + } +} diff --git a/wp-content/plugins/authldap/src/Wrapper/Ldap.php b/wp-content/plugins/authldap/src/Wrapper/Ldap.php new file mode 100644 index 00000000..530de8e8 --- /dev/null +++ b/wp-content/plugins/authldap/src/Wrapper/Ldap.php @@ -0,0 +1,92 @@ + + * + * Licenses under the MIT-license. For details see the included file LICENSE.md + */ + +declare(strict_types=1); + +namespace Org_Heigl\AuthLdap\Wrapper; + +use function ldap_bind; +use function ldap_connect; +use function ldap_error; +use function ldap_escape; +use function ldap_get_entries; +use function ldap_set_option; +use function ldap_start_tls; +use function ldap_unbind; + +final class Ldap implements LdapInterface +{ + private $connection; + + public function __construct(string $ldapUri) + { + $this->connection = ldap_connect($ldapUri); + } + + public function bind($dn = null, $password = null) + { + if (null === $dn && null === $password) { + return ldap_bind($this->connection); + } + return ldap_bind($this->connection, $dn, $password); + } + + public function unbind() + { + return ldap_unbind($this->connection); + } + + public function setOption($option, $value) + { + return ldap_set_option($this->connection, $option, $value); + } + + public function startTls() + { + return ldap_start_tls($this->connection); + } + + public function error() + { + return ldap_error($this->connection); + } + + public function errno() + { + return ldap_errno($this->connection); + } + + public function search( + $base, + $filter, + array $attributes = [], + $attributes_only = 0, + $sizelimit = -1, + $timelimit = -1 + ) { + return ldap_search( + $this->connection, + $base, + $filter, + $attributes, + $attributes_only, + $sizelimit, + $timelimit + ); + } + + public function getEntries($search_result) + { + return ldap_get_entries($this->connection, $search_result); + } + + public static function escape(string $value, string $ignore = '', int $flags = 0): string + { + return ldap_escape($value, $ignore, $flags); + } +} diff --git a/wp-content/plugins/authldap/src/Wrapper/LdapFactory.php b/wp-content/plugins/authldap/src/Wrapper/LdapFactory.php new file mode 100644 index 00000000..d8abbbbe --- /dev/null +++ b/wp-content/plugins/authldap/src/Wrapper/LdapFactory.php @@ -0,0 +1,24 @@ + + * + * Licenses under the MIT-license. For details see the included file LICENSE.md + */ + +declare(strict_types=1); + +namespace Org_Heigl\AuthLdap\Wrapper; + +class LdapFactory +{ + public function createFromLdapUri(string $ldapUri): LdapInterface + { + return new Ldap($ldapUri); + } + + public function escape($value, $ignore = '', $flags = 0): string + { + return Ldap::escape($value, $ignore, $flags); + } +} diff --git a/wp-content/plugins/authldap/src/Wrapper/LdapInterface.php b/wp-content/plugins/authldap/src/Wrapper/LdapInterface.php new file mode 100644 index 00000000..d6f7721d --- /dev/null +++ b/wp-content/plugins/authldap/src/Wrapper/LdapInterface.php @@ -0,0 +1,39 @@ + + * + * Licenses under the MIT-license. For details see the included file LICENSE.md + */ + +declare(strict_types=1); + +namespace Org_Heigl\AuthLdap\Wrapper; + +interface LdapInterface +{ + public function bind($dn = null, $password = null); + + public function unbind(); + + public function setOption($option, $value); + + public function startTls(); + + public function error(); + + public function errno(); + + public function search( + $base, + $filter, + array $attributes = [], + $attributes_only = 0, + $sizelimit = -1, + $timelimit = -1 + ); + + public function getEntries($search_result); + + public static function escape(string $value, string $ignore = '', int $flags = 0): string; +} diff --git a/wp-content/plugins/authldap/view/admin.phtml b/wp-content/plugins/authldap/view/admin.phtml index 978bcf5a..0c55b319 100644 --- a/wp-content/plugins/authldap/view/admin.phtml +++ b/wp-content/plugins/authldap/view/admin.phtml @@ -37,6 +37,7 @@

AuthLDAP Options

+

General Usage of authLDAP

@@ -193,7 +194,7 @@

If checked the plugin will use the user's account to query their own information. If not it will use the admin account.

- +