__METHOD__)); } /** * @defunct This required abstruct function is defunct for LDAP */ public function commit() { throw HTTP_Exception::factory(501,'We shouldnt be here: :method',array(':method'=>__METHOD__)); } /** * @defunct This required abstruct function is defunct for LDAP */ public function list_tables($like = NULL) { throw HTTP_Exception::factory(501,'We shouldnt be here: :method',array(':method'=>__METHOD__)); } /** * @defunct This required abstruct function is defunct for LDAP */ public function query($type, $sql, $as_object = FALSE, array $params = NULL) { throw HTTP_Exception::factory(501,'We shouldnt be here: :method',array(':method'=>__METHOD__)); } /** * @defunct This required abstruct function is defunct for LDAP */ public function rollback() { throw HTTP_Exception::factory(501,'We shouldnt be here: :method',array(':method'=>__METHOD__)); } /** * @defunct This required abstruct function is defunct for LDAP */ public function set_charset($charset) { throw HTTP_Exception::factory(501,'We shouldnt be here: :method',array(':method'=>__METHOD__)); } /** REQUIRED ABSTRACT FUNCTIONS **/ public function escape($value) { return $value;} /** * @override We provide the columns that are in all LDAP objects */ public function list_columns($table,$like=NULL,$add_prefix=TRUE) { return array('dn'=>array('data_type'=>NULL),'objectclass'=>array('data_type'=>NULL)); } /** * @override We override this parent function, since LDAP doesnt quote columns */ public function quote_column($column) { return $column; } /** LDAP **/ /** * Bind to the LDAP server with the creditials * * If we are successful, we return TRUE, if not FALSE * * @return boolean TRUE|FALSE */ private function _bind($u,$p) { Log::instance()->add(LOG_NOTICE,':instance :method BINDing, Username :user, Pass :pass',array(':instance'=>$this->_instance,':method'=>__METHOD__,':user'=>$u,':pass'=>md5($p))); /* // @todo To implement // If SASL has been configured for binding, then start it now. if ($this->isSASLEnabled()) $br = $this->startSASL($this->_r,$method); // Normal bind... else */ if (Kohana::$profiling) $benchmark = Profiler::start("Database LDAP ({$this->_instance})",__METHOD__); try { $br = ldap_bind($this->_connection,$u,$p); } catch (Exception $e) { // This benchmark is worthless if (isset($benchmark)) Profiler::delete($benchmark); return FALSE; } if (! $br) return FALSE; Log::instance()->add(LOG_NOTICE,':instance :method BOUND, Username :user, Pass :pass',array(':instance'=>$this->_instance,':method'=>__METHOD__,':user'=>$u,':pass'=>md5($p))); $this->_connected = TRUE; /* // @todo To implement # If this is a proxy session, we need to switch to the proxy user if ($this->isProxyEnabled() && $bind['id'] && $method != 'anon') if (! $this->startProxy($this->_r,$method)) { $CACHE[$this->index][$method] = null; } */ /* // @todo To implement if (function_exists('run_hook')) run_hook('post_connect',array('server_id'=>$this->index,'method'=>$method,'id'=>$bind['id'])); */ // Get our Schema. if (isset($benchmark)) { Profiler::stop($benchmark); $benchmark = Profiler::start("Database LDAP ({$this->_instance})", 'Schema Retrieve'); } if (isset($benchmark)) Profiler::stop($benchmark); return $br; } /** * Bind to the LDAP server * * If we have been passed a login_attr that is not DN, we'll try and find the * DN to bind with. * * @param string User attribute to connect with, or blank for anonymous * @param string Bind password to use with a DN or blank for anonymous * @return mixed $this|FALSE */ public function bind($user,$pass) { // If we are already connected, no need to re-bind. if ($this->_connected) return $this; // Make sure we are connected. $this->_connection OR $this->connect(); Log::instance()->add(LOG_NOTICE,':instance :method BINDing, Username :user, Pass :pass, LoginAttr :login_attr',array(':instance'=>$this->_instance,':method'=>__METHOD__,':user'=>$user,':pass'=>md5($pass),':login_attr'=>$this->_config['login_attr'])); // Do we need to do an search to find the DN if (! empty($this->_config['login_attr']) AND strtoupper($this->_config['login_attr']) != 'DN') { Log::instance()->add(LOG_NOTICE,':instance :method BINDing, Searching for DN',array(':instance'=>$this->_instance,':method'=>__METHOD__)); // Do we need to authenticate for this search? // Extract the connection parameters, adding required variabels extract($this->_config['connection'] + array( 'username' => '', 'password' => '', 'hostname' => '', 'port' => '', )); // Prevent this information from showing up in traces unset($this->_config['connection']['username'], $this->_config['connection']['password']); // Sanity check if ($this->_instance == 'auth') throw new Kohana_Exception('We shouldnt be authing an auth'); $config = Arr::merge($this->_config,array( 'login_attr'=>'DN', 'connection'=>array( 'hostname'=>$hostname, 'port'=>$port, ), )); try { Log::instance()->add(LOG_NOTICE,':instance :method AUTH BINDing, Username :user, Pass :pass, LoginAttr :login_attr',array(':instance'=>$this->_instance,':method'=>__METHOD__,':user'=>$username,':pass'=>md5($password))); $x = LDAP::factory('auth',NULL,$config); // Our Auth Bind credentials are wrong if (! $x->bind($username,$password)) return FALSE; $u = $x->search(NULL) ->scope('sub') ->where($this->_config['login_attr'],'=',$user) ->execute(NULL,'Model_LDAP'); if (! $u) return FALSE; } catch (Exception $e) { // If we are a command line, we can just print the error echo _('Unable to bind to LDAP server with CONFIG settings, please check them.'); echo _('The error message is').': '.$e->getMessage(); die(); } foreach ($u as $dn => $leaf) if ($this->_bind($dn,$pass)) return ORM::factory('LDAP',$dn); // We didnt find an AUTH DN to bind with return FALSE; } // Bind if ($this->_bind($user,$pass)) return $this; else return FALSE; } /** * Create a connection to an LDAP server */ public function connect() { if ($this->_connection) return; // Extract the connection parameters, adding required variabels extract($this->_config['connection'] + array( 'hostname' => '', 'port' => '', )); Log::instance()->add(LOG_NOTICE,':instance :method CONNECT:- host :hostname, port :port',array(':instance'=>$this->_instance,':method'=>__METHOD__,':hostname'=>$hostname,':port'=>$port)); /* // @todo To implement if (function_exists('run_hook')) run_hook('pre_connect',array('server_id'=>$this->index,'method'=>$method)); */ // Benchmark this connection for the current instance if (Kohana::$profiling) $benchmark = Profiler::start("Database LDAP ({$this->_instance})",__METHOD__); $r = (! empty($this->_config['port'])) ? ldap_connect($hostname,$port) : ldap_connect($hostname); if (! is_resource($r)) { // This benchmark is worthless if (isset($benchmark)) Profiler::delete($benchmark); throw HTTP_Exception::factory(501,'UNHANDLED, $r is not a resource'); } // Go with LDAP version 3 if possible (needed for renaming and Novell schema fetching) ldap_set_option($r,LDAP_OPT_PROTOCOL_VERSION,3); /* Disabling this makes it possible to browse the tree for Active Directory, and seems * to not affect other LDAP servers (tested with OpenLDAP) as phpLDAPadmin explicitly * specifies deref behavior for each ldap_search operation. */ ldap_set_option($r,LDAP_OPT_REFERRALS,0); /* // @todo To implement # Try to fire up TLS is specified in the config if ($this->isTLSEnabled()) $this->startTLS($this->_connection); */ if (isset($benchmark)) Profiler::stop($benchmark); Log::instance()->add(LOG_NOTICE,':instance :method connectED',array(':instance'=>$this->_instance,':method'=>__METHOD__)); $this->_connection = $r; } public function disconnect() { try { // Database is assumed disconnected $status = TRUE; if (is_resource($this->_connection)) { if ($status = ldap_unbind($this->_connection)) { // Clear the connection $this->_connection = NULL; // Clear the instance parent::disconnect(); } } } catch (Exception $e) { // Database is probably not disconnected $status = ! is_resource($this->_connection); } return $status; } public function getSchema() { // Make sure our login_attr is DN if ($this->_instance == 'schema' AND $this->_config['login_attr'] != 'DN') $this->_config['login_attr'] = 'DN'; $x = LDAP::factory('schema',NULL,$this->_config); try { // @todo We should bind as specific shema DN, logged in User or anonymous. if ($x->bind((isset($this->_config['schema']['dn']) ? $this->_config['schema']['dn'] : FALSE),(isset($this->_config['schema']['password']) ? $this->_config['schema']['password'] : FALSE))) { $u = $x->search(array('')) ->scope('base') // @todo: This should be a config item ->cached(86400) ->execute(); if (! $u OR ! isset($u[''][0]['subschemasubentry'][0])) throw new Kohana_Exception('Couldnt find schema?'); $x->setSchema(ORM::factory('LDAP_Schema',$u[''][0]['subschemasubentry'][0])); } } catch (Exception $e) { // If we are a command line, we can just print the error echo _('Unable to retrieve the SCHEMA from the LDAP server.'); echo _('The error message is').': '.$e->getMessage(); die(); } } public function search($base=array()) { return new Database_LDAP_Search($this,$base); } } ?>