diff --git a/app/Classes/LDAP/Server.php b/app/Classes/LDAP/Server.php index 5ae023d..206405f 100644 --- a/app/Classes/LDAP/Server.php +++ b/app/Classes/LDAP/Server.php @@ -2,33 +2,32 @@ namespace App\Classes\LDAP; -use App\Ldap\Entry; +use Exception; use Illuminate\Support\Arr; -use Illuminate\Support\Collection; use Illuminate\Support\Facades\Cache; +use LdapRecord\Models\Model; +use LdapRecord\Query\Collection; +use LdapRecord\Query\Model\Builder; + +use App\Ldap\Entry; + class Server { /** - * Query the server for a DN + * Query the server for a DN and return it's children and if those children have children. * * @param string $dn - * @return array|\LdapRecord\Query\Collection|null + * @return array|Collection|null */ - public function children(string $dn) + public function children(string $dn): ?Collection { - try { - return ($x=(new Entry) - ->query() - ->select(['dn','hassubordinates']) - ->setDn($dn) - ->listing() - ->get()) ? $x : NULL; - - // @todo Tidy up this exception - } catch (\Exception $e) { - dd(['e'=>$e]); - } + return ($x=(new Entry) + ->query() + ->select(['*','hassubordinates']) + ->setDn($dn) + ->listing() + ->get()) ? $x : NULL; } /** @@ -36,66 +35,14 @@ class Server * * @param string $dn * @param array $attrs - * @return array|\LdapRecord\Models\Model|\LdapRecord\Query\Collection|\LdapRecord\Query\Model\Builder|null + * @return array|Model|Collection|Builder|null */ - public function fetch(string $dn,array $attrs=['*','+']) + public function fetch(string $dn,array $attrs=['*','+']): ?Entry { - try { - return ($x=(new Entry) - ->query() - ->select($attrs) - ->find($dn)) ? $x : NULL; - - // @todo Tidy up this exception - } catch (\Exception $e) { - dd(['e'=>$e]); - } - } - - /** - * Gets the root DN of the specified LDAPServer, or NULL if it - * can't find it (ie, the server won't give it to us, or it isnt - * specified in the configuration file). - * - * @return Collection|null array|NULL The root DN(s) of the server on success (string) or NULL if it cannot be determine. - * @todo Sort the entries, so that they are in the correct DN order. - * @testedby GetBaseDNTest::testBaseDNExists() - */ - public function getBaseDN(): ?Collection - { - //findBaseDn()? - // If the base is set in the configuration file, then just return that after validating it exists. - // @todo - if (false) { - - // We need to work out the baseDN - } else { - $result = $this->getDNAttrValues('',['namingcontexts']); - - return $result ? collect($result->namingcontexts) : NULL; - } - } - - /** - * Search for a DN and return its attributes - * - * @param $dn - * @param array $attrs - * @param int $deref // @todo - * @return Entry|bool - */ - protected function getDNAttrValues(string $dn,array $attrs=['*','+'],int $deref=LDAP_DEREF_NEVER): ?Entry - { - try { - return ($x=(new Entry) - ->query() - ->select($attrs) - ->find($dn)) ? $x : NULL; - - // @todo Tidy up this exception - } catch (\Exception $e) { - dd(['e'=>$e]); - } + return ($x=(new Entry) + ->query() + ->select($attrs) + ->find($dn)) ? $x : NULL; } /** @@ -119,11 +66,10 @@ class Server public static function getOID(string $oid,string $key): ?string { $oids = Cache::remember('oids',86400,function() { - try { $f = fopen(config_path('ldap_supported_oids.txt'),'r'); - } catch (\Exception $e) { + } catch (Exception $e) { return NULL; } @@ -154,4 +100,37 @@ class Server ($key == 'desc' ? 'No description available, can you help with one?' : ($key == 'title' ? $oid : NULL)) ); } + + public static function icon(Entry $dn): string + { + $objectclasses = array_map('strtolower',$dn->objectclass); + + // Return icon based upon objectClass value + if (in_array('person',$objectclasses) || + in_array('organizationalperson',$objectclasses) || + in_array('inetorgperson',$objectclasses) || + in_array('account',$objectclasses) || + in_array('posixaccount',$objectclasses)) + + return 'fas fa-user'; + + elseif (in_array('organization',$objectclasses)) + return 'fas fa-university'; + + elseif (in_array('organizationalunit',$objectclasses)) + return 'fas fa-object-group'; + + elseif (in_array('dcobject',$objectclasses) || + in_array('domainrelatedobject',$objectclasses) || + in_array('domain',$objectclasses) || + in_array('builtindomain',$objectclasses)) + + return 'fas fa-network-wired'; + + elseif (in_array('country',$objectclasses)) + return sprintf('flag %s',strtolower(Arr::get($dn->c,0))); + + // Default + return 'fa-fw fas fa-cog'; + } } diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index 5fc2007..40cf490 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -11,16 +11,20 @@ use Illuminate\Support\Facades\File; use App\Ldap\Entry; use App\Classes\LDAP\Server; +use LdapRecord\Models\ModelNotFoundException; class HomeController extends Controller { public function home() { - $o = new Server; + $base = (new Entry)->baseDN(); + + if (! $base) + $base = collect(); return view('home') ->with('server',config('ldap.connections.default.name')) - ->with('bases',$o->getBaseDN()->transform(function($item) { + ->with('bases',$base->transform(function($item) { return [ 'title'=>$item, 'item'=>Crypt::encryptString($item), @@ -33,22 +37,28 @@ class HomeController extends Controller public function info() { - $attrs = collect((new Entry)->rootDSE()->getAttributes()) - ->transform(function($item,$key) { - foreach ($item as $k=>$v) { - if (preg_match('/[0-9]+\.[0-9]+\.[0-9]+/',$v)) { - $format = sprintf( - '%s%s

%s

', - $v, - Server::getOID($v,'title'), - ($x=Server::getOID($v,'ref')) ? sprintf('',$x) : '', - Server::getOID($v,'desc'), + try { + $attrs = collect((new Entry)->rootDSE()->getAttributes()) + ->transform(function($item,$key) { + foreach ($item as $k=>$v) { + if (preg_match('/[0-9]+\.[0-9]+\.[0-9]+/',$v)) { + $format = sprintf( + '%s%s

%s

', + $v, + Server::getOID($v,'title'), + ($x=Server::getOID($v,'ref')) ? sprintf('',$x) : '', + Server::getOID($v,'desc'), ); - $item[$k] = $format; + $item[$k] = $format; + } } - } - return $item; - }); + return $item; + }); + + // @todo If we cant get server info, we should probably show a nice error dialog + } catch (ModelNotFoundException $e) { + $attrs = collect(); + } return view('widgets.dn') ->with('dn',__('Server Info')) @@ -62,7 +72,7 @@ class HomeController extends Controller return view('widgets.dn') ->with('dn',$dn) ->with('leaf',$x=(new Server())->fetch($dn)) - ->with('attributes',$this->sortAttrs(collect($x->getAttributes()))); + ->with('attributes',$x ? $this->sortAttrs(collect($x->getAttributes())) : []); } /** diff --git a/app/Ldap/Entry.php b/app/Ldap/Entry.php index 25a6c34..d5a1eeb 100644 --- a/app/Ldap/Entry.php +++ b/app/Ldap/Entry.php @@ -2,7 +2,10 @@ namespace App\Ldap; +use Illuminate\Support\Collection; use LdapRecord\Models\Model; +use LdapRecord\Models\ModelNotFoundException; +use LdapRecord\Query\Model\Builder; class Entry extends Model { @@ -13,10 +16,39 @@ class Entry extends Model */ public static $objectClasses = []; - public function rootDSE($connection = null) + /** + * Gets the root DN of the specified LDAPServer, or throws an exception if it + * can't find it. + * + * @param null $connection + * @return Collection + * @throws ModelNotFoundException + * @testedin GetBaseDNTest::testBaseDNExists(); + */ + public function baseDN($connection = NULL): ?Collection + { + $base = static::on($connection ?? (new static)->getConnectionName()) + ->in(NULL) + ->read() + ->select(['namingcontexts']) + ->whereHas('objectclass') + ->firstOrFail(); + + return $base->namingcontexts ? collect($base->namingcontexts) : NULL; + } + + /** + * Obtain the rootDSE for the server, that gives us server information + * + * @param null $connection + * @return Entry|null + * @throws ModelNotFoundException + * @testedin TranslateOidTest::testRootDSE(); + */ + public function rootDSE($connection = NULL): ?Entry { return static::on($connection ?? (new static)->getConnectionName()) - ->in(null) + ->in(NULL) ->read() ->select(['+']) ->whereHas('objectclass') diff --git a/tests/Unit/GetBaseDNTest.php b/tests/Unit/GetBaseDNTest.php index 0e20c7a..98eb41d 100644 --- a/tests/Unit/GetBaseDNTest.php +++ b/tests/Unit/GetBaseDNTest.php @@ -7,7 +7,7 @@ use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Foundation\Testing\RefreshDatabase; use Tests\TestCase; -use App\Classes\LDAP\Server; +use App\Ldap\Entry; class GetBaseDNTest extends TestCase { @@ -15,14 +15,15 @@ class GetBaseDNTest extends TestCase * Test that we can get the Base DN of an LDAP server * * @return void + * @throws \LdapRecord\Models\ModelNotFoundException + * @covers \App\Ldap\Entry::baseDN() */ public function testBaseDNExists() { - $o = new Server(); - $x = $o->getBaseDN(); + $o = (new Entry)->baseDN(); - $this->assertIsObject($x); - $this->assertCount(1,$x->toArray()); - $this->assertContains('dc=Test',$x->toArray()); + $this->assertIsObject($o); + $this->assertCount(1,$o->toArray()); + $this->assertContains('dc=Test',$o->toArray()); } } diff --git a/tests/Unit/TranslateOidTest.php b/tests/Unit/TranslateOidTest.php index 13349de..b005973 100644 --- a/tests/Unit/TranslateOidTest.php +++ b/tests/Unit/TranslateOidTest.php @@ -15,7 +15,8 @@ class TranslateOidTest extends TestCase * A basic feature test example. * * @return void - * @covers Server::getOID() + * @throws \LdapRecord\Models\ModelNotFoundException + * @covers \App\Classes\LDAP\Server::getOID() */ public function testRootDSE() {