AuthLdap.php (mrbs-1.9.4) | : | AuthLdap.php (mrbs-1.10.0) | ||
---|---|---|---|---|
<?php | <?php | |||
namespace MRBS\Auth; | namespace MRBS\Auth; | |||
use MRBS\User; | use MRBS\User; | |||
use function MRBS\in_arrayi; | ||||
class AuthLdap extends Auth | class AuthLdap extends Auth | |||
{ | { | |||
// LDAP ERROR CODES | // LDAP ERROR CODES | |||
const LDAP_SUCCESS = 0x00; | const LDAP_SUCCESS = 0x00; | |||
const LDAP_OPERATIONS_ERROR = 0x01; | const LDAP_OPERATIONS_ERROR = 0x01; | |||
const LDAP_PROTOCOL_ERROR = 0x02; | const LDAP_PROTOCOL_ERROR = 0x02; | |||
const LDAP_TIMELIMIT_EXCEEDED = 0x03; | const LDAP_TIMELIMIT_EXCEEDED = 0x03; | |||
const LDAP_SIZELIMIT_EXCEEDED = 0x04; | const LDAP_SIZELIMIT_EXCEEDED = 0x04; | |||
const LDAP_COMPARE_FALSE = 0x05; | const LDAP_COMPARE_FALSE = 0x05; | |||
skipping to change at line 197 | skipping to change at line 198 | |||
* | * | |||
* Checks if the specified username/password pair are valid | * Checks if the specified username/password pair are valid | |||
* | * | |||
* $user - The user name | * $user - The user name | |||
* $pass - The password | * $pass - The password | |||
* | * | |||
* Returns: | * Returns: | |||
* false - The pair are invalid or do not exist | * false - The pair are invalid or do not exist | |||
* string - The validated username | * string - The validated username | |||
*/ | */ | |||
public function validateUser($user, $pass) | public function validateUser(?string $user, ?string $pass) | |||
{ | { | |||
// Check if we do not have a username/password | // Check if we do not have a username/password | |||
// User can always bind to LDAP anonymously with empty password, | // User can always bind to LDAP anonymously with empty password, | |||
// therefore we need to block empty password here... | // therefore we need to block empty password here... | |||
if (!isset($user) || !isset($pass) || strlen($pass)==0) | if (!isset($user) || !isset($pass) || strlen($pass)==0) | |||
{ | { | |||
self::debug('empty username or password passed'); | self::debug('empty username or password passed'); | |||
return false; | return false; | |||
} | } | |||
skipping to change at line 312 | skipping to change at line 313 | |||
} | } | |||
else | else | |||
{ | { | |||
self::debug("bind to '$dn' failed: ". self::ldapError($ldap)); | self::debug("bind to '$dn' failed: ". self::ldapError($ldap)); | |||
} | } | |||
// return failure if no connection is established | // return failure if no connection is established | |||
return false; | return false; | |||
} | } | |||
public function getUser($username) | public function getUser(string $username) : ?User | |||
{ | { | |||
static $users = array(); // Cache results for performance | static $users = array(); // Cache results for performance | |||
if (!isset($username) || ($username === '')) | if (!isset($username) || ($username === '')) | |||
{ | { | |||
return null; | return null; | |||
} | } | |||
if (!isset($users[$username])) | if (!isset($users[$username])) | |||
{ | { | |||
skipping to change at line 482 | skipping to change at line 483 | |||
if (!isset($user['display_name'])) | if (!isset($user['display_name'])) | |||
{ | { | |||
$user['display_name'] = $user['username']; | $user['display_name'] = $user['username']; | |||
} | } | |||
if (isset($user['groups'])) | if (isset($user['groups'])) | |||
{ | { | |||
if (isset($object['config']['ldap_admin_group_dn'])) | if (isset($object['config']['ldap_admin_group_dn'])) | |||
{ | { | |||
$user['level'] = in_array($object['config']['ldap_admin_group_dn'], $use r['groups']) ? 2 : 1; | $user['level'] = in_arrayi($object['config']['ldap_admin_group_dn'], $us er['groups']) ? 2 : 1; | |||
} | } | |||
} | } | |||
self::debug("User '" . $user['username'] . "' found"); | self::debug("User '" . $user['username'] . "' found"); | |||
$object['user'] = $user; | $object['user'] = $user; | |||
return true; | return true; | |||
} | } | |||
public function getUsernames() | public function getUsernames() | |||
{ | { | |||
skipping to change at line 611 | skipping to change at line 612 | |||
$object['users'][] = $user; | $object['users'][] = $user; | |||
} | } | |||
$entry = ldap_next_entry($ldap, $entry); | $entry = ldap_next_entry($ldap, $entry); | |||
} | } | |||
return true; | return true; | |||
} | } | |||
// Returns an array of attributes for use in an LDAP query | // Returns an array of attributes for use in an LDAP query | |||
private static function getAttributes($object, $include_email=true, $include_g roups=true) | private static function getAttributes(array $object, bool $include_email=true, bool $include_groups=true) : array | |||
{ | { | |||
$result = array(); | $result = array(); | |||
// Username | // Username | |||
$result['username'] = \MRBS\utf8_strtolower($object['config']['ldap_user_att rib']); | $result['username'] = \MRBS\utf8_strtolower($object['config']['ldap_user_att rib']); | |||
// The display name attribute might not have been set in the config file | // The display name attribute might not have been set in the config file | |||
if (isset($object['config']['ldap_name_attrib'])) | if (isset($object['config']['ldap_name_attrib'])) | |||
{ | { | |||
$result['display_name'] = \MRBS\utf8_strtolower($object['config']['ldap_na me_attrib']); | $result['display_name'] = \MRBS\utf8_strtolower($object['config']['ldap_na me_attrib']); | |||
skipping to change at line 640 | skipping to change at line 641 | |||
// The group name attribute might not have been set in the config file | // The group name attribute might not have been set in the config file | |||
if ($include_groups && isset($object['config']['ldap_group_member_attrib'])) | if ($include_groups && isset($object['config']['ldap_group_member_attrib'])) | |||
{ | { | |||
$result['groups'] = \MRBS\utf8_strtolower($object['config']['ldap_group_me mber_attrib']); | $result['groups'] = \MRBS\utf8_strtolower($object['config']['ldap_group_me mber_attrib']); | |||
} | } | |||
return $result; | return $result; | |||
} | } | |||
// Returns an associative array from the result of an LDAP search | // Returns an associative array from the result of an LDAP search | |||
private static function getResult($ldap, $entry, $attributes) | private static function getResult($ldap, $entry, array $attributes) : array | |||
{ | { | |||
// Initialise all keys in the user array, in case an attribute isn't present | // Initialise all keys in the user array, in case an attribute isn't present | |||
$attributes_keys = array_keys($attributes); | $attributes_keys = array_keys($attributes); | |||
$user = array(); | $user = array(); | |||
foreach ($attributes_keys as $key) | foreach ($attributes_keys as $key) | |||
{ | { | |||
switch ($key) | switch ($key) | |||
{ | { | |||
case 'username': | case 'username': | |||
case 'display_name': | case 'display_name': | |||
skipping to change at line 711 | skipping to change at line 712 | |||
* | * | |||
* $callback - The callback function | * $callback - The callback function | |||
* $username - The user name | * $username - The user name | |||
* &$object - Reference to the generic object, type defined by caller | * &$object - Reference to the generic object, type defined by caller | |||
* $keep_going - Don't stop when a user has been found, but keep going through all the LDAP | * $keep_going - Don't stop when a user has been found, but keep going through all the LDAP | |||
* hosts. Useful, for example, when you want to get a list of al l users. | * hosts. Useful, for example, when you want to get a list of al l users. | |||
* | * | |||
* Returns: | * Returns: | |||
* boolean - Whether the action was successful | * boolean - Whether the action was successful | |||
*/ | */ | |||
public function action($callback, $username, &$object, $keep_going=false) | public function action(string $callback, string $username, &$object, bool $kee p_going=false) : bool | |||
{ | { | |||
global $ldap_unbind_between_attempts; | global $ldap_unbind_between_attempts; | |||
$result = false; | $result = false; | |||
for ($idx=0; $idx < count(self::$all_ldap_opts['ldap_host']); $idx++) | for ($idx=0; $idx < count(self::$all_ldap_opts['ldap_host']); $idx++) | |||
{ | { | |||
// Establish LDAP connection | // Establish LDAP connection | |||
$uri = self::getUri($idx); | $uri = self::getUri($idx); | |||
$ldap = ldap_connect($uri); | $ldap = ldap_connect($uri); | |||
skipping to change at line 837 | skipping to change at line 838 | |||
if ($result && !$keep_going) | if ($result && !$keep_going) | |||
{ | { | |||
return true; | return true; | |||
} | } | |||
} // for () | } // for () | |||
return $result; | return $result; | |||
} | } | |||
// A wrapper for ldap_bind() that optionally suppresses "invalid credentials" errors. | // A wrapper for ldap_bind() that optionally suppresses "invalid credentials" errors. | |||
private static function ldapBind ($link_identifier, $bind_rdn=null, $bind_pass word=null) | private static function ldapBind ($link_identifier, ?string $bind_rdn=null, ?s tring $bind_password=null) : bool | |||
{ | { | |||
global $ldap_suppress_invalid_credentials; | global $ldap_suppress_invalid_credentials; | |||
// Suppress all errors and then look to see what the error was and then | // Suppress all errors and then look to see what the error was and then | |||
// trigger the error again, depending on config settings. | // trigger the error again, depending on config settings. | |||
$result = @ldap_bind($link_identifier, $bind_rdn, $bind_password); | $result = @ldap_bind($link_identifier, $bind_rdn, $bind_password); | |||
if (!$result) | if (!$result) | |||
{ | { | |||
$errno = ldap_errno($link_identifier); | $errno = ldap_errno($link_identifier); | |||
if (!$ldap_suppress_invalid_credentials || ($errno != self::LDAP_INVALID_C REDENTIALS)) | if (!$ldap_suppress_invalid_credentials || ($errno != self::LDAP_INVALID_C REDENTIALS)) | |||
{ | { | |||
trigger_error(ldap_err2str($errno), E_USER_WARNING); | trigger_error(ldap_err2str($errno), E_USER_WARNING); | |||
} | } | |||
} | } | |||
return $result; | return $result; | |||
} | } | |||
// Gets the full LDAP URI | // Gets the full LDAP URI | |||
private static function getUri($idx) | private static function getUri(int $idx) : string | |||
{ | { | |||
// First get the port | // First get the scheme and host | |||
if (isset(self::$all_ldap_opts['ldap_port'][$idx])) | ||||
{ | ||||
$port = self::$all_ldap_opts['ldap_port'][$idx]; | ||||
} | ||||
else | ||||
{ | ||||
$port = self::DEFAULT_PORT_LDAP; | ||||
} | ||||
// Now get the scheme and host | ||||
$host = self::$all_ldap_opts['ldap_host'][$idx]; | $host = self::$all_ldap_opts['ldap_host'][$idx]; | |||
$parsed_url = parse_url($host); | $parsed_url = parse_url($host); | |||
if (isset($parsed_url['scheme'])) | if (isset($parsed_url['scheme'])) | |||
{ | { | |||
$scheme = $parsed_url['scheme']; | $scheme = $parsed_url['scheme']; | |||
$host = $parsed_url['host']; | $host = $parsed_url['host']; | |||
} | } | |||
else | ||||
// If we haven't got a scheme then make an educated guess based on the port. | ||||
if (!isset($scheme)) | ||||
{ | { | |||
// Make an educated guess at the scheme | // And if there isn't a port defined either then use a sensible default | |||
$port = self::$all_ldap_opts['ldap_port'][$idx] ?? self::DEFAULT_PORT_LDAP | ||||
; | ||||
$scheme = ($port == self::DEFAULT_PORT_LDAPS) ? 'ldaps' : 'ldap'; | $scheme = ($port == self::DEFAULT_PORT_LDAPS) ? 'ldaps' : 'ldap'; | |||
} | } | |||
// If we have got a scheme then get the port. If it has been defined explic | ||||
itly in the | ||||
// config file, then use that. Otherwise make an educated guess based on the | ||||
scheme. | ||||
else | ||||
{ | ||||
if (isset(self::$all_ldap_opts['ldap_port'][$idx])) | ||||
{ | ||||
$port = self::$all_ldap_opts['ldap_port'][$idx]; | ||||
} | ||||
else | ||||
{ | ||||
$port = ($scheme == 'ldaps') ? self::DEFAULT_PORT_LDAPS : self::DEFAULT_ | ||||
PORT_LDAP; | ||||
} | ||||
} | ||||
return "$scheme://$host:$port"; | return "$scheme://$host:$port"; | |||
} | } | |||
private static function setOptions($ldap, $idx) | private static function setOptions($ldap, int $idx) : void | |||
{ | { | |||
if (isset(self::$all_ldap_opts['ldap_deref'][$idx])) | if (isset(self::$all_ldap_opts['ldap_deref'][$idx])) | |||
{ | { | |||
ldap_set_option($ldap, LDAP_OPT_DEREF, self::$all_ldap_opts['ldap_deref'][ $idx]); | ldap_set_option($ldap, LDAP_OPT_DEREF, self::$all_ldap_opts['ldap_deref'][ $idx]); | |||
} | } | |||
if (isset(self::$all_ldap_opts['ldap_v3'][$idx]) && | if (isset(self::$all_ldap_opts['ldap_v3'][$idx]) && | |||
self::$all_ldap_opts['ldap_v3'][$idx]) | self::$all_ldap_opts['ldap_v3'][$idx]) | |||
{ | { | |||
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3); | ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3); | |||
skipping to change at line 929 | skipping to change at line 936 | |||
if (isset(self::$all_ldap_opts['ldap_disable_referrals'][$idx]) && | if (isset(self::$all_ldap_opts['ldap_disable_referrals'][$idx]) && | |||
self::$all_ldap_opts['ldap_disable_referrals'][$idx]) | self::$all_ldap_opts['ldap_disable_referrals'][$idx]) | |||
{ | { | |||
// Required to do a search on Active Directory for Win 2003+ | // Required to do a search on Active Directory for Win 2003+ | |||
ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0); | ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0); | |||
} | } | |||
} | } | |||
// Adds extra diagnostic information to ldap_error() | // Adds extra diagnostic information to ldap_error() | |||
private static function ldapError ($link_identifier) | private static function ldapError ($link_identifier) : string | |||
{ | { | |||
$result = ldap_error($link_identifier); | $result = ldap_error($link_identifier); | |||
// LDAP_OPT_DIAGNOSTIC_MESSAGE is not supported by all LDAP libraries | // LDAP_OPT_DIAGNOSTIC_MESSAGE is not supported by all LDAP libraries | |||
if (defined('LDAP_OPT_DIAGNOSTIC_MESSAGE') && | if (defined('LDAP_OPT_DIAGNOSTIC_MESSAGE') && | |||
ldap_get_option($link_identifier, LDAP_OPT_DIAGNOSTIC_MESSAGE, $err) && | ldap_get_option($link_identifier, LDAP_OPT_DIAGNOSTIC_MESSAGE, $err) && | |||
isset($err) && ($err !== '')) | isset($err) && ($err !== '')) | |||
{ | { | |||
$result .= " [$err]"; | $result .= " [$err]"; | |||
} | } | |||
return $result; | return $result; | |||
} | } | |||
/* debug($message) | /* debug($message) | |||
* | * | |||
* Output LDAP debugging, if either of the configuration variables | * Output LDAP debugging, if either of the configuration variables | |||
* $ldap_debug or $ldap_debug_attributes is true. | * $ldap_debug or $ldap_debug_attributes is true. | |||
* | * | |||
*/ | */ | |||
private static function debug($message) | private static function debug(string $message) : void | |||
{ | { | |||
global $ldap_debug, $ldap_debug_attributes; | global $ldap_debug, $ldap_debug_attributes; | |||
if ($ldap_debug || $ldap_debug_attributes) | if ($ldap_debug || $ldap_debug_attributes) | |||
{ | { | |||
list($called, $caller) = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); | list($called, $caller) = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); | |||
error_log( | error_log( | |||
"[MRBS DEBUG] " . | "[MRBS DEBUG] " . | |||
$caller['class'] . $caller['type'] . $caller['function'] . '(' . $call ed['line'] . ')' . | $caller['class'] . $caller['type'] . $caller['function'] . '(' . $call ed['line'] . ')' . | |||
": $message" | ": $message" | |||
skipping to change at line 979 | skipping to change at line 986 | |||
if ($ldap_debug) | if ($ldap_debug) | |||
{ | { | |||
return (\MRBS\get_microtime() - self::$profile_clock); | return (\MRBS\get_microtime() - self::$profile_clock); | |||
} | } | |||
else | else | |||
{ | { | |||
return null; | return null; | |||
} | } | |||
} | } | |||
private static function resetProfileClock() | private static function resetProfileClock() : void | |||
{ | { | |||
global $ldap_debug; | global $ldap_debug; | |||
if ($ldap_debug) | if ($ldap_debug) | |||
{ | { | |||
self::$profile_clock = \MRBS\get_microtime(); | self::$profile_clock = \MRBS\get_microtime(); | |||
} | } | |||
} | } | |||
} | } | |||
End of changes. 17 change blocks. | ||||
25 lines changed or deleted | 36 lines changed or added |