⚝
One Hat Cyber Team
⚝
Your IP:
216.73.216.78
Server IP:
41.128.143.86
Server:
Linux host.raqmix.cloud 6.8.0-1025-azure #30~22.04.1-Ubuntu SMP Wed Mar 12 15:28:20 UTC 2025 x86_64
Server Software:
Apache
PHP Version:
8.3.23
Buat File
|
Buat Folder
Eksekusi
Dir :
~
/
usr
/
share
/
psa-pear
/
pear
/
php
/
Horde
/
Auth
/
Edit File: Ldap.php
<?php /** * Copyright 1999-2017 Horde LLC (http://www.horde.org/) * * See the enclosed file COPYING for license information (LGPL). If you did * not receive this file, see http://www.horde.org/licenses/lgpl21. * * @author Jon Parise <jon@horde.org> * @category Horde * @license http://www.horde.org/licenses/lgpl21 LGPL-2.1 * @package Auth */ /** * The Horde_Auth_Ldap class provides an LDAP implementation of the Horde * authentication system. * * 'preauthenticate' hook should return LDAP connection information in the * 'ldap' credentials key. * * @author Jon Parise <jon@horde.org> * @category Horde * @copyright 1999-2017 Horde LLC * @license http://www.horde.org/licenses/lgpl21 LGPL-2.1 * @package Auth */ class Horde_Auth_Ldap extends Horde_Auth_Base { /** * An array of capabilities, so that the driver can report which * operations it supports and which it doesn't. * * @var array */ protected $_capabilities = array( 'add' => true, 'update' => true, 'resetpassword' => true, 'remove' => true, 'list' => true, 'authenticate' => true, ); /** * LDAP object * * @var Horde_Ldap */ protected $_ldap; /** * Constructor. * * @param array $params Required parameters: * <pre> * 'basedn' - (string) [REQUIRED] The base DN for the LDAP server. * 'filter' - (string) The LDAP formatted search filter to search for * users. This setting overrides the 'objectclass' parameter. * 'ldap' - (Horde_Ldap) [REQUIRED] Horde LDAP object. * 'objectclass - (string|array): The objectclass filter used to search * for users. Either a single or an array of objectclasses. * 'uid' - (string) [REQUIRED] The username search key. * </pre> * * @throws Horde_Auth_Exception * @throws InvalidArgumentException */ public function __construct(array $params = array()) { foreach (array('basedn', 'ldap', 'uid') as $val) { if (!isset($params[$val])) { throw new InvalidArgumentException(__CLASS__ . ': Missing ' . $val . ' parameter.'); } } if (!empty($params['ad'])) { $this->_capabilities['resetpassword'] = false; } $this->_ldap = $params['ldap']; unset($params['ldap']); parent::__construct($params); } /** * Checks for shadowLastChange and shadowMin/Max support and returns their * values. We will also check for pwdLastSet if Active Directory is * support is requested. For this check to succeed we need to be bound * to the directory. * * @param string $dn The dn of the user. * * @return array Array with keys being "shadowlastchange", "shadowmin" * "shadowmax", "shadowwarning" and containing their * respective values or false for no support. */ protected function _lookupShadow($dn) { /* Init the return array. */ $lookupshadow = array( 'shadowlastchange' => false, 'shadowmin' => false, 'shadowmax' => false, 'shadowwarning' => false ); /* According to LDAP standard, to read operational attributes, you * must request them explicitly. Attributes involved in password * expiration policy: * pwdlastset: Active Directory * shadow*: shadowUser schema * passwordexpirationtime: Sun and Fedora Directory Server */ try { $result = $this->_ldap->search(null, '(objectClass=*)', array( 'attributes' => array( 'pwdlastset', 'shadowmax', 'shadowmin', 'shadowlastchange', 'shadowwarning', 'passwordexpirationtime' ), 'scope' => 'base' )); } catch (Horde_Ldap_Exception $e) { return $lookupshadow; } if (!$result) { return $lookupshadow; } $info = reset($result); // TODO: 'ad'? if (!empty($this->_params['ad'])) { if (isset($info['pwdlastset'][0])) { /* Active Directory handles timestamps a bit differently. * Convert the timestamp to a UNIX timestamp. */ $lookupshadow['shadowlastchange'] = floor((($info['pwdlastset'][0] / 10000000) - 11644406783) / 86400) - 1; /* Password expiry attributes are in a policy. We cannot * read them so use the Horde config. */ $lookupshadow['shadowwarning'] = $this->_params['warnage']; $lookupshadow['shadowmin'] = $this->_params['minage']; $lookupshadow['shadowmax'] = $this->_params['maxage']; } } elseif (isset($info['passwordexpirationtime'][0])) { /* Sun/Fedora Directory Server uses a special attribute * passwordexpirationtime. It has precedence over shadow* * because it actually locks the expired password at the LDAP * server level. The correct way to check expiration should * be using LDAP controls, unfortunately PHP doesn't support * controls on bind() responses. */ $ldaptimepattern = "/([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})Z/"; if (preg_match($ldaptimepattern, $info['passwordexpirationtime'][0], $regs)) { /* Sun/Fedora Directory Server return expiration time, not * last change time. We emulate the behaviour taking it * back to maxage. */ $lookupshadow['shadowlastchange'] = floor(mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]) / 86400) - $this->_params['maxage']; /* Password expiry attributes are in not accessible policy * entry. */ $lookupshadow['shadowwarning'] = $this->_params['warnage']; $lookupshadow['shadowmin'] = $this->_params['minage']; $lookupshadow['shadowmax'] = $this->_params['maxage']; } elseif ($this->_logger) { $this->_logger->log('Wrong time format: ' . $info['passwordexpirationtime'][0], 'ERR'); } } else { if (isset($info['shadowmax'][0])) { $lookupshadow['shadowmax'] = $info['shadowmax'][0]; } if (isset($info['shadowmin'][0])) { $lookupshadow['shadowmin'] = $info['shadowmin'][0]; } if (isset($info['shadowlastchange'][0])) { $lookupshadow['shadowlastchange'] = $info['shadowlastchange'][0]; } if (isset($info['shadowwarning'][0])) { $lookupshadow['shadowwarning'] = $info['shadowwarning'][0]; } } return $lookupshadow; } /** * Find out if the given set of login credentials are valid. * * @param string $userId The userId to check. * @param array $credentials An array of login credentials. * * @throws Horde_Auth_Exception */ protected function _authenticate($userId, $credentials) { if (!strlen($credentials['password'])) { throw new Horde_Auth_Exception('', Horde_Auth::REASON_BADLOGIN); } /* Search for the user's full DN. */ $this->_ldap->bind(); try { $dn = $this->_ldap->findUserDN($userId); } catch (Horde_Exception_NotFound $e) { throw new Horde_Auth_Exception('', Horde_Auth::REASON_BADLOGIN); } catch (Horde_Exception_Ldap $e) { throw new Horde_Auth_Exception($e->getMessage(), Horde_Auth::REASON_MESSAGE); } /* Attempt to bind to the LDAP server as the user. */ try { $this->_ldap->bind($dn, $credentials['password']); // Be sure we rebind as the configured user. $this->_ldap->bind(); } catch (Horde_Ldap_Exception $e) { // Be sure we rebind as the configured user. $this->_ldap->bind(); if (Horde_Ldap::errorName($e->getCode() == 'LDAP_INVALID_CREDENTIALS')) { throw new Horde_Auth_Exception('', Horde_Auth::REASON_BADLOGIN); } throw new Horde_Auth_Exception($e->getMessage(), Horde_Auth::REASON_MESSAGE); } if ($this->_params['password_expiration'] == 'yes') { $shadow = $this->_lookupShadow($dn); if ($shadow['shadowmax'] && $shadow['shadowlastchange'] && $shadow['shadowwarning']) { $today = floor(time() / 86400); $toexpire = $shadow['shadowlastchange'] + $shadow['shadowmax'] - $today; $warnday = $shadow['shadowlastchange'] + $shadow['shadowmax'] - $shadow['shadowwarning']; if ($today >= $warnday) { $this->setCredential('expire', $toexpire); } if ($toexpire == 0) { $this->setCredential('change', true); } elseif ($toexpire < 0) { throw new Horde_Auth_Exception('', Horde_Auth::REASON_EXPIRED); } } } } /** * Add a set of authentication credentials. * * @param string $userId The userId to add. * @param array $credentials The credentials to be set. * * @throws Horde_Auth_Exception */ public function addUser($userId, $credentials) { if (!empty($this->_params['ad'])) { throw new Horde_Auth_Exception(__CLASS__ . ': Adding users is not supported for Active Directory.'); } if (isset($credentials['ldap'])) { $entry = $credentials['ldap']; $dn = $entry['dn']; /* Remove the dn entry from the array. */ unset($entry['dn']); } else { /* Try this simple default and hope it works. */ $dn = $this->_params['uid'] . '=' . $userId . ',' . $this->_params['basedn']; $entry['cn'] = $userId; $entry['sn'] = $userId; $entry[$this->_params['uid']] = $userId; $entry['objectclass'] = array_merge( array('top'), $this->_params['newuser_objectclass']); $entry['userPassword'] = Horde_Auth::getCryptedPassword( $credentials['password'], '', $this->_params['encryption'], 'true'); if ($this->_params['password_expiration'] == 'yes') { $entry['shadowMin'] = $this->_params['minage']; $entry['shadowMax'] = $this->_params['maxage']; $entry['shadowWarning'] = $this->_params['warnage']; $entry['shadowLastChange'] = floor(time() / 86400); } } try { $this->_ldap->add(Horde_Ldap_Entry::createFresh($dn, $entry)); } catch (Horde_Ldap_Exception $e) { throw new Horde_Auth_Exception(sprintf(__CLASS__ . ': Unable to add user "%s". This is what the server said: ', $userId) . $e->getMessage()); } } /** * Remove a set of authentication credentials. * * @param string $userId The userId to add. * @param string $dn TODO * * @throws Horde_Auth_Exception */ public function removeUser($userId, $dn = null) { if (!empty($this->_params['ad'])) { throw new Horde_Auth_Exception(__CLASS__ . ': Removing users is not supported for Active Directory'); } if (is_null($dn)) { /* Search for the user's full DN. */ try { $dn = $this->_ldap->findUserDN($userId); } catch (Horde_Exception_Ldap $e) { throw new Horde_Auth_Exception($e); } } try { $this->_ldap->delete($dn); } catch (Horde_Ldap_Exception $e) { throw new Horde_Auth_Exception(sprintf(__CLASS__ . ': Unable to remove user "%s"', $userId)); } } /** * Update a set of authentication credentials. * * @todo Clean this up for Horde 5. * * @param string $oldID The old userId. * @param string $newID The new userId. * @param array $credentials The new credentials. * @param string $olddn The old user DN. * @param string $newdn The new user DN. * * @throws Horde_Auth_Exception */ public function updateUser($oldID, $newID, $credentials, $olddn = null, $newdn = null) { if (!empty($this->_params['ad'])) { throw new Horde_Auth_Exception(__CLASS__ . ': Updating users is not supported for Active Directory.'); } if (is_null($olddn)) { /* Search for the user's full DN. */ try { $dn = $this->_ldap->findUserDN($oldID); } catch (Horde_Exception_Ldap $e) { throw new Horde_Auth_Exception($e); } $olddn = $dn; $newdn = preg_replace('/uid=.*?,/', 'uid=' . $newID . ',', $dn, 1); $shadow = $this->_lookupShadow($dn); /* If shadowmin hasn't yet expired only change when we are administrator */ if ($shadow['shadowlastchange'] && $shadow['shadowmin'] && ($shadow['shadowlastchange'] + $shadow['shadowmin'] > (time() / 86400))) { throw new Horde_Auth_Exception('Minimum password age has not yet expired'); } /* Set the lastchange field */ if ($shadow['shadowlastchange']) { $entry['shadowlastchange'] = floor(time() / 86400); } /* Encrypt the new password */ $entry['userpassword'] = Horde_Auth::getCryptedPassword( $credentials['password'], '', $this->_params['encryption'], 'true'); } else { $entry = $credentials; unset($entry['dn']); } try { if ($oldID != $newID) { $this->_ldap->move($olddn, $newdn); $this->_ldap->modify($newdn, array('replace' => $entry)); } else { $this->_ldap->modify($olddn, array('replace' => $entry)); } } catch (Horde_Ldap_Exception $e) { throw new Horde_Auth_Exception(sprintf(__CLASS__ . ': Unable to update user "%s"', $newID)); } } /** * Reset a user's password. Used for example when the user does not * remember the existing password. * * @param string $userId The user id for which to reset the password. * * @return string The new password on success. * @throws Horde_Auth_Exception */ public function resetPassword($userId) { if (!empty($this->_params['ad'])) { throw new Horde_Auth_Exception(__CLASS__ . ': Updating users is not supported for Active Directory.'); } /* Search for the user's full DN. */ try { $dn = $this->_ldap->findUserDN($userId); } catch (Horde_Exception_Ldap $e) { throw new Horde_Auth_Exception($e); } /* Get a new random password. */ $password = Horde_Auth::genRandomPassword(); /* Encrypt the new password */ $entry = array( 'userpassword' => Horde_Auth::getCryptedPassword($password, '', $this->_params['encryption'], 'true')); /* Set the lastchange field */ $shadow = $this->_lookupShadow($dn); if ($shadow['shadowlastchange']) { $entry['shadowlastchange'] = floor(time() / 86400); } /* Update user entry. */ try { $this->_ldap->modify($dn, array('replace' => $entry)); } catch (Horde_Ldap_Exception $e) { throw new Horde_Auth_Exception($e); } return $password; } /** * Lists all users in the system. * * @param boolean $sort Sort the users? * * @return array The array of userIds. * @throws Horde_Auth_Exception */ public function listUsers($sort = false) { $params = array( 'attributes' => array($this->_params['uid']), 'scope' => $this->_params['scope'], 'sizelimit' => isset($this->_params['sizelimit']) ? $this->_params['sizelimit'] : 0 ); /* Add a sizelimit, if specified. Default is 0, which means no limit. * Note: You cannot override a server-side limit with this. */ $userlist = array(); try { $search = $this->_ldap->search( $this->_params['basedn'], Horde_Ldap_Filter::build(array('filter' => $this->_params['filter'])), $params); $uid = Horde_String::lower($this->_params['uid']); foreach ($search as $val) { $userlist[] = $val->getValue($uid, 'single'); } } catch (Horde_Ldap_Exception $e) { } return $this->_sort($userlist, $sort); } /** * Checks if $userId exists in the LDAP backend system. * * @author Marco Ferrante, University of Genova (I) * * @param string $userId User ID for which to check * * @return boolean Whether or not $userId already exists. */ public function exists($userId) { $params = array( 'scope' => $this->_params['scope'] ); try { $uidfilter = Horde_Ldap_Filter::create($this->_params['uid'], 'equals', $userId); $classfilter = Horde_Ldap_Filter::build(array('filter' => $this->_params['filter'])); $search = $this->_ldap->search( $this->_params['basedn'], Horde_Ldap_Filter::combine('and', array($uidfilter, $classfilter)), $params); if ($search->count() < 1) { return false; } if ($search->count() > 1 && $this->_logger) { $this->_logger->log('Multiple LDAP entries with user identifier ' . $userId, 'WARN'); } return true; } catch (Horde_Ldap_Exception $e) { if ($this->_logger) { $this->_logger->log('Error searching LDAP user: ' . $e->getMessage(), 'ERR'); } return false; } } }
Simpan