Skip to content
Snippets Groups Projects
Commit 324394c6 authored by Tobias Gross-Vogt's avatar Tobias Gross-Vogt
Browse files

implemented local data mechanism

parent cceeed81
No related branches found
No related tags found
No related merge requests found
Pipeline #107485 passed
......@@ -8,7 +8,8 @@
"ext-simplexml": "*",
"adldap2/adldap2": "^10.3",
"dbp/relay-auth-bundle": "^0.1.6",
"dbp/relay-base-person-bundle": "^0.2.0",
"dbp/relay-base-person-bundle": "dev-main as 0.2.0",
"dbp/relay-core-bundle": "^0.1.35",
"guzzlehttp/guzzle": "^7.3",
"league/uri": "^6.5",
"symfony/event-dispatcher": "^5.4",
......@@ -40,6 +41,9 @@
"sort-packages": true,
"platform": {
"php": "7.3"
},
"allow-plugins": {
"composer/package-versions-deprecated": true
}
},
"scripts": {
......
......@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "660bb35831e9baee96c0c873db1f624a",
"content-hash": "486c7399159622dbac4ab15d95ea77b6",
"packages": [
{
"name": "adldap2/adldap2",
......@@ -346,15 +346,15 @@
},
{
"name": "dbp/relay-base-person-bundle",
"version": "v0.2.0",
"version": "dev-main",
"source": {
"type": "git",
"url": "https://gitlab.tugraz.at/dbp/relay/dbp-relay-base-person-bundle",
"reference": "9793a5e69a4a4b4ae76f0eacc1510ad33e5ec1a3"
"reference": "b304723071831c2e5e01ffbd254106fc868e825f"
},
"require": {
"api-platform/core": "^2.6.3",
"dbp/relay-core-bundle": "^0.1.25",
"dbp/relay-core-bundle": "^0.1.35",
"ext-json": "*",
"guzzlehttp/guzzle": "^7.0",
"nelmio/cors-bundle": "^2.1.0",
......@@ -381,6 +381,7 @@
"symfony/phpunit-bridge": "^5.2",
"vimeo/psalm": "^4.4"
},
"default-branch": true,
"type": "symfony-bundle",
"autoload": {
"psr-4": {
......@@ -391,15 +392,15 @@
"license": [
"AGPL-3.0-or-later"
],
"time": "2022-03-17T14:27:32+00:00"
"time": "2022-05-02T07:24:36+00:00"
},
{
"name": "dbp/relay-core-bundle",
"version": "v0.1.34",
"version": "v0.1.35",
"source": {
"type": "git",
"url": "https://gitlab.tugraz.at/dbp/relay/dbp-relay-core-bundle",
"reference": "d957d248aff513901e89d6eeb7dc8d0e3f68ea63"
"reference": "79d1b52f65989ee2285a9219c4a552f2cbc9bab2"
},
"require": {
"api-platform/core": "^2.6.6",
......@@ -459,7 +460,7 @@
"AGPL-3.0-or-later"
],
"description": "The core bundle of the Relay API gateway",
"time": "2022-04-26T12:25:46+00:00"
"time": "2022-05-02T07:07:30+00:00"
},
{
"name": "doctrine/annotations",
......@@ -11344,9 +11345,18 @@
"time": "2015-12-17T08:42:14+00:00"
}
],
"aliases": [],
"aliases": [
{
"package": "dbp/relay-base-person-bundle",
"version": "dev-main",
"alias": "0.2.0",
"alias_normalized": "0.2.0.0"
}
],
"minimum-stability": "stable",
"stability-flags": [],
"stability-flags": {
"dbp/relay-base-person-bundle": 20
},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
......@@ -11358,5 +11368,5 @@
"platform-overrides": {
"php": "7.3"
},
"plugin-api-version": "2.3.0"
"plugin-api-version": "2.2.0"
}
......@@ -5,9 +5,9 @@ declare(strict_types=1);
namespace Dbp\Relay\BasePersonConnectorLdapBundle\Event;
use Dbp\Relay\BasePersonBundle\Entity\Person;
use Symfony\Contracts\EventDispatcher\Event;
use Dbp\Relay\CoreBundle\LocalData\LocalDataAwareEvent;
class PersonFromUserItemPostEvent extends Event
class PersonFromUserItemPostEvent extends LocalDataAwareEvent
{
public const NAME = 'dbp.relay.base_person_connector_ldap_bundle.person_from_user_item.post';
......@@ -17,6 +17,8 @@ class PersonFromUserItemPostEvent extends Event
public function __construct(array $attributes, Person $person, bool $full)
{
parent::__construct($person);
$this->attributes = $attributes;
$this->person = $person;
$this->full = $full;
......@@ -41,4 +43,14 @@ class PersonFromUserItemPostEvent extends Event
{
$this->person = $person;
}
public function getEntity(): Person
{
return $this->person;
}
public function getSourceData(): array
{
return $this->attributes;
}
}
......@@ -16,11 +16,12 @@ use Adldap\Models\User;
use Adldap\Query\Builder;
use Dbp\Relay\BasePersonBundle\Entity\Person;
use Dbp\Relay\BasePersonConnectorLdapBundle\Event\PersonFromUserItemPostEvent;
use Dbp\Relay\BasePersonConnectorLdapBundle\Event\PersonFromUserItemPreEvent;
use Dbp\Relay\BasePersonConnectorLdapBundle\Event\PersonUserItemPreEvent;
use Dbp\Relay\CoreBundle\API\UserSessionInterface;
use Dbp\Relay\CoreBundle\Exception\ApiError;
use Dbp\Relay\CoreBundle\Helpers\Tools as CoreTools;
use Dbp\Relay\CoreBundle\LocalData\LocalData;
use Dbp\Relay\CoreBundle\LocalData\LocalDataAwareEventDispatcher;
use Psr\Cache\CacheItemPoolInterface;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerAwareInterface;
......@@ -37,20 +38,18 @@ class LDAPApi implements LoggerAwareInterface, ServiceSubscriberInterface
private $PAGESIZE = 50;
/**
* @var Adldap
*/
private $ad;
/** @var ProviderInterface|null */
private $provider;
/** @var CacheItemPoolInterface|null */
private $cachePool;
/** @var CacheItemPoolInterface|null */
private $personCache;
private $cacheTTL;
/**
* @var Person|null
*/
/** @var Person|null */
private $currentPerson;
private $providerConfig;
......@@ -72,14 +71,18 @@ class LDAPApi implements LoggerAwareInterface, ServiceSubscriberInterface
/** @var EventDispatcherInterface */
private $dispatcher;
/** @var LocalDataAwareEventDispatcher */
private $localDataAwareEventDispatcher;
public function __construct(ContainerInterface $locator, EventDispatcherInterface $dispatcher)
{
$this->ad = new Adldap();
$this->provider = null;
$this->cacheTTL = 0;
$this->currentPerson = null;
$this->locator = $locator;
$this->deploymentEnv = 'production';
$this->dispatcher = $dispatcher;
$this->localDataAwareEventDispatcher = new LocalDataAwareEventDispatcher(Person::class, $dispatcher);
}
public function setConfig(array $config)
......@@ -168,15 +171,20 @@ class LDAPApi implements LoggerAwareInterface, ServiceSubscriberInterface
if ($this->logger !== null) {
Adldap::setLogger($this->logger);
}
$ad = new Adldap();
$ad->addProvider($this->providerConfig);
$provider = $ad->connect();
assert($provider instanceof Provider);
if ($this->cachePool !== null) {
$provider->setCache(new Psr16Cache($this->cachePool));
if ($this->provider === null) {
$ad = new Adldap();
$ad->addProvider($this->providerConfig);
$this->provider = $ad->connect();
assert($this->provider instanceof Provider);
if ($this->cachePool !== null) {
$this->provider->setCache(new Psr16Cache($this->cachePool));
}
}
return $provider;
return $this->provider;
}
private function getCachedBuilder(ProviderInterface $provider): Builder
......@@ -185,9 +193,7 @@ class LDAPApi implements LoggerAwareInterface, ServiceSubscriberInterface
// return $provider->search()->cache($until=$this->cacheTTL);
// We depend on the default TTL of the cache for now...
/**
* @var Builder $builder
*/
/** @var Builder $builder */
$builder = $provider->search()->cache();
return $builder;
......@@ -220,6 +226,8 @@ class LDAPApi implements LoggerAwareInterface, ServiceSubscriberInterface
public function getPersons(array $filters): array
{
$this->localDataAwareEventDispatcher->initRequestedLocalDataAttributes(LocalData::getIncludeParameter($filters));
$persons = [];
$items = $this->getPeopleUserItems($filters);
foreach ($items as $item) {
......@@ -230,7 +238,7 @@ class LDAPApi implements LoggerAwareInterface, ServiceSubscriberInterface
return $persons;
}
public function getPersonUserItem(string $identifier): ?User
private function getPersonUserItem(string $identifier): ?User
{
$preEvent = new PersonUserItemPreEvent($identifier);
$this->dispatcher->dispatch($preEvent, PersonUserItemPreEvent::NAME);
......@@ -295,21 +303,25 @@ class LDAPApi implements LoggerAwareInterface, ServiceSubscriberInterface
}
$postEvent = new PersonFromUserItemPostEvent($attributes, $person, $full);
$this->dispatcher->dispatch($postEvent, PersonFromUserItemPostEvent::NAME);
$this->localDataAwareEventDispatcher->dispatch($postEvent, PersonFromUserItemPostEvent::NAME);
return $postEvent->getPerson();
}
public function getPerson(string $id): Person
public function getPerson(string $id, array $options = []): Person
{
$id = str_replace('/people/', '', $id);
$this->localDataAwareEventDispatcher->initRequestedLocalDataAttributes(LocalData::getIncludeParameter($options));
// extract username in case $id is an iri, e.g. /base/people/{user}
$parts = explode('/', $id);
$id = $parts[count($parts) - 1];
$session = $this->getUserSession();
$currentIdentifier = $session->getUserIdentifier();
if ($currentIdentifier !== null && $currentIdentifier === $id) {
// fast path: getCurrentPerson() does some caching
$person = $this->getCurrentPerson();
// fast path
$person = $this->getCurrentPersonCached(true);
assert($person !== null);
} else {
$user = $this->getPersonUserItem($id);
......@@ -324,63 +336,65 @@ class LDAPApi implements LoggerAwareInterface, ServiceSubscriberInterface
return $this->locator->get(UserSessionInterface::class);
}
public function getCurrentPersonCached(): Person
/**
* @thorws NotFoundHttpException
*/
private function getCurrentPersonCached(bool $checkLocalDataAttributes): ?Person
{
$session = $this->getUserSession();
$currentIdentifier = $session->getUserIdentifier();
assert($currentIdentifier !== null);
if ($currentIdentifier === null) {
return null;
}
$forceCreation = false;
if ($this->currentPerson) {
if ($this->currentPerson->getIdentifier() === $currentIdentifier) {
if (!$checkLocalDataAttributes || $this->localDataAwareEventDispatcher->checkRequestedAttributesIdentitcal($this->currentPerson)) {
return $this->currentPerson;
} else {
// cache a new instance of Person because the cached instance's local data attributes do not match the requested attributes
$forceCreation = true;
}
}
$this->currentPerson = null;
}
$cache = $this->personCache;
$cacheKey = $session->getSessionCacheKey().'-'.$currentIdentifier;
// make sure the cache is longer than the session, so just double it.
$cacheTTL = $session->getSessionTTL() * 2;
$person = null;
$item = $cache->getItem($cacheKey);
if ($item->isHit()) {
if (!$forceCreation && $item->isHit()) {
$person = $item->get();
if ($person === null) {
throw new NotFoundHttpException();
}
return $person;
} else {
try {
$user = $this->getPersonUserItem($currentIdentifier);
$person = $this->personFromUserItem($user, true);
} catch (NotFoundHttpException $e) {
$person = null;
}
$item->set($person);
$item->expiresAfter($cacheTTL);
$cache->save($item);
if ($person === null) {
throw new NotFoundHttpException();
}
return $person;
}
}
public function getCurrentPerson(): ?Person
{
$session = $this->getUserSession();
$currentIdentifier = $session->getUserIdentifier();
if ($currentIdentifier === null) {
return null;
}
if ($this->currentPerson !== null && $this->currentPerson->getIdentifier() !== $currentIdentifier) {
$this->currentPerson = null;
}
$this->currentPerson = $person;
if ($this->currentPerson === null) {
$this->currentPerson = $this->getCurrentPersonCached();
throw new NotFoundHttpException();
}
return $this->currentPerson;
}
public function getCurrentPerson(): ?Person
{
return $this->getCurrentPersonCached(false);
}
public static function getSubscribedServices(): array
{
return [
......
......@@ -9,6 +9,7 @@ use Dbp\Relay\BasePersonBundle\Entity\Person;
class LDAPPersonProvider implements PersonProviderInterface
{
/** @var LDAPApi */
private $ldapApi;
public function __construct(LDAPApi $ldapApi)
......@@ -16,16 +17,25 @@ class LDAPPersonProvider implements PersonProviderInterface
$this->ldapApi = $ldapApi;
}
/**
* @param array $filters $filters['search'] can be a string to search for people (e.g. part of the name)
*
* @return Person[]
*/
public function getPersons(array $filters): array
{
return $this->ldapApi->getPersons($filters);
}
public function getPerson(string $id): Person
public function getPerson(string $id, array $options = []): Person
{
return $this->ldapApi->getPerson($id);
return $this->ldapApi->getPerson($id, $options);
}
/**
* Returns the Person matching the current user. Or null if there is no associated person
* like when the client is another server.
*/
public function getCurrentPerson(): ?Person
{
return $this->ldapApi->getCurrentPerson();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment