Enabled LDAP ORM operation

This commit is contained in:
Deon George 2013-08-16 12:21:17 +10:00
parent 2997f6ada0
commit 83fcf55501
14 changed files with 655 additions and 152 deletions

View File

@ -0,0 +1,4 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
class Database_LDAP_Search_Result extends Kohana_Database_LDAP_Search_Result {}
?>

View File

@ -9,7 +9,7 @@
* @copyright (c) 2013 phpLDAPadmin Development Team
* @license http://dev.phpldapadmin.org/license.html
*/
class Kohana_Auth_LDAP extends Auth {
abstract class Kohana_Auth_LDAP extends Auth {
// Unnused required abstract functions
public function password($username) {}
public function check_password($password) {}

View File

@ -21,10 +21,6 @@ abstract class Kohana_Database_LDAP extends Kohana_LDAP {
* @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_columns($table, $like = NULL, $add_prefix = TRUE) { throw HTTP_Exception::factory(501,'We shouldnt be here: :method',array(':method'=>__METHOD__)); }
/**
* @defunct This required abstruct function is defunct for LDAP
*/
@ -45,6 +41,13 @@ abstract class Kohana_Database_LDAP extends Kohana_LDAP {
/** 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(),'objectclass'=>array());
}
/**
* @override We override this parent function, since LDAP doesnt quote columns
*/
@ -166,7 +169,7 @@ abstract class Kohana_Database_LDAP extends Kohana_LDAP {
$u = $x->search(NULL)
->scope('sub')
->where($this->_config['login_attr'],'=',$user)
->run();
->execute();
if (! $u)
return FALSE;
@ -178,8 +181,7 @@ abstract class Kohana_Database_LDAP extends Kohana_LDAP {
die();
}
foreach ($u as $base => $entries)
foreach ($entries as $dn => $details)
foreach ($u as $dn => $leaf)
if ($this->_bind($dn,$pass))
return $this;

View File

@ -1,4 +1,5 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* LDAP database result. See [Results](/database/results) for usage and examples.
*
@ -8,9 +9,137 @@
* @copyright (c) 2013 phpLDAPadmin Development Team
* @license http://dev.phpldapadmin.org/license.html
*/
class Kohana_Database_LDAP_Result extends Database_Result {
abstract class Kohana_Database_LDAP_Result extends Database_Result {
private $_current_entry = NULL;
/** SeekableIterator **/
/**
* Implements [Iterator::current], returns the current LDAP Leaf Entry.
*
* @return mixed LDAP leaf array of values
*/
public function current() {
if (! $this->_current_entry)
return array();
if ($this->_as_object === TRUE) {
// Return an stdClass
throw HTTP_Exception::factory(501,'Not implemented');
} elseif (is_string($this->_as_object)) {
// Return an object of given class name
throw HTTP_Exception::factory(501,'Not implemented');
} else {
// Return an array of the row
// @todo We could probably cache this for optimisation
$attrs = $vals = array();
array_push($attrs,ldap_first_attribute($this->_result['l'],$this->_current_entry));
while ($x = ldap_next_attribute($this->_result['l'],$this->_current_entry))
array_push($attrs,$x);
foreach ($attrs as $attr) {
$vals[strtolower($attr)] = ldap_get_values($this->_result['l'],$this->_current_entry,$attr);
// We dont need the count entry
unset($vals[strtolower($attr)]['count']);
}
$vals['dn'] = $this->key();
return $vals;
}
}
/**
* Implements [Iterator::key], returns the dn.
*
* echo key($result);
*
* @return string LDAP Distringuised Name
*/
public function key() {
return ldap_get_dn($this->_result['l'],$this->_current_entry);
}
/**
* Implements [Iterator::next], moves to the next row.
*
* next($result);
*
* @return $this
*/
public function next() {
$this->_current_entry = ldap_next_entry($this->_result['l'],$this->_current_entry);
++$this->_current_row;
return $this;
}
/**
* @override We cant go backwards!
*/
public function prev() {
throw new Kohana_Exception('Cant go backwards');
}
/**
* Implements [Iterator::rewind], moves to the first entry.
*
* reset($result);
*
* @return void
*/
public function rewind() {
if ($this->_total_rows)
$this->_current_entry = ldap_first_entry($this->_result['l'],$this->_result['r']);
$this->_current_row = 0;
}
/**
* Implements [SeekableIterator::seek], to seek to an entry.
*
* [!!] This method is only used internally.
*
* @return boolean
*/
public function seek($dn) {
$this->_current_entry = ldap_first_entry($this->_result['l'],$this->_result['r']);
do {
if ($dn == $this->key())
return TRUE;
// Increment internal row for optimization assuming rows are fetched in order
$this->_current_entry = ldap_next_entry($this->_result['l'],$this->_current_entry);
} while ($this->_current_entry);
// We didnt find it
return FALSE;
}
/**
* Implements [Iterator::valid], checks if the current row exists.
*
* [!!] This method is only used internally.
*
* @return boolean
*/
public function valid() {
return (boolean)$this->_current_entry;
}
/** ArrayAccess **/
public function offsetExists($offset) {
return $this->valid();
}
/** Custom Methods **/
public function __construct($result, $sql, $as_object = FALSE, array $params = NULL) {
parent::__construct($result, $sql, $as_object, $params);
@ -53,104 +182,5 @@ class Kohana_Database_LDAP_Result extends Database_Result {
return $result;
}
public function current() {
if (! $this->_current_entry)
return array();
if ($this->_as_object === TRUE) {
// Return an stdClass
throw HTTP_Exception::factory(501,'Not implemented');
} elseif (is_string($this->_as_object)) {
// Return an object of given class name
throw HTTP_Exception::factory(501,'Not implemented');
} else {
// Return an array of the row
// @todo We could probably cache this for optimisation
$attrs = $vals = array();
array_push($attrs,ldap_first_attribute($this->_result['l'],$this->_current_entry));
while ($x = ldap_next_attribute($this->_result['l'],$this->_current_entry))
array_push($attrs,$x);
foreach ($attrs as $attr) {
$vals[strtolower($attr)] = ldap_get_values($this->_result['l'],$this->_current_entry,$attr);
// We dont need the count entry
unset($vals[strtolower($attr)]['count']);
}
return $vals;
}
}
/**
* Implements [Iterator::key], returns the dn.
*
* echo key($result);
*
* @return integer
*/
public function key() {
return ldap_get_dn($this->_result['l'],$this->_current_entry);
}
/**
* Implements [Iterator::next], moves to the next row.
*
* next($result);
*
* @return $this
*/
public function next() {
$this->_current_entry = ldap_next_entry($this->_result['l'],$this->_current_entry);
++$this->_current_row;
return $this;
}
public function offsetExists($offset) {
return $this->valid();
}
public function prev() {
throw new Kohana_Exception('Cant go backwards');
}
public function seek($dn) {
$this->_current_entry = ldap_first_entry($this->_result['l'],$this->_result['r']);
do {
if ($dn == $this->key())
return TRUE;
// Increment internal row for optimization assuming rows are fetched in order
$this->_current_entry = ldap_next_entry($this->_result['l'],$this->_current_entry);
} while ($this->_current_entry);
// We didnt find it
return FALSE;
}
public function rewind() {
if ($this->_total_rows)
$this->_current_entry = ldap_first_entry($this->_result['l'],$this->_result['r']);
$this->_current_row = 0;
}
/**
* Implements [Iterator::valid], checks if the current row exists.
*
* [!!] This method is only used internally.
*
* @return boolean
*/
public function valid() {
return (boolean)$this->_current_entry;
}
} // End Database_LDAP_Result
?>

View File

@ -1,4 +1,5 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Object used for caching the results of select queries. See [Results](/database/results#select-cached) for usage and examples.
*
@ -8,7 +9,7 @@
* @copyright (c) 2013 phpLDAPadmin Development Team
* @license http://dev.phpldapadmin.org/license.html
*/
class Kohana_Database_LDAP_Result_Cached extends Database_Result_Cached {
abstract class Kohana_Database_LDAP_Result_Cached extends Database_Result_Cached {
public function __construct(array $result, $sql, $as_object = NULL)
{
@ -65,5 +66,5 @@ class Kohana_Database_LDAP_Result_Cached extends Database_Result_Cached {
return FALSE;
}
}
} // End Database_LDAP_Result_Cached
?>

View File

@ -27,6 +27,9 @@ abstract class Kohana_Database_LDAP_Search {
// Cache lifetime
protected $_lifetime = NULL;
// Parameters for __construct when using object results
protected $_object_params = array();
/**
* Callable database methods
* @var array
@ -34,6 +37,14 @@ abstract class Kohana_Database_LDAP_Search {
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',
'limit',
);
/**
* ORM methods that are called, but dont do anything in LDAP
*/
protected static $_orm_ignore_methods = array(
'from',
);
/**
@ -74,18 +85,19 @@ abstract class Kohana_Database_LDAP_Search {
// Return the property
return $this->{'_'.$method};
}
elseif (in_array($method,Database_LDAP_Search::$_db_methods))
{
} 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)));
} elseif (in_array($method,Database_LDAP_Search::$_orm_ignore_methods)) {
return $this;
} else {
throw new Kohana_Exception('Invalid method :method called in :class (:args)',
array(':method' => $method,':class' => get_class($this),':args'=>print_r($args,TRUE)));
}
}
@ -99,16 +111,37 @@ abstract class Kohana_Database_LDAP_Search {
$this->_db_applied[$name] = $name;
switch ($name) {
case 'limit':
$this->_size_limit = $args[0];
break;
default:
call_user_func_array(array($search,$name),$args);
}
}
return $search;
}
public function as_assoc() {
$this->_as_object = FALSE;
$this->_object_params = array();
return $this;
}
/**
* Figure out the bases
*/
public function base() {
public function base(array $base=NULL) {
if (! is_null($base))
$this->_base = $base;
if ($this->_base)
return $this->_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;
@ -117,16 +150,13 @@ abstract class Kohana_Database_LDAP_Search {
$u = $x->search(array(''))
->scope('base')
->run();
// Remove the '' base
$u = array_pop($u);
->execute();
// Quick validation
if ($u->count() > 1)
if ($u['']->count() > 1)
throw HTTP_Exception::factory(501,'We got more than 1 null DN?');
return isset($u['']['namingcontexts']) ? $u['']['namingcontexts'] : array();
return isset($u['']['']['namingcontexts']) ? $u['']['']['namingcontexts'] : array();
}
/**
@ -158,9 +188,22 @@ abstract class Kohana_Database_LDAP_Search {
/**
* Search the LDAP database
*/
public function run($as_object=FALSE,$object_params=NULL) {
public function execute($db=NULL,$as_object=FALSE,$object_params=NULL) {
$query = array();
if (! is_object($this->_db))
throw new Kohana_Exception('db must be an object');
// We'll override the DB if we have been given one
if (is_object($db))
$this->_db = $db;
if ($as_object === NULL)
$as_object = $this->_as_object;
if ($object_params === NULL)
$object_params = $this->_object_params;
// Query Defaults
$attrs_only = 0;
@ -168,10 +211,12 @@ abstract class Kohana_Database_LDAP_Search {
if ($this->_db_pending)
$this->_filter = $this->_build();
$result = array();
foreach ($this->_base as $base) {
$result[$base] = NULL;
// Validation that we are connected, no point contining if we are not.
if (! $this->_db->connection())
throw HTTP_Exception::factory(501,'Cant run a search without a connection (:type,:filter)',array(':type'=>$this->_db,':filter'=>$this->_filter));
$result = new Database_LDAP_Search_Result;
foreach ($this->_base as $base) {
if ($this->_lifetime !== NULL AND $this->_db->caching()) {
// Set the cache key based on the database instance name and SQL
$cache_key = 'Database::query("'.$this->_db.'","'.$base.'","'.$this->_scope.'","'.$this->_filter.'")';
@ -184,7 +229,8 @@ abstract class Kohana_Database_LDAP_Search {
}
// Search is not cached, OR caching is disabled, so we'll query
if (! $result[$base]) {
if (! isset($result[$base])) {
try {
switch ($this->_scope) {
case 'base':
$search = ldap_read($this->_db->connection(),$base,$this->_filter,$this->_attrs,$attrs_only,$this->_size_limit,$this->_time_limit,$this->_deref);
@ -200,6 +246,11 @@ abstract class Kohana_Database_LDAP_Search {
break;
}
} catch (Exception $e) {
throw HTTP_Exception::factory(501,'Error running a query (SCOPE::scope,TYPE::type,FILTER::filter,ATTRS::attrs) [:error]',
array(':scope'=>$this->_scope,':type'=>$this->_db,':filter'=>$this->_filter,':attrs'=>join('|',$this->_attrs),':error'=>$e->getMessage()));
}
$result[$base] = new Database_LDAP_Result(array('l'=>$this->_db->connection(),'r'=>$search),array('b'=>$base,'s'=>$this->_scope,'f'=>$this->_filter),$as_object,$object_params);
// Cache the result array

View File

@ -10,8 +10,12 @@
* @license http://dev.phpldapadmin.org/license.html
*/
abstract class Kohana_Database_LDAP_Search_Builder_Query extends Database_Query_Builder {
// WHERE ...
protected $_where = array();
// LIMIT ...
protected $_limit = NULL;
/**
* @defunct Not implemented
*/
@ -207,9 +211,23 @@ abstract class Kohana_Database_LDAP_Search_Builder_Query extends Database_Query_
case 'OR':
return '(|'.$filter.')';
case '':
return '(&(objectClass=*))';
default:
throw new Kohana_Exception('Condition :condition not handled.',array(':condition'=>$condition));
throw new Kohana_Exception('Condition ":condition" not handled.',array(':condition'=>$current_condition));
}
}
/**
* Return up to "LIMIT ..." results
*
* @param integer $number maximum results to return or NULL to reset
* @return $this
*/
public function limit($number) {
$this->_limit = $number;
return $this;
}
}
?>

View File

@ -0,0 +1,90 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Return the query search result.
*
* @package Kohana/LDAP
* @category Query
* @author Deon George
* @copyright (c) 2013 phpLDAPadmin Development Team
* @license http://dev.phpldapadmin.org/license.html
*/
abstract class Kohana_Database_LDAP_Search_Result implements ArrayAccess,Iterator,Countable {
private $_count = 0;
protected $result = array();
private $_rewound = FALSE;
private $_current_key = NULL;
/** Countable **/
public function count() {
$c = 0;
foreach ($this->result as $k=>$v)
$c += count($v);
return $c;
}
/** ArrayAccess **/
public function offsetExists($offset) {
return isset($this->result[$offset]);
}
public function offsetGet($offset) {
return $this->result[$offset];
}
public function offsetSet($offset,$value) {
if (isset($this->result[$offset]))
$this->_count -= $this->result[$offset]->count();
$this->result[$offset] = $value;
$this->_count += $value->count();
}
public function offsetUnset($offset) {
unset($this->result[$offset]);
}
/** Iterator **/
public function current() {
if (! $this->_rewound)
$this->rewind();
return current($this->result)->current();
}
public function key() {
return current($this->result)->key();
}
public function next() {
if (current($this->result)->valid() AND current($this->result)->next()->valid())
return current($this->result);
next($this->result);
while (current($this->result) AND ! current($this->result)->valid())
if (next($this->result) === FALSE)
break;
return current($this->result);
}
public function rewind() {
reset($this->result);
if (! current($this->result)->valid())
$this->next(FALSE);
$this->_rewound = TRUE;
}
public function valid() {
return is_object(current($this->result)) ? current($this->result)->valid() : FALSE;
}
} // End Database_LDAP_Search_Result
?>

View File

@ -0,0 +1,93 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* Kohana ORM LDAP Extension
*
* @package LDAP/ORM
* @category Helpers
* @author Deon George
* @copyright (c) 2013 phpLDAPadmin Development Team
* @license http://dev.phpldapadmin.org/license.html
*/
abstract class Kohana_ORM_LDAP extends ORM {
protected $_disable_wild_select = TRUE;
protected $_disable_join_table_name = TRUE;
protected $_primary_key = 'dn';
public function __construct($id = NULL) {
// We'll process our $id
parent::__construct(NULL);
if (empty($this->_cast_data) AND $id) {
if (is_array($id)) {
// Passing an array of column => values
foreach ($id as $column => $value)
$this->where($column, '=', $value);
$this->find();
} else {
// Passing the primary key
$this->base($id)->find();
}
}
}
/**
* Initializes the Database Builder to given query type
*
* @param integer $type Type of Database query
* @return ORM
*/
protected function _build($type) {
// Construct new builder object based on query type
switch ($type) {
case Database::SELECT:
$this->_db_builder = new Database_LDAP_Search($this->_db,NULL);
break;
default:
throw HTTP_Exception::factory(501,'Unknown type :type',array(':type'=>$type));
}
// 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($this->_db_builder, $name), $args);
}
return $this;
}
protected function _initialize() {
parent::_initialize();
// Check if this model has already been initialized
if ($init = Arr::get(ORM::$_init_cache, $this->_object_name, FALSE)) {
// We need to make sure that our _db is an LDAP DB source.
if ( ! is_object($this->_db) OR ! $this->_db instanceof LDAP) {
// Get database instance
$init['_db'] = LDAP::factory('user',NULL,$this->_db_group);
}
ORM::$_init_cache[$this->_object_name] = $init;
$this->_db = $init['_db'];
}
}
public function base($value) {
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'base',
'args' => array(array($value)),
);
return $this;
}
}
?>

14
classes/Model/LDAP.php Normal file
View File

@ -0,0 +1,14 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class provides our ORM interaction with LDAP
*
* @package Kohana/LDAP
* @category Model/LDAP
* @author Deon George
* @copyright (c) 2013 phpLDAPadmin Development Team
* @license http://dev.phpldapadmin.org/license.html
*/
class Model_LDAP extends ORM_LDAP {
}
?>

4
classes/ORM/LDAP.php Normal file
View File

@ -0,0 +1,4 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
abstract class ORM_LDAP extends Kohana_ORM_LDAP {}
?>

View File

@ -41,12 +41,12 @@ Class LDAPCaching extends Unittest_TestCase {
$u = $x->search(array(''))
->scope('base')
->cached($cached,$force)
->run();
->execute();
$u = $x->search(array(''))
->scope('base')
->cached($cached,$force)
->run();
->execute();
if ($expect)
$this->assertInstanceOf('Database_LDAP_Result',$u['']);

View File

@ -0,0 +1,141 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This will test our LDAPResult array is working as expected
*
* @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 LDAPResult extends Unittest_TestCase {
function testDatabase_LDAP_Result_One() {
$x = LDAP::factory('user');
$x->connect();
// We'll do a query first.
$u = $x->search(array(''))
->scope('base')
->execute();
$this->assertEquals(1,$u->count());
foreach ($u[''] as $k => $v) {
$this->assertEquals('',$k);
$this->assertTrue(is_array($v));
}
$x->disconnect();
}
function testDatabase_LDAP_Result_Many() {
$x = LDAP::factory('user');
$x->connect();
$y = LDAP::factory('auth');
$y->connect();
// We'll do a query first.
$u = $x->search(NULL)
->scope('sub')
->where('uid','=','bart*')
->execute();
foreach ($u['dc=example.com'] as $k => $v) {
$this->assertEquals('cn=Bart Simpson,dc=example.com',$k);
$this->assertTrue(is_array($v));
}
$this->assertEquals(2,count($u['o=Simpsons']));
$this->assertEquals(count($u['o=Simpsons']),$u['o=Simpsons']->count());
$c = 0;
foreach ($u['o=Simpsons'] as $k => $v) {
if (! $c++)
$this->assertEquals('cn=Bart Simpson,ou=People,o=Simpsons',$k);
else
$this->assertEquals('cn=Bart Simpson-ML,ou=People,o=Simpsons',$k);
$this->assertTrue(is_array($v));
}
$x->disconnect();
}
function testDatabase_LDAP_Search_Result_One() {
$x = LDAP::factory('user');
$x->connect();
// We'll do a query first.
$u = $x->search(array(''))
->scope('base')
->execute();
$this->assertEquals(1,$u->count());
foreach ($u as $k => $v) {
$this->assertEquals('',$k);
$this->assertTrue(is_array($v));
}
$x->disconnect();
}
function testDatabase_LDAP_Search_Result_Many() {
$x = LDAP::factory('user');
$x->connect();
$y = LDAP::factory('auth');
$y->connect();
// We'll do a query first.
$u = $x->search(NULL)
->scope('sub')
->where('uid','=','bart*')
->execute();
$this->assertEquals(3,count($u));
$c = 0;
foreach ($u as $k => $v) {
switch (++$c) {
case 1: $this->assertEquals('cn=Bart Simpson,dc=example.com',$k); break;
case 2: $this->assertEquals('cn=Bart Simpson,ou=People,o=Simpsons',$k); break;
case 3: $this->assertEquals('cn=Bart Simpson-ML,ou=People,o=Simpsons',$k); break;
default: throw new Kohana_Exception('Unknown value of c? (:c)',array(':c'=>serialize($c)));
}
$this->assertTrue(is_array($v));
}
$x->disconnect();
}
function testDatabase_LDAP_Search_Result_OneDeep() {
$x = LDAP::factory('user');
$x->connect();
$y = LDAP::factory('auth');
$y->connect();
// We'll do a query first.
$u = $x->search(NULL)
->scope('sub')
->where('uid','=','bart-ml')
->execute();
$this->assertEquals(1,count($u));
$c = 0;
foreach ($u as $k => $v) {
switch (++$c) {
case 1: $this->assertEquals('cn=Bart Simpson-ML,ou=People,o=Simpsons',$k); break;
default: throw new Kohana_Exception('Unknown value of c? (:c)',array(':c'=>serialize($c)));
}
$this->assertTrue(is_array($v));
}
$x->disconnect();
}
}

55
tests/classes/LDAPorm.php Normal file
View File

@ -0,0 +1,55 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This should test all our ORM methods
*
* @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 LDAPorm 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
*/
function testorm() {
$x = ORM::factory('LDAP',NULL);
$this->assertInstanceOf('ORM',$x);
}
function testormloaddn() {
// @todo It would be nice if we auto connect as required.
$y = LDAP::factory('auth');
$y->connect();
$y = LDAP::factory('user');
$y->connect();
$x = ORM::factory('LDAP','cn=Bart Simpson,ou=People,o=Simpsons');
$this->assertInstanceOf('ORM',$x);
}
function testormdnval() {
// @todo It would be nice if we auto connect as required.
$y = LDAP::factory('auth');
$y->connect();
$y = LDAP::factory('user');
$y->connect();
$x = ORM::factory('LDAP','cn=Bart Simpson,ou=People,o=Simpsons');
$this->assertEquals($x->cn['0'],'Bart Simpson');
}
}