diff --git a/src/Adapter/Ldap.php b/src/Adapter/Ldap.php index e53e664..f9c50f6 100644 --- a/src/Adapter/Ldap.php +++ b/src/Adapter/Ldap.php @@ -2,7 +2,7 @@ namespace Ulmus\Ldap\Adapter; -use Ulmus\{ Common\PdoObject, Exception\AdapterConfigurationException }; +use Ulmus\{Common\PdoObject, Exception\AdapterConfigurationException, Ldap\Entity\User}; use Ulmus\Ldap\Common\LdapObject; @@ -64,13 +64,11 @@ class Ldap implements \Ulmus\Adapter\AdapterInterface { } } - public function authenticate(string $username, string $password) : bool + public function authenticate(string $dn, string $password) : bool { $this->ldapObject = $this->getLdapObject(); - $bind = $this->ldapObject->bind($username, $password); - - return $bind; + return $this->ldapObject->bind($dn, $password);; } public function connect() : object diff --git a/src/Common/LdapObject.php b/src/Common/LdapObject.php index 2e63b15..ebf2294 100644 --- a/src/Common/LdapObject.php +++ b/src/Common/LdapObject.php @@ -52,7 +52,9 @@ class LdapObject { throw new \Exception("LdapObject is already binded with a user. Use the unbind() method to release it."); } - return $this->binded = ldap_bind($this->connection, $dn, $password); + $this->binded = ldap_bind($this->connection, $dn, $password); + + return $this->binded; } public function unbind() : void @@ -69,6 +71,11 @@ class LdapObject { return $this->bind($dn, $password); } + public function compare(? string $dn, string $attribute, /* mixed */ $value) /*: bool|int*/ + { + return ldap_compare($this->connection, $dn, $attribute, $value); + } + public function select(array $filter, array $fields = []) { static::$dump && call_user_func_array(static::$dump, [ $filter, $fields ]); @@ -108,8 +115,7 @@ class LdapObject { if ( $attributes = ldap_get_attributes($this->connection, $result) ) { for ($i = 0; $i < $attributes['count']; $i++) { $key = $attributes[$i]; - - $dataset[$key] = $attributes[$key][0]; + $dataset[$key] = $attributes[$key]['count'] > 1 ? array_diff_key($attributes[$key], [ 'count' => "" ]) : $attributes[$key][0]; } } @@ -142,6 +148,29 @@ class LdapObject { return $this; } + public function runInsertQuery(array $filter, array $dataset) + { + return $this->runQuery($filter, $dataset); + } + + public function runUpdateQuery(array $filter, array $dataset) + { + return $this->runQuery($filter, $dataset); + } + + public function runDeleteQuery(array $filter, array $dataset) + { + static::$dump && call_user_func_array(static::$dump, [ $filter, $dataset ]); + + if ( false === ( $queryResult = ldap_mod_del($this->connection, $filter['dn'], $dataset) ) ) { + $this->throwLdapException(); + } + + $this->rowCount = 1; + + return $this; + } + protected function throwLdapException() : void { throw new \Exception(sprintf('LDAP error #%s `%s`', ldap_errno($this->connection), ldap_error($this->connection))); diff --git a/src/Entity/Field/Datetime.php b/src/Entity/Field/Datetime.php index 8bf4e8f..81e421f 100644 --- a/src/Entity/Field/Datetime.php +++ b/src/Entity/Field/Datetime.php @@ -8,5 +8,4 @@ class Datetime extends \Ulmus\Entity\Field\Datetime { { return new static(substr($arguments[0], 0, 8)); } - } diff --git a/src/Entity/Field/LdapDatetime.php b/src/Entity/Field/LdapDatetime.php new file mode 100644 index 0000000..7f4ff25 --- /dev/null +++ b/src/Entity/Field/LdapDatetime.php @@ -0,0 +1,41 @@ +modify(round($time * $resolution ).' Seconds') + ->setTimeZone(new \DateTimeZone($timeZone)) + ->format('Y-m-d H:i:s') + ); + } + + public function save() + { + return (string) $this->getSystemTime(); + } + + public function getSystemTime($basis = '1601-01-01 00:00:00', $resolution = 1.E7, $timeZone = 'UTC') : int + { + $interval = (new \DateTime('1970-01-01 00:00:00 UTC'))->diff(new \DateTime($basis.' UTC')); + + $diff = $interval->days * 86400 + $interval->h * 3600 + $interval->i * 60 + $interval->s; + + return ( $this->setTimeZone(new \DateTimeZone($timeZone))->getTimestamp() + $diff ) * $resolution; + } +} diff --git a/src/Entity/OrganizationalUnit.php b/src/Entity/OrganizationalUnit.php index 6cf868c..b21da5b 100644 --- a/src/Entity/OrganizationalUnit.php +++ b/src/Entity/OrganizationalUnit.php @@ -46,6 +46,11 @@ class OrganizationalUnit */ public string $telephoneNumber; + /** + * @Field('name' => 'objectGUID') + */ + public string $guid; + public function __toString() : string { return $this->ou; diff --git a/src/Entity/User.php b/src/Entity/User.php index f8a6b76..74a3522 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -2,7 +2,7 @@ namespace Ulmus\Ldap\Entity; -use Ulmus\Ldap\Entity\Field\{ Datetime }; +use Ulmus\Ldap\Entity\Field\{ Datetime, LdapDatetime }; /** * @ObjectClass('user') @@ -81,6 +81,11 @@ class User */ public string $title; + /** + * @Field('readonly' => true) + */ + public ? array $memberOf; + /** * @Field */ @@ -106,6 +111,61 @@ class User */ public string $extensionAttribute4; + /** + * @Field + */ + public string $extensionAttribute5; + + /** + * @Field + */ + public string $extensionAttribute6; + + /** + * @Field + */ + public string $extensionAttribute7; + + /** + * @Field + */ + public string $extensionAttribute8; + + /** + * @Field + */ + public string $extensionAttribute9; + + /** + * @Field + */ + public string $extensionAttribute10; + + /** + * @Field + */ + public string $extensionAttribute11; + + /** + * @Field + */ + public string $extensionAttribute12; + + /** + * @Field + */ + public string $extensionAttribute13; + + /** + * @Field + */ + public string $extensionAttribute14; + + /** + * @Field + */ + public string $extensionAttribute15; + /** * @Field */ @@ -124,20 +184,38 @@ class User /** * @Field */ - public Datetime $lastLogonDate; + public string $scriptPath; /** - * #Field('name' => 'createTimeStamp') + * @Field */ - # public Datetime $createdAt; + public string $sid; /** - * #Field('name' => 'modifyTimeStamp') + * @Field('name' => "lastLogon", 'readonly' => true) */ - # public Datetime $updatedAt; + public LdapDatetime $lastLogon; + + /** + * @Field('name' => "whenChanged", 'readonly' => true) + * / + public LdapDatetime $updatedAt; + + /** + * @Field('name' => "whenCreated", 'readonly' => true) + * / + public LdapDatetime $createdAt; */ public function __toString() : string { - return implode(' ', array_filter([ $this->firstname ?? "", $this->lastname ?? "" ])) ?: $this->displayName; + return implode(' ', array_filter([ $this->firstname ?? "", $this->lastname ?? "" ])) ?: ( $this->displayName ?? "" ); + } + + public function memberOfGroup() : array + { + $arr = array_map(fn($e) => explode('=', explode(',', $e)[0])[1], $this->memberOf); + usort($arr, 'strcasecmp'); + + return $arr; } } \ No newline at end of file diff --git a/src/EntityTrait.php b/src/EntityTrait.php index 5bb57c7..14f952d 100644 --- a/src/EntityTrait.php +++ b/src/EntityTrait.php @@ -14,6 +14,11 @@ trait EntityTrait { */ public string $dn; + /** + * @Field + */ + public string $cn; + public static function resolveEntity() : EntityResolver { return Ulmus::resolveEntity(static::class); diff --git a/src/Repository.php b/src/Repository.php index 43078dd..16f80bd 100644 --- a/src/Repository.php +++ b/src/Repository.php @@ -56,6 +56,19 @@ class Repository extends \Ulmus\Repository return $this; } + public function loadAllFromOU(string $ou) : EntityCollection + { + $dn = $this->adapter->connector()->dn; + + $this->adapter->connector()->dn = $ou; + + $collection = $this->collectionFromQuery(); + + $this->adapter->connector()->dn = $dn; + + return $collection; + } + public function update(string $dn, string $alias, ? string $schema) : self { $this->queryBuilder->update($dn, "", ""); @@ -63,9 +76,16 @@ class Repository extends \Ulmus\Repository return $this; } - public function escapeValue(string $identifier) : string + public function runDeleteQuery() /* : mixed */ { - return $this->adapter->adapter()->escapeIdentifier($identifier, Adapter\Ldap::IDENTIFIER_FILTER); + $this->finalizeQuery(); + + return Ulmus::runQuery($this->queryBuilder, $this->adapter); + } + + public function escapeValue($identifier) : string + { + return is_object($identifier) ? $identifier : $this->adapter->adapter()->escapeIdentifier($identifier, Adapter\Ldap::IDENTIFIER_FILTER); } public function filterServerRequest(SearchRequest\SearchRequestInterface $searchRequest, bool $count = true) : self