* * 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; 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 */ private $_ch = null; private $_username = ''; private $_password = ''; private $_starttls = false; public function __construct($URI, $debug = false, $starttls = false) { $this->_debug=$debug; $array = parse_url($URI); 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 AuthLdap_Exception */ 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 (! $this->_ch) { throw new AuthLDAP_Exception('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 (is_resource($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 (! is_resource($this->_ch)) { throw new AuthLDAP_Exception('No Resource-handle given'); } $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 AuthLDAP_Exception('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 (! is_Resource($this->_ch)) { throw new AuthLDAP_Exception('No resource handle avbailable'); } if (! $base) { $base = $this->_baseDn; } $result = ldap_search($this->_ch, $base, $filter, $attributes); if ($result === false) { throw new AuthLDAP_Exception('no result found'); } $this->_info = @ldap_get_entries($this->_ch, $result); if ($this->_info === false) { throw new AuthLDAP_Exception('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, $username)); 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 AuthLDAP_Exception('[LDAP_ERROR]' . ldap_errno($this->_ch) . ':' . ldap_error($this->_ch), $_v[0]['line']); } } } class AuthLDAP_Exception extends Exception { public function __construct($message, $line = null) { parent :: __construct($message); if ($line) { $this -> line = $line; } } }