From d2aecdec004b24d53f80784d23284eba54a70095 Mon Sep 17 00:00:00 2001 From: Olav Morken <olav.morken@uninett.no> Date: Mon, 6 Jul 2009 09:12:00 +0000 Subject: [PATCH] Auth/LDAP: Change the error handling code. git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@1551 44740490-163a-0410-bde0-09ae8108e29a --- lib/SimpleSAML/Auth/LDAP.php | 632 +++++++++++------- lib/SimpleSAML/Auth/LDAPException.php | 38 -- lib/SimpleSAML/Error/AuthSource.php | 14 + lib/SimpleSAML/Error/BadUserInnput.php | 14 + lib/SimpleSAML/Error/Exception.php | 48 ++ lib/SimpleSAML/Error/InvalidCredential.php | 14 + lib/SimpleSAML/Error/User.php | 16 + lib/SimpleSAML/Error/UserNotFound.php | 15 + .../Auth/Backend/Test/StandardLDAPTest.php | 2 +- 9 files changed, 500 insertions(+), 293 deletions(-) delete mode 100644 lib/SimpleSAML/Auth/LDAPException.php create mode 100644 lib/SimpleSAML/Error/AuthSource.php create mode 100644 lib/SimpleSAML/Error/BadUserInnput.php create mode 100644 lib/SimpleSAML/Error/Exception.php create mode 100644 lib/SimpleSAML/Error/InvalidCredential.php create mode 100644 lib/SimpleSAML/Error/User.php create mode 100644 lib/SimpleSAML/Error/UserNotFound.php diff --git a/lib/SimpleSAML/Auth/LDAP.php b/lib/SimpleSAML/Auth/LDAP.php index 04cd9e31d..32ce1e804 100644 --- a/lib/SimpleSAML/Auth/LDAP.php +++ b/lib/SimpleSAML/Auth/LDAP.php @@ -1,5 +1,16 @@ <?php +/** + * Constants defining possible errors + */ +define('ERR_INTERNAL', 1); +define('ERR_NO_USER', 2); +define('ERR_WRONG_PW', 3); +define('ERR_AS_DATA_INCONSIST', 4); +define('ERR_AS_INTERNAL', 5); +define('ERR_AS_ATTRIBUTE', 6); + + /** * The LDAP class holds helper functions to access an LDAP database. * @@ -12,257 +23,380 @@ class SimpleSAML_Auth_LDAP { /** - * LDAP link + * LDAP link identifier. + * + * @var resource */ private $ldap = null; - + /** - * private constructor restricts instantiaton to getInstance() + * Timeout value, in seconds. + * + * @var int */ + private $timeout = 0; + + /** + * Private constructor restricts instantiation to getInstance(). + * + * @param string $hostname + * @param bool $enable_tls + * @param bool $debug + * @param int $timeout + */ + // TODO: Flesh out documentation. public function __construct($hostname, $enable_tls = TRUE, $debug = FALSE, $timeout = 0) { + // Debug. SimpleSAML_Logger::debug('Library - LDAP __construct(): Setup LDAP with ' . - 'host "' . $hostname . - ', tls=' . var_export($enable_tls, TRUE) . - ', debug=' . var_export($debug, TRUE) . - ', timeout=' . var_export($timeout, true)); + 'host=\'' . $hostname . + '\', tls=' . var_export($enable_tls, true) . + ', debug=' . var_export($debug, true) . + ', timeout=' . var_export($timeout, true)); + + // Set debug level and protocol version, if supported. + // (OpenLDAP 2.x.x or Netscape Directory SDK x.x needed). + if ($debug && !ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7)) + SimpleSAML_Logger::warning('Library - LDAP __construct(): Unable to set debug level (LDAP_OPT_DEBUG_LEVEL) to 7'); + if (!@ldap_set_option($this->ldap, LDAP_OPT_PROTOCOL_VERSION, 3)) + // TODO: Should this be a warning instead? + throw $this->makeException('Library - LDAP __construct(): Failed to set LDAP Protocol version (LDAP_OPT_PROTOCOL_VERSION) to 3', ERR_INTERNAL); - if ($debug) ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7); + // Connect. $this->ldap = @ldap_connect($hostname); - - // Set timeouts, if supported... + if ($this->ldap == FALSE) + throw new $this->makeException('Library - LDAP __construct(): Unable to connect to \'' . $hostname . '\'', ERR_INTERNAL); + + // Set timeouts, if supported. // (OpenLDAP 2.x.x or Netscape Directory SDK x.x needed). + // TODO: Should these be moved to before ldap_connect() above? + $this->timeout = $timeout; if (!@ldap_set_option($this->ldap, LDAP_OPT_NETWORK_TIMEOUT, $timeout)) - SimpleSAML_Logger::warning('Library - LDAP __construct(): Unable to set timeouts [LDAP_OPT_NETWORK_TIMEOUT] to ' . var_export($timeout, true)); + SimpleSAML_Logger::warning('Library - LDAP __construct(): Unable to set timeouts (LDAP_OPT_NETWORK_TIMEOUT) to ' . $timeout); if (!@ldap_set_option($this->ldap, LDAP_OPT_TIMELIMIT, $timeout)) - SimpleSAML_Logger::warning('Library - LDAP __construct(): Unable to set timeouts [LDAP_OPT_TIMELIMIT] to ' . var_export($timeout, true)); + SimpleSAML_Logger::warning('Library - LDAP __construct(): Unable to set timeouts (LDAP_OPT_TIMELIMIT) to ' . $timeout); - if (empty($this->ldap)) - throw new Exception('Error initializing LDAP connection with PHP LDAP library.'); - - $this->setV3(); - - if (!preg_match("/ldaps:/i",$hostname) and $enable_tls) { - if (!@ldap_start_tls($this->ldap)) { - throw $this->getLDAPException('Could not force LDAP into TLS-session. Please verify certificates and configuration. Could also be that PHP the LDAP library cannot connect to the LDAP server [' . $hostname . ']: '); - } - } + // Enable TLS, if needed. + if (!preg_match("/ldaps:/i", $hostname) and $enable_tls) + if (!@ldap_start_tls($this->ldap)) + throw $this->makeException('Library - LDAP __construct(): Unable to force TLS', ERR_INTERNAL); } - /** - * - */ - public function getLDAPException($message) { - if (ldap_errno($this->ldap) == 0) { - return new Exception($message); - } - return new SimpleSAML_Auth_LDAPException($message . ' [' . ldap_error($this->ldap) . ']', ldap_errno($this->ldap)); - } /** - * @DEPRECATED 2008-02-27 - */ - public function getLastError() { - if (ldap_errno($this->ldap) == 0) return NULL; - return ldap_error($this->ldap); - } - - /** - * Set LDAP version 3 option on the connection handler. Will throw an error if not possible. + * Convenience method to create an LDAPException as well as log the + * description. + * + * @param string $description + * The exception's description + * @return Exception */ - private function setV3() { - // Give error if LDAPv3 is not supported - if (!@ldap_set_option($this->ldap, LDAP_OPT_PROTOCOL_VERSION, 3)) - throw $this->getLDAPException('Failed to set LDAP Protocol version to 3'); + private function makeException($description, $type = NULL) { + $errNo = 0x00; + + // Log LDAP code and description, if possible. + if (empty($this->ldap)){ + SimpleSAML_Logger::error($description); + }else{ + $errNo = @ldap_errno($this->ldap); + } + + // Decide exception type and return + if($type){ + if($errNo !== 0){ + // Only log real LDAP errors; not success. + SimpleSAML_Logger::error($description . '; cause: \'' . ldap_error($this->ldap) . '\' (0x' . dechex($errNo) . ')'); + }else{ + SimpleSAML_Logger::error($description); + } + + switch ($type){ + case ERR_INTERNAL:// 1 - ExInternal + return new SimpleSAML_Error_Exception($description, $errNo); + case ERR_NO_USER:// 2 - ExUserNotFound + return new SimpleSAML_Error_UserNotFound($description, $errNo); + case ERR_WRONG_PW:// 3 - ExInvalidCredential + return new SimpleSAML_Error_InvalidCredential($description, $errNo); + case ERR_AS_DATA_INCONSIST:// 4 - ExAsDataInconsist + return new SimpleSAML_Error_AuthSource($description, $errNo); + case ERR_AS_INTERNAL:// 5 - ExAsInternal + return new SimpleSAML_Error_AuthSource($description, $errNo); + } + }else{ + switch ($errNo){ + case 0x20://LDAP_NO_SUCH_OBJECT + SimpleSAML_Logger::warning($description . '; cause: \'' . ldap_error($this->ldap) . '\' (0x' . dechex($errNo) . ')'); + return new SimpleSAML_Error_UserNotFound($description, $errNo); + case 0x31://LDAP_INVALID_CREDENTIALS + SimpleSAML_Logger::info($description . '; cause: \'' . ldap_error($this->ldap) . '\' (0x' . dechex($errNo) . ')'); + return new SimpleSAML_Error_InvalidCredential($description, $errNo); + case -1://NO_SERVER_CONNECTION + SimpleSAML_Logger::error($description . '; cause: \'' . ldap_error($this->ldap) . '\' (0x' . dechex($errNo) . ')'); + return new SimpleSAML_Error_AuthSource($description, $errNo); + default: + SimpleSAML_Logger::error($description . '; cause: \'' . ldap_error($this->ldap) . '\' (0x' . dechex($errNo) . ')'); + return new SimpleSAML_Error_AuthSource($description, $errNo); + } + } } - + + /** - * Search for DN in one single base only + * Search for DN from a single base. * - * @param $allowZeroHits Default is false. If set to true it will return NULL instead - * of throwing an exception if no results was found. + * @param string $base + * Indication of root of subtree to search + * @param string|array $attribute + * The attribute name(s) to search for. + * @param string $value + * The attribute value to search for. + * @return string + * The DN of the resulting found element. + * @throws SimpleSAML_Error_Exception if: + * - Attribute parameter is wrong type + * @throws SimpleSAML_Error_AuthSource if: + * - Not able to connect to LDAP server + * - False search result + * - Count return false + * - Searche found more than one result + * - Failed to get first entry from result + * - Failed to get DN for entry + * @throws SimpleSAML_Error_UserNotFound if: + * - Zero entries was found */ - public function searchfordnSingleBase($searchbase, $searchattr, $searchvalue, $allowZeroHits = FALSE) { - - // Search for ePPN - $search = $this->generateSearchFilter($searchattr, $searchvalue); - SimpleSAML_Logger::debug('Library - LDAP: Search for DN base:' . $searchbase . ' search: ' . $search); - $search_result = @ldap_search($this->ldap, $searchbase, $search, array() ); + private function search($base, $attribute, $value) { - if ($search_result === false) - throw $this->getLDAPException('Failed performing a LDAP search:' . $search); + // Create the search filter. + $attribute = self::escape_filter_value($attribute, FALSE); + $value = self::escape_filter_value($value); + if (is_array($attribute)) { - // Check number of entries. ePPN should be unique! - if (@ldap_count_entries($this->ldap, $search_result) > 1 ) - throw $this->getLDAPException("Found multiple entries in LDAP search: " . $search . ' base(s): ' . $searchbase); - - if (@ldap_count_entries($this->ldap, $search_result) == 0) { - if ($allowZeroHits) { - return NULL; - } else { - throw $this->getLDAPException('LDAP search returned zero entries: ' . $search . ' base: ' . $searchbase); + // We have more than one attribute. + $filter = ''; + foreach ($attribute AS $attr) { + $filter .= '(' . $attr . '=' . $value. ')'; } + $filter = '(|' . $filter . ')'; + + } elseif (is_string($attribute)) { + + // We have only one attribute. + $filter = '(' . $attribute . '=' . $value. ')'; + + } else { + // We have an unknown attribute type... + throw $this->makeException('Library - LDAP search(): Search attribute must be an array or a string', ERR_INTERNAL); } - // Authenticate user and fetch attributes - $entry = ldap_first_entry($this->ldap, $search_result); - - if (empty($entry)) - throw $this->getLDAPException('Could not retrieve result of LDAP search: ' . $search); + // Search using generated filter. + SimpleSAML_Logger::debug('Library - LDAP search(): Searching base \'' . $base . '\' for \'' . $filter . '\''); + // TODO: Should aliases be dereferenced? + $result = @ldap_search($this->ldap, $base, $filter, array(), 0, 0, $this->timeout); + if ($result === FALSE){ + throw $this->makeException('Library - LDAP search(): Failed search on base \'' . $base . '\' for \'' . $filter . '\''); + } + + // Sanity checks on search results. + $count = @ldap_count_entries($this->ldap, $result); + if($count === FALSE){ + throw $this->makeException('Library - LDAP search(): Failed to get number of entries returned'); + }elseif($count > 1){ + // More than one entry is found. External error + throw $this->makeException('Library - LDAP search(): Found ' . $count . ' entries searching base \'' . $base . '\' for \'' . $filter . '\'', ERR_AS_DATA_INCONSIST); + }elseif($count === 0){ + // No entry is fond => wrong username is given (or not registered in the catalogue). User error + throw $this->makeException('Library - LDAP search(): Found no entries searching base \'' . $base . '\' for \'' . $filter . '\'', ERR_NO_USER); + } + + // Resolve the DN from the search result. + $entry = @ldap_first_entry($this->ldap, $result); + if ($entry === FALSE) + throw $this->makeException('Library - LDAP search(): Unable to retrieve result after searching base \'' . $base . '\' for \'' . $filter . '\''); $dn = @ldap_get_dn($this->ldap, $entry); - - if (empty($dn)) - throw $this->getLDAPException('Error retrieving DN from search result.'); - + if ($dn === FALSE) + throw $this->makeException('Library - LDAP search(): Unable to get DN after searching base \'' . $base . '\' for \'' . $filter . '\''); + // FIXME: Are we now shure, if no excepton hawe been thrown, that we are returning av DN? return $dn; - } - - + /** - * Search for a DN. You specify an attribute name and an attribute value - * and the function will return the DN of the result of the search. + * Search for a DN. + * + * @param string|array $base + * The base, or bases, which to search from. + * @param string|array $attribute + * The attribute name(s) searched for. + * @param string $value + * The attribute value searched for. + * @param bool $allowZeroHits + * Determines if the method will throw an exception if no hits are found. + * Defaults to FALSE. + * @return string + * The DN of the matching element, if found. If no element was found and + * $allowZeroHits is set to FALSE, an exception will be thrown; otherwise + * NULL will be returned. + * @throws SimpleSAML_Error_AuthSource if: + * - LDAP search encounter some problems when searching cataloge + * - Not able to connect to LDAP server + * @throws SimpleSAML_Error_UserNotFound if: + * - $allowZeroHits er TRUE and no result is found * - * @param $allowZeroHits Default is false. If set to true it will return NULL instead - * of throwing an exception if no results was found. */ - public function searchfordn($searchbase, $searchattr, $searchvalue, $allowZeroHits = FALSE) { + public function searchfordn($base, $attribute, $value, $allowZeroHits = FALSE) { - SimpleSAML_Logger::debug('Library - LDAP: searchfordn() Search for entries'); - $searchbases = SimpleSAML_Utilities::arrayize($searchbase); - - /** - * Traverse all search bases. If DN was found, return the result. - */ + // Traverse all search bases, returning DN if found. + $bases = SimpleSAML_Utilities::arrayize($base); $result = NULL; - foreach($searchbases AS $sbase) { + foreach ($bases AS $current) { try { - $result = $this->searchfordnSingleBase($sbase, $searchattr, $searchvalue, TRUE); - if (!empty($result)) return $result; - - // If LDAP search failed, log errors, but continue to look in the other base DNs. - } catch(Exception $e) { - SimpleSAML_Logger::warning('Library - LDAP: Search for DN failed for base:' . $sbase . ' exception: ' . - $e->getMessage()); + // Single base search. + $result = $this->search($current, $attribute, $value); + // We don't hawe to look any futher if user is found + if (!empty($result)) + return $result; + // If search failed, attempt the other base DNs. + }catch(SimpleSAML_Error_UserNotFound $e){ + // Just continue searching } } - SimpleSAML_Logger::debug('Library - LDAP: searchfordn() Zero entries found'); - - if ($allowZeroHits) { + // Decide what to do for zero entries. + SimpleSAML_Logger::debug('Library - LDAP searchfordn(): No entries found'); + if($allowZeroHits){ + // Zero hits allowed. return NULL; } else { - throw $this->getLDAPException('LDAP search returned zero entries: ' . $searchattr . '=' . $searchvalue . ' base(s): ' . - join(' & ', $searchbases)); + // Zero hits not allowed. + throw $this->makeException('Library - LDAP searchfordn(): LDAP search returned zero entries for filter \'(' . $attribute . ' = ' . $value . ')\' on base(s) \'(' . join(' & ', $bases) . ')\'', 2); } - } - + + /** - * Generate a search filter for one or more attribute names to match - * one attribute value. + * Bind to LDAP with a specific DN and password. Simple wrapper around + * ldap_bind() with some additional logging. * - * @param $searchattr Can be either an array or a string. Attribute name. - * @param $searchvalue Attribute value to match - * @return A LDAP search filter. - */ - private function generateSearchFilter($searchattr, $searchvalue) { - $searchattr = self::escape_filter_value($searchattr, FALSE); - $searchvalue = self::escape_filter_value($searchvalue); - - if (is_array($searchattr)) { - - $search = ''; - foreach ($searchattr AS $attr) { - $search .= '(' . $attr . '=' . $searchvalue. ')'; - } - return '(|' . $search . ')'; - - } elseif (is_string($searchattr)) { - return '(' . $searchattr . '=' . $searchvalue. ')'; - } else { - throw $this->getLDAPException('Search attribute is required to be an array or a string.'); - } - } - - - /** - * Bind to LDAP with a specific DN and password. + * @param string $dn + * The DN used. + * @param string $password + * The password used. + * @return bool + * Returns TRUE if successful, FALSE if LDAP_INVALID_CREDENTIALS. + * @throws SimpleSAML_Error_Exception on other errors */ public function bind($dn, $password) { + + // Bind, with error handling. if (@ldap_bind($this->ldap, $dn, $password)) { - SimpleSAML_Logger::debug('Library - LDAP: Bind successfull with ' . $dn); + + // Good. + SimpleSAML_Logger::debug('Library - LDAP bind(): Bind successful with DN \'' . $dn . '\''); return TRUE; + + } + + /* Handle invalid DN/password. + * LDAP_INVALID_CREDENTIALS */ + if (ldap_errno($this->ldap) === 49) { + return FALSE; } - SimpleSAML_Logger::debug('Library - LDAP: Bind failed with [' . $dn . ']. LDAP error code [' . ldap_errno($this->ldap) . ']'); - return FALSE; + + // Bad. + throw $this->makeException('Library - LDAP bind(): Bind failed with DN \'' . $dn . '\''); + } /** - * Search DN for attributes, and return associative array. + * Search a given DN for attributes, and return the resulting associative + * array. + * + * @param string $dn + * The DN of an element. + * @param string|array $attributes + * The names of the attribute(s) to retrieve. Defaults to NULL; that is, + * all available attributes. Note that this is not very effective. + * @param int $maxsize + * The maximum size of any attribute's value(s). If exceeded, the attribute + * will not be returned. + * @return array + * The array of attributes and their values. + * @see http://no.php.net/manual/en/function.ldap-read.php */ public function getAttributes($dn, $attributes = NULL, $maxsize = NULL) { - - $searchtxt = (is_array($attributes) ? join(',', $attributes) : 'all attributes'); - SimpleSAML_Logger::debug('Library - LDAP: Get attributes from ' . $dn . ' (' . $searchtxt . ')'); - - if (is_array($attributes)) - $sr = @ldap_read($this->ldap, $dn, 'objectClass=*', $attributes ); - else - $sr = @ldap_read($this->ldap, $dn, 'objectClass=*'); - - if ($sr === false) - throw $this->getLDAPException('Could not retrieve attributes for user'); - - $ldapEntry = @ldap_first_entry($this->ldap, $sr); - if ($ldapEntry === false) { - throw $this->getLDAPException('Could not retrieve attributes for user - could not select first entry'); - } - $ldapAttributes = @ldap_get_attributes($this->ldap, $ldapEntry); - if ($ldapAttributes === false) { - throw $this->getLDAPException('Could not retrieve attributes for user - error fetching attributes for select first entry:'); - } + // Preparations, including a pretty debug message... + $description = 'all attributes'; + if (is_array($attributes)) { + $description = '\'' . join(',', $attributes) . '\''; + } else + // Get all attributes... + // TODO: Verify that this originally was the intended behaviour. Could $attributes be a string? + $attributes = array(); + SimpleSAML_Logger::debug('Library - LDAP getAttributes(): Getting ' . $description . ' from DN \'' . $dn . '\''); + + // Attempt to get attributes. + // TODO: Should aliases be dereferenced? + $result = @ldap_read($this->ldap, $dn, 'objectClass=*', $attributes, 0, 0, $this->timeout); + if ($result === false) + throw $this->makeException('Library - LDAP getAttributes(): Failed to get attributes from DN \'' . $dn . '\''); + $entry = @ldap_first_entry($this->ldap, $result); + if ($entry === false) + throw $this->makeException('Library - LDAP getAttributes(): Could not get first entry from DN \'' . $dn . '\''); + $attributes = @ldap_get_attributes($this->ldap, $entry); // Recycling $attributes... Possibly bad practice. + if ($attributes === false) + throw $this->makeException('Library - LDAP getAttributes(): Could not get attributes of first entry from DN \'' . $dn . '\''); + + // Parsing each found attribute into our result set. + $result = array(); // Recycling $result... Possibly bad practice. + for ($i = 0; $i < $attributes['count']; $i++) { + + // Ignore attributes that exceed the maximum allowed size. + $name = $attributes[$i]; + $attribute = $attributes[$name]; + + // Deciding whether to base64 encode. + $values = array(); + for ($j = 0; $j < $attribute['count']; $j++) { + $value = $attribute[$j]; + + if (!empty($maxsize) && strlen($value) >= $maxsize) { + // Ignoring and warning. + SimpleSAML_Logger::warning('Library - LDAP getAttributes(): Attribute \'' . + $name . '\' exceeded maximum allowed size by ' + ($maxsize - strlen($value))); + continue; + } - $attributes = array(); - for ($i = 0; $i < $ldapAttributes['count']; $i++) { - $attributeName = $ldapAttributes[$i]; + // Base64 encode jpegPhoto. + if (strtolower($name) === 'jpegphoto') { + $values[] = base64_encode($value); + } else + $values[] = $value; - $base64encode = FALSE; - $include = FALSE; - - if (strtolower($attributeName) === 'jpegphoto') { - $base64encode = TRUE; } - $attribute = $ldapAttributes[$attributeName]; - $valueCount = $attribute['count']; + // Adding. + $result[$name] = $values; - $values = array(); - for ($j = 0; $j < $valueCount; $j++) { - /* - SimpleSAML_Logger::debug('Library - attribute size of [' . $attributeName . '] (' . strlen($attribute[$j]) . ' of ' . - (is_null($maxsize) ? 'NA' : $maxsize) . ')'); - */ - if (is_null($maxsize) or strlen($attribute[$j]) < $maxsize) { - $include = TRUE; - $values[] = ($base64encode ? base64_encode($attribute[$j]) : $attribute[$j] ); - } else { - SimpleSAML_Logger::debug('Library - attribute size of [' . $attributeName . '] exceeded maximum limit of ' . $maxsize . ' - skipping attribute value'); - } - - } - if ($include) $attributes[$attributeName] = $values; } - - SimpleSAML_Logger::debug('Library - LDAP: Found attributes (' . join(',', array_keys($attributes)) . ')'); - return $attributes; - + + // We're done. + SimpleSAML_Logger::debug('Library - LDAP getAttributes(): Found attributes \'(' . join(',', array_keys($result)) . ')\''); + return $result; } - + + + /** + * Enter description here... + * + * @param string $config + * @param string $username + * @param string $password + * @return array|bool + */ + // TODO: Documentation; only cleared up exception/log messages. public function validate($config, $username, $password = null) { /* Escape any characters with a special meaning in LDAP. The following @@ -272,19 +406,18 @@ class SimpleSAML_Auth_LDAP { */ $username = addcslashes($username, ',+"\\<>;*'); $password = addcslashes($password, ',+"\\<>;*'); - - if (isset($config['priv_user_dn']) && !$this->bind($config['priv_user_dn'], $config['priv_user_pw']) ) { - throw $this->getLDAPException('Could not bind with system user: ' . $config['priv_user_dn']); - } + + if (isset($config['priv_user_dn'])) + $this->bind($config['priv_user_dn'], $config['priv_user_pw']); if (isset($config['dnpattern'])) { $dn = str_replace('%username%', $username, $config['dnpattern']); } else { - $dn = $this->searchfordn($config['searchbase'], $config['searchattributes'], $username); + $dn = $this->searchfordn($config['searchbase'], $config['searchattributes'], $username); } if ($password != null) { /* checking users credentials ... assuming below that she may read her own attributes ... */ if (!$this->bind($dn, $password)) { - SimpleSAML_Logger::info('AUTH - ldap: '. $username . ' failed to authenticate. DN=' . $dn); + SimpleSAML_Logger::info('Library - LDAP validate(): Failed to authenticate \''. $username . '\' using DN \'' . $dn . '\''); return FALSE; } } @@ -294,79 +427,70 @@ class SimpleSAML_Auth_LDAP { */ $attributes = $this->getAttributes($dn, $config['attributes']); return $attributes; - - } - - - + } - /** - * Borrowed function from PEAR:LDAP. - * - * Escapes the given VALUES according to RFC 2254 so that they can be safely used in LDAP filters. - * - * Any control characters with an ACII code < 32 as well as the characters with special meaning in - * LDAP filters "*", "(", ")", and "\" (the backslash) are converted into the representation of a - * backslash followed by two hex digits representing the hexadecimal value of the character. - * - * @param array $values Array of values to escape - * - * @static - * @return array Array $values, but escaped - */ - public static function escape_filter_value($values = array(), $singleValue = TRUE) { - // Parameter validation - if (!is_array($values)) { - $values = array($values); - } + /** + * Borrowed function from PEAR:LDAP. + * + * Escapes the given VALUES according to RFC 2254 so that they can be safely used in LDAP filters. + * + * Any control characters with an ACII code < 32 as well as the characters with special meaning in + * LDAP filters "*", "(", ")", and "\" (the backslash) are converted into the representation of a + * backslash followed by two hex digits representing the hexadecimal value of the character. + * + * @static + * @param array $values Array of values to escape + * @return array Array $values, but escaped + */ + public static function escape_filter_value($values = array(), $singleValue = TRUE) { + // Parameter validation + if (!is_array($values)) { + $values = array($values); + } - foreach ($values as $key => $val) { - // Escaping of filter meta characters - $val = str_replace('\\', '\5c', $val); - $val = str_replace('*', '\2a', $val); - $val = str_replace('(', '\28', $val); - $val = str_replace(')', '\29', $val); + foreach ($values as $key => $val) { + // Escaping of filter meta characters + $val = str_replace('\\', '\5c', $val); + $val = str_replace('*', '\2a', $val); + $val = str_replace('(', '\28', $val); + $val = str_replace(')', '\29', $val); - // ASCII < 32 escaping - $val = self::asc2hex32($val); + // ASCII < 32 escaping + $val = self::asc2hex32($val); - if (null === $val) $val = '\0'; // apply escaped "null" if string is empty + if (null === $val) $val = '\0'; // apply escaped "null" if string is empty - $values[$key] = $val; - } + $values[$key] = $val; + } if ($singleValue) return $values[0]; - return $values; - } - - /** - * Borrowed function from PEAR:LDAP. - * - * Converts all ASCII chars < 32 to "\HEX" - * - * @param string $string String to convert - * - * @static - * @return string - */ - public static function asc2hex32($string) - { - for ($i = 0; $i < strlen($string); $i++) { - $char = substr($string, $i, 1); - if (ord($char) < 32) { - $hex = dechex(ord($char)); - if (strlen($hex) == 1) $hex = '0'.$hex; - $string = str_replace($char, '\\'.$hex, $string); - } - } - return $string; - } - - + return $values; + } + /** + * Borrowed function from PEAR:LDAP. + * + * Converts all ASCII chars < 32 to "\HEX" + * + * @param string $string String to convert + * + * @static + * @return string + */ + public static function asc2hex32($string) { + for ($i = 0; $i < strlen($string); $i++) { + $char = substr($string, $i, 1); + if (ord($char) < 32) { + $hex = dechex(ord($char)); + if (strlen($hex) == 1) $hex = '0'.$hex; + $string = str_replace($char, '\\'.$hex, $string); + } + } + return $string; + } } -?> +?> \ No newline at end of file diff --git a/lib/SimpleSAML/Auth/LDAPException.php b/lib/SimpleSAML/Auth/LDAPException.php deleted file mode 100644 index 876ceeafb..000000000 --- a/lib/SimpleSAML/Auth/LDAPException.php +++ /dev/null @@ -1,38 +0,0 @@ -<?php - -/** - * Exception related to LDAP. - * - * @author Andreas Ă…kre Solberg, UNINETT AS. - * @package simpleSAMLphp - * @version $Id$ - */ -class SimpleSAML_Auth_LDAPException extends Exception { - - - /** - * LDAP Error code - */ - private $ldapErrorcode; - - /** - * Create a new NotFound error - * - * @param string $reason Optional description of why the given page could not be found. - */ - public function __construct($message, $ldapErrorcode = NULL) { - parent::__construct($message . ' (' . $this->getErrorCode() . ')'); - $this->ldapErrorcode = $ldapErrorcode; - } - - /** - * Return the error code from LDAP. - * - */ - public function getErrorCode() { - return $this->ldapErrorcode; - } - -} - -?> \ No newline at end of file diff --git a/lib/SimpleSAML/Error/AuthSource.php b/lib/SimpleSAML/Error/AuthSource.php new file mode 100644 index 000000000..6e353d53e --- /dev/null +++ b/lib/SimpleSAML/Error/AuthSource.php @@ -0,0 +1,14 @@ +<?php +/** + * Baseclass for auth source exceptions. + * + * @author Thomas Graff <thomas.graff@uninett.no> + * @package simpleSAMLphp_base + * @version $Id$ + * + */ +class SimpleSAML_Error_AuthSource extends SimpleSAML_Error_Exception{ + +} + +?> \ No newline at end of file diff --git a/lib/SimpleSAML/Error/BadUserInnput.php b/lib/SimpleSAML/Error/BadUserInnput.php new file mode 100644 index 000000000..69bda7c26 --- /dev/null +++ b/lib/SimpleSAML/Error/BadUserInnput.php @@ -0,0 +1,14 @@ +<?php +/** + * Exception indicating illegal innput from user. + * + * @author Thomas Graff <thomas.graff@uninett.no> + * @package simpleSAMLphp_base + * @version $Id$ + * + */ +class SimpleSAML_Error_BadUserInnput extends SimpleSAML_Error_User{ + +} + +?> \ No newline at end of file diff --git a/lib/SimpleSAML/Error/Exception.php b/lib/SimpleSAML/Error/Exception.php new file mode 100644 index 000000000..9e1f656cd --- /dev/null +++ b/lib/SimpleSAML/Error/Exception.php @@ -0,0 +1,48 @@ +<?php + +/** + * Baseclass for simpleSAML Exceptions + * + * @author Thomas Graff <thomas.graff@uninett.no> + * @package simpleSAMLphp_base + * @version $Id$ + */ +class SimpleSAML_Error_Exception extends Exception { + + /** + * Constructor for this error. + * + * @param string $message Exception message + * @param int $code Error code + */ + public function __construct($message, $code = 0) { + assert('is_string($message) || is_int($code)'); + + parent::__construct($message, $code); + } + + + /** + * Set the HTTP return code for this error. + * + * This should be overridden by subclasses who want a different return code than 500 Internal Server Error. + */ + protected function setHTTPCode() { + header('HTTP/1.0 500 Internal Server Error'); + } + + + /** + * Display this error. + * + * This method displays a standard simpleSAMLphp error page and exits. + */ + public function show() { + $this->setHTTPCode(); + $session = SimpleSAML_Session::getInstance(); + $e = $this; + SimpleSAML_Utilities::fatalError($session->getTrackID(), $this->errorCode, $e); + } +} + +?> \ No newline at end of file diff --git a/lib/SimpleSAML/Error/InvalidCredential.php b/lib/SimpleSAML/Error/InvalidCredential.php new file mode 100644 index 000000000..f8e2bfbf5 --- /dev/null +++ b/lib/SimpleSAML/Error/InvalidCredential.php @@ -0,0 +1,14 @@ +<?php +/** + * Exception indicating wrong password given by user. + * + * @author Thomas Graff <thomas.graff@uninett.no> + * @package simpleSAMLphp_base + * @version $Id$ + * + */ +class SimpleSAML_Error_InvalidCredential extends SimpleSAML_Error_User{ + +} + +?> \ No newline at end of file diff --git a/lib/SimpleSAML/Error/User.php b/lib/SimpleSAML/Error/User.php new file mode 100644 index 000000000..1c7c7a6c6 --- /dev/null +++ b/lib/SimpleSAML/Error/User.php @@ -0,0 +1,16 @@ +<?php + +/** + * Baseclass for user error exceptions + * + * + * @author Thomas Graff <thomas.graff@uninett.no> + * @package simpleSAMLphp_base + * @version $Id$ + * + */ +class SimpleSAML_Error_User extends SimpleSAML_Error_Exception{ + +} + +?> \ No newline at end of file diff --git a/lib/SimpleSAML/Error/UserNotFound.php b/lib/SimpleSAML/Error/UserNotFound.php new file mode 100644 index 000000000..85c09c763 --- /dev/null +++ b/lib/SimpleSAML/Error/UserNotFound.php @@ -0,0 +1,15 @@ +<?php + +/** + * Exception indicating user not found by authsource. + * + * @author Thomas Graff <thomas.graff@uninett.no> + * @package simpleSAMLphp_base + * @version $Id$ + * + */ +class SimpleSAML_Error_UserNotFound extends SimpleSAML_Error_User{ + +} + +?> \ No newline at end of file diff --git a/modules/ldapstatus/lib/Auth/Backend/Test/StandardLDAPTest.php b/modules/ldapstatus/lib/Auth/Backend/Test/StandardLDAPTest.php index c33a0e1d8..104265f88 100755 --- a/modules/ldapstatus/lib/Auth/Backend/Test/StandardLDAPTest.php +++ b/modules/ldapstatus/lib/Auth/Backend/Test/StandardLDAPTest.php @@ -132,7 +132,7 @@ class sspmod_ldapstatus_Auth_Backend_Test_StandardLDAPTest extends sspmod_feide_ $result['ldapSearchBogus'] = array(TRUE,$tester->tack('ldapSearchBogus')); $result['ldapSearchBogus']['time'] = $tester->tack('ldapSearchBogus', FALSE); - } catch (sspmod_feide_Exception_UserNotFound $e) { + } catch (SimpleSAML_Error_UserNotFound $e) { $result['ldapSearchBogus'] = array(TRUE,$tester->tack('ldapSearchBogus')); } catch (Exception $e) { -- GitLab