Initial Working KH Module for LDAP queries
This commit is contained in:
commit
81aec2f376
4
classes/Auth/LDAP.php
Normal file
4
classes/Auth/LDAP.php
Normal file
@ -0,0 +1,4 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
|
||||
class Auth_LDAP extends Kohana_Auth_LDAP {}
|
||||
?>
|
4
classes/Database/LDAP.php
Normal file
4
classes/Database/LDAP.php
Normal file
@ -0,0 +1,4 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
|
||||
class Database_LDAP extends Kohana_Database_LDAP {}
|
||||
?>
|
4
classes/Database/LDAP/Search.php
Normal file
4
classes/Database/LDAP/Search.php
Normal file
@ -0,0 +1,4 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
|
||||
class Database_LDAP_Search extends Kohana_Database_LDAP_Search {}
|
||||
?>
|
4
classes/Database/LDAP/Search/Builder/Query.php
Normal file
4
classes/Database/LDAP/Search/Builder/Query.php
Normal file
@ -0,0 +1,4 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
|
||||
class Database_LDAP_Search_Builder_Query extends Kohana_Database_LDAP_Search_Builder_Query {}
|
||||
?>
|
85
classes/Kohana/Auth/LDAP.php
Normal file
85
classes/Kohana/Auth/LDAP.php
Normal file
@ -0,0 +1,85 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
|
||||
/**
|
||||
* LDAP Auth driver.
|
||||
*
|
||||
* @package Kohana/LDAP
|
||||
* @subpackage Auth/LDAP
|
||||
* @category Helpers
|
||||
* @author Deon George
|
||||
* @copyright (c) phpLDAPadmin Development Team
|
||||
* @license http://dev.phpldapadmin.org/license.html
|
||||
*/
|
||||
class Kohana_Auth_LDAP extends Auth {
|
||||
// Unnused required abstract functions
|
||||
public function password($username) {}
|
||||
public function check_password($password) {}
|
||||
|
||||
// Overrides
|
||||
public function hash($str) {
|
||||
// Since this is used automatically to encrypted a password, we need to suppress that for LDAP
|
||||
if (! $this->_config['hash_key'])
|
||||
return $str;
|
||||
else
|
||||
return parent::hash($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a user in.
|
||||
*
|
||||
* @param string username
|
||||
* @param string password
|
||||
* @param boolean enable autologin (not supported)
|
||||
* @return boolean
|
||||
*/
|
||||
protected function _login($user, $password, $remember) {
|
||||
if ( ! is_object($user)) {
|
||||
$username = $user;
|
||||
|
||||
// Load the user
|
||||
// @todo Get the server ID
|
||||
$user = Database_LDAP::factory('user')->bind($username,$password);
|
||||
}
|
||||
|
||||
// @todo Implement conditional logging based on memberships to groups or other criteria.
|
||||
// @todo This check of user being logged in needs to be better
|
||||
if ($user) {
|
||||
/*
|
||||
// @todo To implement
|
||||
if ($remember === TRUE) {
|
||||
// Token data
|
||||
$data = array(
|
||||
'user_id'=>$user->id,
|
||||
'expires'=>time()+$this->_config['lifetime'],
|
||||
'user_agent'=>sha1(Request::$user_agent),
|
||||
);
|
||||
|
||||
// Create a new autologin token
|
||||
$token = ORM::factory('user_token')
|
||||
->values($data)
|
||||
->create();
|
||||
|
||||
// Set the autologin cookie
|
||||
Cookie::set('authautologin', $token->token, $this->_config['lifetime']);
|
||||
}
|
||||
*/
|
||||
|
||||
// Finish the login
|
||||
if (PHP_SAPI !== 'cli')
|
||||
$this->complete_login($user);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Login failed
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
public function logout($destroy=FALSE,$logout_all=FALSE) {
|
||||
Database_LDAP::factory('user')->disconnect();
|
||||
|
||||
if (PHP_SAPI !== 'cli')
|
||||
return parent::logout($destroy,$logout_all);
|
||||
}
|
||||
}
|
||||
?>
|
267
classes/Kohana/Database/LDAP.php
Normal file
267
classes/Kohana/Database/LDAP.php
Normal file
@ -0,0 +1,267 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
|
||||
/**
|
||||
* This class takes care of communicating with LDAP
|
||||
*
|
||||
* @package Kohana/LDAP
|
||||
* @category Database/LDAP
|
||||
* @author Deon George
|
||||
* @copyright (c) phpLDAPadmin Development Team
|
||||
* @license http://dev.phpldapadmin.org/license.html
|
||||
*/
|
||||
abstract class Kohana_Database_LDAP extends Database {
|
||||
// Our required abstract functions
|
||||
public function set_charset($charset) {}
|
||||
public function query($type, $sql, $as_object = FALSE, array $params = NULL) {}
|
||||
public function begin($mode = NULL) {}
|
||||
public function commit() {}
|
||||
public function rollback() {}
|
||||
public function list_tables($like = NULL) {}
|
||||
public function list_columns($table, $like = NULL, $add_prefix = TRUE) {}
|
||||
public function escape($value) { return $value;}
|
||||
|
||||
/** OVERRIDES **/
|
||||
|
||||
/**
|
||||
* We override this parent function, since LDAP doesnt quote columns
|
||||
* @note Override
|
||||
*/
|
||||
public function quote_column($column) {
|
||||
return $column;
|
||||
}
|
||||
|
||||
/** Database_LDAP **/
|
||||
|
||||
/**
|
||||
* @var boolean Whether we are full connected connection & bind
|
||||
*/
|
||||
protected $_connected = FALSE;
|
||||
|
||||
/**
|
||||
* @var string Our default usage when connection
|
||||
*/
|
||||
public static $usage = 'default';
|
||||
|
||||
private function _bind($u,$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 Bind ({$this->_instance})", $this->_instance);
|
||||
|
||||
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;
|
||||
|
||||
$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']));
|
||||
*/
|
||||
|
||||
if (isset($benchmark))
|
||||
Profiler::stop($benchmark);
|
||||
|
||||
return $br;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind to the LDAP server
|
||||
*
|
||||
* @param string User DN to connect with, or blank for anonymous
|
||||
* @param string Password for DN, or blank for anonymous
|
||||
*/
|
||||
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();
|
||||
|
||||
// Do we need to do an search to find the DN
|
||||
if (! empty($this->_config['login_attr']) AND strtoupper($this->_config['login_attr']) != 'DN') {
|
||||
// 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 = array(
|
||||
'login_attr'=>'DN',
|
||||
'type'=>$this->_config['type'],
|
||||
'connection'=>array(
|
||||
'hostname'=>$hostname,
|
||||
'port'=>$port,
|
||||
),
|
||||
);
|
||||
|
||||
try {
|
||||
$x = Database_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)
|
||||
->run();
|
||||
|
||||
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 $base => $entries)
|
||||
foreach ($entries as $dn => $details)
|
||||
if ($this->_bind($details['dn'],$pass)) {
|
||||
// \xFF is a better delimiter, but the PHP driver uses underscore
|
||||
$this->_connection_id = sha1($this->_instance.'_'.$details['dn']);
|
||||
return $this;
|
||||
}
|
||||
|
||||
// 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' => '',
|
||||
));
|
||||
|
||||
/*
|
||||
// @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 Connect ({$this->_instance})", $this->_instance);
|
||||
|
||||
$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);
|
||||
|
||||
$this->_connection = $r;
|
||||
}
|
||||
|
||||
public function connected() {
|
||||
return ($this->_connection AND $this->_connected);
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper for parent::instance(), so that we can create multiple connections
|
||||
* to the same LDAP server with different credentials/purposes.
|
||||
*
|
||||
* @param string A free form usage name, for this connection
|
||||
* @param string A database configuration name, as per parent::instance()
|
||||
* @param array An alternative database configuration to use for $name.
|
||||
* @see Database::instance();
|
||||
*/
|
||||
public static function factory($usage=NULL,$name=NULL,array $config=NULL) {
|
||||
// Use the default instance name
|
||||
if ($usage === NULL)
|
||||
$usage = Database_LDAP::$usage;
|
||||
|
||||
if (! isset(Database::$instances[$usage])) {
|
||||
// Use the default instance name
|
||||
if ($name === NULL)
|
||||
$name = Database::$default;
|
||||
|
||||
// Load the configuration for this database
|
||||
if ($config === NULL)
|
||||
$config = Kohana::$config->load('database')->$name;
|
||||
}
|
||||
|
||||
return parent::instance($usage,$config);
|
||||
}
|
||||
|
||||
public function search($base=array()) {
|
||||
return new Database_LDAP_Search($this->_connection,$base);
|
||||
}
|
||||
}
|
||||
?>
|
246
classes/Kohana/Database/LDAP/Search.php
Normal file
246
classes/Kohana/Database/LDAP/Search.php
Normal file
@ -0,0 +1,246 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
|
||||
/**
|
||||
* This class takes care of searching within LDAP
|
||||
*
|
||||
* @package Kohana/LDAP
|
||||
* @subpackage LDAP/Search
|
||||
* @category Helpers
|
||||
* @author Deon George
|
||||
* @copyright (c) phpLDAPadmin Development Team
|
||||
* @license http://dev.phpldapadmin.org/license.html
|
||||
*/
|
||||
abstract class Kohana_Database_LDAP_Search {
|
||||
private $_connection; // Our LDAP Server to query
|
||||
|
||||
private $_attrs = array('*','+'); // LDAP Attributes to Return
|
||||
private $_base = array(); // LDAP Search Base
|
||||
private $_deref = LDAP_DEREF_NEVER; // LDAP Search Default DEREF
|
||||
private $_filter = '(objectclass=*)'; // LDAP Search Filter
|
||||
private $_size_limit = '500'; // LDAP Search Size Limit
|
||||
private $_scope = 'base'; // LDAP Search Scope
|
||||
private $_time_limit = '60'; // LDAP Search Time Limit
|
||||
private $_db_pending = array(); // LDAP Query Filter to compile
|
||||
|
||||
/**
|
||||
* Callable database methods
|
||||
* @var array
|
||||
*/
|
||||
protected static $_db_methods = array(
|
||||
'where', 'and_where', 'or_where', 'where_open', 'and_where_open', 'or_where_open', 'where_close',
|
||||
'and_where_close', 'or_where_close',
|
||||
);
|
||||
|
||||
/**
|
||||
* Members that have access methods
|
||||
* @var array
|
||||
*/
|
||||
protected static $_properties = array(
|
||||
);
|
||||
|
||||
public function __construct($resource,$base=array()) {
|
||||
$this->_connection = $resource;
|
||||
|
||||
$this->_base = is_null($base) ? $this->base() : $base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles pass-through to database methods. Calls to query methods
|
||||
* (query, get, insert, update) are not allowed. Query builder methods
|
||||
* are chainable.
|
||||
*
|
||||
* @param string $method Method name
|
||||
* @param array $args Method arguments
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($method,array $args) {
|
||||
if (in_array($method,Database_LDAP_Search::$_properties)) {
|
||||
/*
|
||||
// @todo To Implement
|
||||
if ($method === 'validation')
|
||||
{
|
||||
if ( ! isset($this->_validation))
|
||||
{
|
||||
// Initialize the validation object
|
||||
$this->_validation();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Return the property
|
||||
return $this->{'_'.$method};
|
||||
}
|
||||
elseif (in_array($method,Database_LDAP_Search::$_db_methods))
|
||||
{
|
||||
// Add pending database call which is executed after query type is determined
|
||||
$this->_db_pending[] = array('name' => $method,'args' => $args);
|
||||
|
||||
return $this;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Kohana_Exception('Invalid method :method called in :class',
|
||||
array(':method' => $method,':class' => get_class($this)));
|
||||
}
|
||||
}
|
||||
|
||||
private function _build() {
|
||||
$search = new Database_LDAP_Search_Builder_Query();
|
||||
|
||||
// Process pending database method calls
|
||||
foreach ($this->_db_pending as $method) {
|
||||
$name = $method['name'];
|
||||
$args = $method['args'];
|
||||
|
||||
$this->_db_applied[$name] = $name;
|
||||
|
||||
call_user_func_array(array($search,$name),$args);
|
||||
}
|
||||
|
||||
return $search;
|
||||
}
|
||||
|
||||
/**
|
||||
* Figure out the bases
|
||||
*/
|
||||
public function base() {
|
||||
// If the base is set in the configuration file, then just return that.
|
||||
if (! is_null($x=Kohana::$config->load('database.default.connection.database')))
|
||||
return $x;
|
||||
|
||||
$x = Database_LDAP::factory('auth');
|
||||
|
||||
$u = $x->search(array(''))
|
||||
->scope('base')
|
||||
->run();
|
||||
|
||||
// Remove the '' base
|
||||
$u = array_pop($u);
|
||||
$u = array_pop($u);
|
||||
|
||||
return isset($u['namingcontexts']) ? $u['namingcontexts'] : array();
|
||||
}
|
||||
|
||||
public static function instance($resource) {
|
||||
return new Database_LDAP_Search($resource);
|
||||
}
|
||||
|
||||
public function deref($val) {
|
||||
$this->_deref = $val;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the LDAP database
|
||||
*/
|
||||
public function run() {
|
||||
$query = array();
|
||||
|
||||
// Query Defaults
|
||||
$attrs_only = 0;
|
||||
|
||||
// Compile our query
|
||||
if ($this->_db_pending)
|
||||
$this->_filter = $this->_build();
|
||||
|
||||
$result = array();
|
||||
foreach ($this->_base as $base) {
|
||||
switch ($this->_scope) {
|
||||
case 'base':
|
||||
$search = ldap_read($this->_connection,$base,$this->_filter,$this->_attrs,$attrs_only,$this->_size_limit,$this->_time_limit,$this->_deref);
|
||||
break;
|
||||
|
||||
case 'one':
|
||||
$search = ldap_list($this->_connection,$base,$this->_filter,$this->_attrs,$attrs_only,$this->_size_limit,$this->_time_limit,$this->_deref);
|
||||
break;
|
||||
|
||||
case 'sub':
|
||||
default:
|
||||
$search = ldap_search($this->_connection,$base,$this->_filter,$this->_attrs,$attrs_only,$this->_size_limit,$this->_time_limit,$this->_deref);
|
||||
break;
|
||||
}
|
||||
|
||||
if (! $search) {
|
||||
$result[$base] = array();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the first entry identifier
|
||||
if ($entries = ldap_get_entries($this->_connection,$search)) {
|
||||
|
||||
# Remove the count
|
||||
if (isset($entries['count']))
|
||||
unset($entries['count']);
|
||||
|
||||
// Iterate over the entries
|
||||
foreach ($entries as $a => $entry) {
|
||||
if (! isset($entry['dn']))
|
||||
throw HTTP_Exception::factory(501,'No DN?');
|
||||
|
||||
// Remove the none entry references.
|
||||
if (! is_array($entry)) {
|
||||
unset($entries[$a]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$dn = $entry['dn'];
|
||||
unset($entry['dn']);
|
||||
|
||||
// Iterate over the attributes
|
||||
foreach ($entry as $b => $attrs) {
|
||||
// Remove the none entry references.
|
||||
if (! is_array($attrs)) {
|
||||
unset($entry[$b]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove the count
|
||||
if (isset($entry[$b]['count']))
|
||||
unset($entry[$b]['count']);
|
||||
}
|
||||
|
||||
// Our queries always include the DN (the only value not an array).
|
||||
$entry['dn'] = $dn;
|
||||
$result[$base][$dn] = $entry;
|
||||
}
|
||||
}
|
||||
|
||||
// Sort our results
|
||||
if (isset($result[$base]))
|
||||
foreach ($result[$base] as $key => $values)
|
||||
ksort($result[$base][$key]);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function size_limit($val) {
|
||||
$this->_size_limit = $val;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function scope($val) {
|
||||
switch ($val) {
|
||||
case 'base':
|
||||
case 'sub':
|
||||
case 'one': $this->_scope = $val;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Kohana_Exception('Unknown search scope :scope',array(':scope',$val));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function time_limit($val) {
|
||||
$this->_time_limit = $val;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
?>
|
214
classes/Kohana/Database/LDAP/Search/Builder/Query.php
Normal file
214
classes/Kohana/Database/LDAP/Search/Builder/Query.php
Normal file
@ -0,0 +1,214 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
|
||||
/**
|
||||
* This class takes care of building an LDAP filter query
|
||||
*
|
||||
* @package Kohana/LDAP
|
||||
* @subpackage LDAP/Search
|
||||
* @category Helpers
|
||||
* @author Deon George
|
||||
* @copyright (c) phpLDAPadmin Development Team
|
||||
* @license http://dev.phpldapadmin.org/license.html
|
||||
*/
|
||||
abstract class Kohana_Database_LDAP_Search_Builder_Query extends Database_Query_Builder {
|
||||
protected $_where = array();
|
||||
|
||||
// @todo Not implemented
|
||||
public function reset() {}
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct(Database::SELECT,'ldap');
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias of and_where()
|
||||
*
|
||||
* @param mixed column name or array($column, $alias) or object
|
||||
* @param string logic operator
|
||||
* @param mixed column value
|
||||
* @return $this
|
||||
*/
|
||||
public function where($column,$op,$value) {
|
||||
return $this->and_where($column,$op,$value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new "AND WHERE" condition for the query.
|
||||
*
|
||||
* @param mixed column name or array($column,$alias) or object
|
||||
* @param string logic operator
|
||||
* @param mixed column value
|
||||
* @return $this
|
||||
*/
|
||||
public function and_where($column,$op,$value) {
|
||||
$this->_where[] = array('AND' => array($column,$op,$value));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new "OR WHERE" condition for the query.
|
||||
*
|
||||
* @param mixed column name or array($column,$alias) or object
|
||||
* @param string logic operator
|
||||
* @param mixed column value
|
||||
* @return $this
|
||||
*/
|
||||
public function or_where($column,$op,$value) {
|
||||
$this->_where[] = array('OR' => array($column,$op,$value));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias of and_where_open()
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function where_open() {
|
||||
return $this->and_where_open();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a new "AND WHERE (...)" grouping.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function and_where_open() {
|
||||
$this->_where[] = array('AND' => '(');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a new "OR WHERE (...)" grouping.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function or_where_open() {
|
||||
$this->_where[] = array('OR' => '(');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function compile($db = NULL) {
|
||||
$filter = '';
|
||||
|
||||
return $this->_compile_conditions($db,$this->_where);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes an open "AND WHERE (...)" grouping.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function where_close() {
|
||||
return $this->and_where_close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes an open "AND WHERE (...)" grouping.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function and_where_close() {
|
||||
$this->_where[] = array('AND' => ')');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes an open "OR WHERE (...)" grouping.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function or_where_close() {
|
||||
$this->_where[] = array('OR' => ')');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles an array of conditions into an LDAP filter.
|
||||
*
|
||||
* @param object Database instance
|
||||
* @param array condition statements
|
||||
* @return string
|
||||
*/
|
||||
protected function _compile_conditions(Database $db,array $conditions,$index=0) {
|
||||
$current_condition = $last_condition = NULL;
|
||||
|
||||
$filter = '';
|
||||
$sub = 0;
|
||||
foreach ($conditions as $key => $group) {
|
||||
// If we have been called again, we need to skip ahead, or skip what has been processed
|
||||
if ($key < $index OR $sub)
|
||||
continue;
|
||||
|
||||
// Process groups of conditions
|
||||
foreach ($group as $logic => $condition) {
|
||||
if ($condition === '(') {
|
||||
$filter .= $this->_compile_conditions($db,$conditions,$key+1);
|
||||
$sub = 1;
|
||||
|
||||
} elseif ($condition === ')') {
|
||||
if ($index) {
|
||||
// As we return, we'll include our condition
|
||||
switch ($current_condition) {
|
||||
case 'AND':
|
||||
return '(&'.$filter.')';
|
||||
|
||||
case 'OR':
|
||||
return '(|'.$filter.')';
|
||||
|
||||
default:
|
||||
throw new Kohana_Exception('Condition :condition not handled.',array(':condition'=>$condition));
|
||||
}
|
||||
}
|
||||
|
||||
$sub = 0;
|
||||
|
||||
} else {
|
||||
// We currently cant handle when a condition changes, without brackets.
|
||||
if ($filter AND $current_condition AND $current_condition != $logic)
|
||||
throw new Kohana_Exception('Condition changed without brackets');
|
||||
|
||||
$current_condition = $logic;
|
||||
|
||||
// Split the condition
|
||||
list($column,$op,$value) = $condition;
|
||||
|
||||
// Database operators are always uppercase
|
||||
$op = strtoupper($op);
|
||||
|
||||
if ((is_string($value) AND array_key_exists($value,$this->_parameters)) === FALSE) {
|
||||
// Quote the value, it is not a parameter
|
||||
$value = $db->quote($value);
|
||||
}
|
||||
|
||||
if ($column) {
|
||||
// Apply proper quoting to the column
|
||||
$column = $db->quote_column($column);
|
||||
}
|
||||
|
||||
// Append the statement to the query
|
||||
$filter .= trim('('.$column.$op.$value.')');
|
||||
}
|
||||
|
||||
$last_condition = $condition;
|
||||
}
|
||||
}
|
||||
|
||||
switch ($current_condition) {
|
||||
case 'AND':
|
||||
return '(&'.$filter.')';
|
||||
|
||||
case 'OR':
|
||||
return '(|'.$filter.')';
|
||||
|
||||
default:
|
||||
throw new Kohana_Exception('Condition :condition not handled.',array(':condition'=>$condition));
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
43
config/database.php
Normal file
43
config/database.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
|
||||
/**
|
||||
* LDAP Configuration - LDAP Server Definitions
|
||||
*
|
||||
* @package Kohana/LDAP
|
||||
* @category Configuration
|
||||
* @author Deon George
|
||||
* @copyright (c) phpLDAPadmin Development Team
|
||||
* @license http://dev.phpldapadmin.org/license.html
|
||||
*/
|
||||
|
||||
return array (
|
||||
'default' => array (
|
||||
'type' => 'ldap',
|
||||
'connection' => array(
|
||||
/**
|
||||
* The following options are available for MySQL:
|
||||
*
|
||||
* string hostname server hostname, or socket
|
||||
* string database our basedn
|
||||
* string username database username
|
||||
* string password database password
|
||||
* boolean persistent use persistent connections?
|
||||
*
|
||||
* Ports and sockets may be appended to the hostname.
|
||||
*/
|
||||
'hostname' => 'localhost',
|
||||
'database' => NULL,
|
||||
'port' => 389,
|
||||
'username' => FALSE,
|
||||
'password' => FALSE,
|
||||
'persistent' => NULL,
|
||||
),
|
||||
'table_prefix' => NULL,
|
||||
'charset' => 'utf8',
|
||||
'caching' => FALSE,
|
||||
'profiling' => TRUE,
|
||||
|
||||
'login_attr'=>'uid',
|
||||
),
|
||||
);
|
||||
?>
|
105
tests/classes/LDAPConnection.php
Normal file
105
tests/classes/LDAPConnection.php
Normal file
@ -0,0 +1,105 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
|
||||
/**
|
||||
* This should test all our connection methods to the LDAP server
|
||||
* and return success and failures.
|
||||
*
|
||||
* @package Kohana/LDAP
|
||||
* @category Test
|
||||
* @author Deon George
|
||||
* @copyright (c) 2013 phpLDAPadmin Development Team
|
||||
* @license http://dev.phpldapadmin.org/license.html
|
||||
* @group ldap
|
||||
* @group ldap.server
|
||||
*/
|
||||
Class LDAPConnection extends Unittest_TestCase {
|
||||
function hosts() {
|
||||
return array(
|
||||
array('localhost','389','a',TRUE),
|
||||
array('localhost','389','b',TRUE),
|
||||
array('localhost','390','a',FALSE),
|
||||
array('localhost','390','b',FALSE),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that we can connect to an LDAP server
|
||||
* @dataProvider hosts
|
||||
*/
|
||||
function testConnect($host,$port,$instance,$expect) {
|
||||
$connection = array(
|
||||
'type'=>'ldap',
|
||||
'connection'=>array('hostname'=>$host,'port'=>$port),
|
||||
);
|
||||
|
||||
$x = Database_LDAP::factory($instance,NULL,$connection);
|
||||
$x->connect();
|
||||
|
||||
if ($expect)
|
||||
$this->assertAttributeInternalType('resource','_connection',$x);
|
||||
// In OpenLDAP, this still returns a resource, even though it should be a failure.
|
||||
else
|
||||
$this->assertAttributeInternalType('resource','_connection',$x);
|
||||
|
||||
$x->disconnect();
|
||||
}
|
||||
|
||||
function auths() {
|
||||
return array(
|
||||
array('bart','eatmyshorts',TRUE),
|
||||
array('bart','Eatmyshorts',FALSE),
|
||||
array('nobart','Eatmyshorts',FALSE),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider auths
|
||||
* @depends testConnect
|
||||
*/
|
||||
function testAuth($user,$password,$expect) {
|
||||
if ($expect)
|
||||
$this->assertTrue(Auth::instance()->login($user,$password));
|
||||
else
|
||||
$this->assertFalse(Auth::instance()->login($user,$password));
|
||||
|
||||
Auth::instance()->logout();
|
||||
}
|
||||
|
||||
function authconfig() {
|
||||
return array(
|
||||
array('','',TRUE),
|
||||
array('bart','x',FALSE),
|
||||
array('cn=Manager','Eatmyshorts',FALSE),
|
||||
array('cn=Manager,dc=example.com','NotAllowed',TRUE),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider authconfig
|
||||
* @depends testConnect
|
||||
*/
|
||||
function testAuthConfiguration($user,$password,$expect) {
|
||||
$connection = array(
|
||||
'type'=>'ldap',
|
||||
'login_attr'=>'uid',
|
||||
'connection'=>array(
|
||||
'hostname'=>'localhost',
|
||||
'port'=>389,
|
||||
'username'=>$user,
|
||||
'password'=>$password
|
||||
),
|
||||
);
|
||||
|
||||
// Ensure we start with a clean auth connection.
|
||||
Database_LDAP::factory('auth')->disconnect();
|
||||
Database_LDAP::factory('default')->disconnect();
|
||||
|
||||
$x = Database_LDAP::factory('default',NULL,$connection);
|
||||
$x->bind('bart','eatmyshorts');
|
||||
|
||||
if ($expect)
|
||||
$this->assertTrue($x->connected());
|
||||
else
|
||||
$this->assertFalse($x->connected());
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user