From f3ea2ffc2495a246bd889b8f1098976d22fac658 Mon Sep 17 00:00:00 2001 From: "robin.kluth" Date: Mon, 24 Jul 2023 09:43:17 +0200 Subject: [PATCH] Optional caching --- README.md | 4 +++ src/LdapAuth.php | 76 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/README.md b/README.md index d243cef..0f3d5cf 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ This extensions adds a simple LDAP-Auth mechanism for your yii2 application * Read self defined LDAP attributes * Domain autodetection based on IPFilter. * Filter out results by checking every results `sidHistory` +* Optional query caching ## Installation @@ -32,6 +33,9 @@ Either you use it as standalone or add this as component: 'ldap' => [ 'class' => 'commifreak\yii2\LdapAuth', 'filterBySidhistory' => false, // Filter by checking sidHistory? + 'enableCache' => false, + 'forceApcuCache' => false, + 'apcuCacheTtl' => 3600, 'domains' => [ ['name' => 'Domain1', 'hostname' => 'domain1.tld', 'autodetectIps' => ['172.31.0.0/16', '192.168.178.0/24', '127.0.0.1'], 'baseDn' => 'DC=Domain1,DC=tld', 'publicSearchUser' => 'example@domain', 'publicSearchUserPassword' => 'secret'], ['name' => 'Domain2', 'hostname' => '192.168.178.14', 'autodetectIps' => ['192.168.178.55'], 'baseDn' => 'DC=Domain2,DC=tld', 'publicSearchUser' => 'example@domain', 'publicSearchUserPassword' => 'secret'], diff --git a/src/LdapAuth.php b/src/LdapAuth.php index 7a16586..d5c3c59 100644 --- a/src/LdapAuth.php +++ b/src/LdapAuth.php @@ -46,6 +46,24 @@ class LdapAuth extends BaseObject */ public $filterBySidhistory = false; + /** + * Enable optional object caching. Uses Yii::$app->cache component. Or enable APCu with `forceApcuCache` + * @var bool + */ + public $enableCache = false; + + /** + * Force the use of APCu caching instead of the Yii2 cache component + * @var bool + */ + public $forceApcuCache = false; + + /** + * Time in seconds objects are cached, if `forceApcuCache` is enabled! + * @var int + */ + public $apcuCacheTtl = 3600; + private $_ldapBaseDn; private $_l; private $_username; @@ -59,6 +77,15 @@ public function init() throw new Exception("LDAP-extension missing :("); } + // Check for APCu missing if not cli. + if (php_sapi_name() != 'cli' && $this->enableCache && $this->forceApcuCache && !extension_loaded('apcu')) { + throw new Exception("Caching is enabled but APCU is not! :("); + } + + if ($this->enableCache && !$this->forceApcuCache && !isset(Yii::$app->cache)) { + throw new Exception("Caching is enabled with Yii cache component but its not configured! :("); + } + // Sort the domains one time for this run! $autoDetectDomainKey = $this->autoDetect(); @@ -360,6 +387,34 @@ public function searchUser(?string $searchFor, ?array $attributes = [], ?string throw new InvalidArgumentException("Search term is empty but the filter has a placeholder set! Set a term or set a new filter."); } + $cacheKey = 'y2ldap_' . md5($searchFor . (implode("", $attributes)) . $searchFilter); + Yii::debug("Cache-Key: " . $cacheKey, __METHOD__); + + if ($this->enableCache) { + if (!$this->forceApcuCache) { + $storedValue = Yii::$app->cache->get($cacheKey); + if ($storedValue) { + Yii::debug("[YII] Returning cached asset", __METHOD__); + return $storedValue; + } + Yii::debug("Was not cached or invalid", __METHOD__); + } else { + if (apcu_exists($cacheKey)) { + Yii::debug("Caching enabled and this search is stored!", __METHOD__); + $apcuValue = apcu_fetch($cacheKey); + if ($apcuValue !== false) { + Yii::debug("[APCU] Returning cached asset!", __METHOD__); + return $apcuValue; + } + Yii::warning("Could not return cached asset!", __METHOD__); + } else { + Yii::debug("No cache entry!", __METHOD__); + } + } + } else { + Yii::debug("Caching disabled", __METHOD__); + } + // Default set $domains = $this->domains; @@ -471,6 +526,27 @@ public function searchUser(?string $searchFor, ?array $attributes = [], ?string Yii::debug("Result:", __METHOD__); Yii::debug($return, __METHOD__); + if ($this->enableCache) { + Yii::debug("Adding cache entry", __METHOD__); + if (!$this->forceApcuCache) { + if (Yii::$app->cache->set($cacheKey, $result)) { + Yii::debug("[YII] Caching succeeded!", __METHOD__); + } else { + Yii::warning("[YII] Caching failed!", __METHOD__); + } + } else { + $cacheResult = apcu_store($cacheKey, $return, $this->apcuCacheTtl); + if (!$cacheResult) { + Yii::warning("[APCU] Caching was not successful!", __METHOD__); + } else { + Yii::debug("[APCU] Cached!", __METHOD__); + } + } + } else { + Yii::debug("Not caching: Disabled", __METHOD__); + } + + return empty($return) ? [] : $return;