LDAP: use OC_Cache to cache results from LDAP. Default is set to 10 min. Should improve performance especially when LDAP users use the sync client, because userExists checks with the LDAP server are reduced.

This commit is contained in:
Arthur Schiwon 2012-07-26 16:11:23 +02:00
parent e0121ea75e
commit 6c92a85d49
5 changed files with 109 additions and 34 deletions

View File

@ -26,11 +26,6 @@ namespace OCA\user_ldap;
class GROUP_LDAP extends lib\Access implements \OCP\GroupInterface {
protected $enabled = false;
protected $_group_user = array();
protected $_user_groups = array();
protected $_group_users = array();
protected $_groups = array();
public function setConnector(lib\Connection &$connection) {
parent::setConnector($connection);
if(empty($this->connection->ldapGroupFilter) || empty($this->connection->ldapGroupMemberAssocAttr)) {
@ -51,18 +46,20 @@ class GROUP_LDAP extends lib\Access implements \OCP\GroupInterface {
if(!$this->enabled) {
return false;
}
if(isset($this->_group_user[$gid][$uid])) {
return $this->_group_user[$gid][$uid];
if($this->connection->isCached('inGroup'.$uid.':'.$gid)) {
return $this->connection->getFromCache('inGroup'.$uid.':'.$gid);
}
$dn_user = $this->username2dn($uid);
$dn_group = $this->groupname2dn($gid);
// just in case
if(!$dn_group || !$dn_user) {
$this->connection->writeToCache('inGroup'.$uid.':'.$gid, false);
return false;
}
//usually, LDAP attributes are said to be case insensitive. But there are exceptions of course.
$members = $this->readAttribute($dn_group, $this->connection->ldapGroupMemberAssocAttr);
if(!$members) {
$this->connection->writeToCache('inGroup'.$uid.':'.$gid, false);
return false;
}
@ -81,8 +78,10 @@ class GROUP_LDAP extends lib\Access implements \OCP\GroupInterface {
$members = $dns;
}
$this->_group_user[$gid][$uid] = in_array($dn_user, $members);
return $this->_group_user[$gid][$uid];
$isInGroup = in_array($dn_user, $members);
$this->connection->writeToCache('inGroup'.$uid.':'.$gid, $isInGroup);
return $isInGroup;
}
/**
@ -97,12 +96,12 @@ class GROUP_LDAP extends lib\Access implements \OCP\GroupInterface {
if(!$this->enabled) {
return array();
}
if(isset($this->_user_groups[$uid])) {
return $this->_user_groups[$uid];
if($this->connection->isCached('getUserGroups'.$uid)) {
return $this->connection->getFromCache('getUserGroups'.$uid);
}
$userDN = $this->username2dn($uid);
if(!$userDN) {
$this->_user_groups[$uid] = array();
$this->connection->writeToCache('getUserGroups'.$uid, array());
return array();
}
@ -124,9 +123,10 @@ class GROUP_LDAP extends lib\Access implements \OCP\GroupInterface {
$this->connection->ldapGroupMemberAssocAttr.'='.$uid
));
$groups = $this->fetchListOfGroups($filter, array($this->connection->ldapGroupDisplayName,'dn'));
$this->_user_groups[$uid] = array_unique($this->ownCloudGroupNames($groups), SORT_LOCALE_STRING);
$groups = array_unique($this->ownCloudGroupNames($groups), SORT_LOCALE_STRING);
$this->connection->writeToCache('getUserGroups'.$uid, $groups);
return $this->_user_groups[$uid];
return $groups;
}
/**
@ -137,19 +137,19 @@ class GROUP_LDAP extends lib\Access implements \OCP\GroupInterface {
if(!$this->enabled) {
return array();
}
if(isset($this->_group_users[$gid])) {
return $this->_group_users[$gid];
if($this->connection->isCached('usersInGroup'.$gid)) {
return $this->connection->getFromCache('usersInGroup'.$gid);
}
$groupDN = $this->groupname2dn($gid);
if(!$groupDN) {
$this->_group_users[$gid] = array();
$this->connection->writeToCache('usersInGroup'.$gid, array());
return array();
}
$members = $this->readAttribute($groupDN, $this->connection->ldapGroupMemberAssocAttr);
if(!$members) {
$this->_group_users[$gid] = array();
$this->connection->writeToCache('usersInGroup'.$gid, array());
return array();
}
@ -173,8 +173,10 @@ class GROUP_LDAP extends lib\Access implements \OCP\GroupInterface {
if(!$isMemberUid) {
$result = array_intersect($result, \OCP\User::getUsers());
}
$this->_group_users[$gid] = array_unique($result, SORT_LOCALE_STRING);
return $this->_group_users[$gid];
$groupUsers = array_unique($result, SORT_LOCALE_STRING);
$this->connection->writeToCache('usersInGroup'.$gid, $groupUsers);
return $groupUsers;
}
/**
@ -187,11 +189,14 @@ class GROUP_LDAP extends lib\Access implements \OCP\GroupInterface {
if(!$this->enabled) {
return array();
}
if(empty($this->_groups)) {
$ldap_groups = $this->fetchListOfGroups($this->connection->ldapGroupFilter, array($this->connection->ldapGroupDisplayName, 'dn'));
$this->_groups = $this->ownCloudGroupNames($ldap_groups);
if($this->connection->isCached('getGroups')) {
return $this->connection->getFromCache('getGroups');
}
return $this->_groups;
$ldap_groups = $this->fetchListOfGroups($this->connection->ldapGroupFilter, array($this->connection->ldapGroupDisplayName, 'dn'));
$ldap_groups = $this->ownCloudGroupNames($ldap_groups);
$this->connection->writeToCache('getGroups', $ldap_groups);
return $ldap_groups;
}
/**

View File

@ -28,7 +28,10 @@ class Connection {
private $configID;
private $configured = false;
//cached settings
//cache handler
protected $cache;
//settings
protected $config = array(
'ldapHost' => null,
'ldapPort' => null,
@ -48,10 +51,12 @@ class Connection {
'ldapQuotaAttribute' => null,
'ldapQuotaDefault' => null,
'ldapEmailAttribute' => null,
'ldapCacheTTL' => null,
);
public function __construct($configID = 'user_ldap') {
$this->configID = $configID;
$this->cache = \OC_Cache::getGlobalCache();
}
public function __destruct() {
@ -92,6 +97,57 @@ class Connection {
return $this->ldapConnectionRes;
}
private function getCacheKey($key) {
$prefix = 'LDAP-'.$this->configID.'-';
if(is_null($key)) {
return $prefix;
}
return $prefix.md5($key);
}
public function getFromCache($key) {
if(!$this->configured) {
$this->readConfiguration();
}
if(!$this->config['ldapCacheTTL']) {
return null;
}
if(!$this->isCached($key)) {
return null;
}
$key = $this->getCacheKey($key);
return unserialize(base64_decode($this->cache->get($key)));
}
public function isCached($key) {
if(!$this->configured) {
$this->readConfiguration();
}
if(!$this->config['ldapCacheTTL']) {
return false;
}
$key = $this->getCacheKey($key);
return $this->cache->hasKey($key);
}
public function writeToCache($key, $value) {
if(!$this->configured) {
$this->readConfiguration();
}
if(!$this->config['ldapCacheTTL']) {
return null;
}
$key = $this->getCacheKey($key);
$value = base64_encode(serialize($value));
$this->cache->set($key, $value, $this->config['ldapCacheTTL']);
}
public function clearCache() {
$this->cache->clear($this->getCacheKey(null));
}
/**
* Caches the general LDAP configuration.
*/
@ -118,6 +174,7 @@ class Connection {
$this->config['ldapEmailAttribute'] = \OCP\Config::getAppValue($this->configID, 'ldap_email_attr', '');
$this->config['ldapGroupMemberAssocAttr'] = \OCP\Config::getAppValue($this->configID, 'ldap_group_member_assoc_attribute', 'uniqueMember');
$this->config['ldapIgnoreNamingRules'] = \OCP\Config::getSystemValue('ldapIgnoreNamingRules', false);
$this->config['ldapCacheTTL'] = \OCP\Config::getAppValue($this->configID, 'ldap_cache_ttl', 10*60);
$this->configured = $this->validateConfiguration();
}

View File

@ -20,7 +20,7 @@
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
$params = array('ldap_host', 'ldap_port', 'ldap_dn', 'ldap_agent_password', 'ldap_base', 'ldap_base_users', 'ldap_base_groups', 'ldap_userlist_filter', 'ldap_login_filter', 'ldap_group_filter', 'ldap_display_name', 'ldap_group_display_name', 'ldap_tls', 'ldap_nocase', 'ldap_quota_def', 'ldap_quota_attr', 'ldap_email_attr', 'ldap_group_member_assoc_attribute');
$params = array('ldap_host', 'ldap_port', 'ldap_dn', 'ldap_agent_password', 'ldap_base', 'ldap_base_users', 'ldap_base_groups', 'ldap_userlist_filter', 'ldap_login_filter', 'ldap_group_filter', 'ldap_display_name', 'ldap_group_display_name', 'ldap_tls', 'ldap_nocase', 'ldap_quota_def', 'ldap_quota_attr', 'ldap_email_attr', 'ldap_group_member_assoc_attribute', 'ldap_cache_ttl');
OCP\Util::addscript('user_ldap', 'settings');
@ -29,18 +29,23 @@ if ($_POST) {
if(isset($_POST[$param])){
if('ldap_agent_password' == $param) {
OCP\Config::setAppValue('user_ldap', $param, base64_encode($_POST[$param]));
} elseif('ldap_cache_ttl' == $param) {
if(OCP\Config::getAppValue('user_ldap', $param,'') != $_POST[$param]) {
$ldap = new \OCA\user_ldap\lib\Connection('user_ldap');
$ldap->clearCache();
OCP\Config::setAppValue('user_ldap', $param, $_POST[$param]);
}
} else {
OCP\Config::setAppValue('user_ldap', $param, $_POST[$param]);
}
}
elseif('ldap_tls' == $param) {
// unchecked checkboxes are not included in the post paramters
OCP\Config::setAppValue('user_ldap', $param, 0);
OCP\Config::setAppValue('user_ldap', $param, 0);
}
elseif('ldap_nocase' == $param) {
OCP\Config::setAppValue('user_ldap', $param, 0);
}
}
}
@ -57,5 +62,6 @@ $tmpl->assign( 'ldap_display_name', OCP\Config::getAppValue('user_ldap', 'ldap_d
$tmpl->assign( 'ldap_group_display_name', OCP\Config::getAppValue('user_ldap', 'ldap_group_display_name', 'cn'));
$tmpl->assign( 'ldap_group_member_assoc_attribute', OCP\Config::getAppValue('user_ldap', 'ldap_group_member_assoc_attribute', 'uniqueMember'));
$tmpl->assign( 'ldap_agent_password', base64_decode(OCP\Config::getAppValue('user_ldap', 'ldap_agent_password')));
$tmpl->assign( 'ldap_cache_ttl', OCP\Config::getAppValue('user_ldap', 'ldap_cache_ttl', '600'));
return $tmpl->fetchPage();

View File

@ -26,6 +26,7 @@
<p><label for="ldap_quota_attr">Quota Attribute</label><input type="text" id="ldap_quota_attr" name="ldap_quota_attr" value="<?php echo $_['ldap_quota_attr']; ?>" />
<label for="ldap_quota_def">Quota Default</label><input type="text" id="ldap_quota_def" name="ldap_quota_def" value="<?php if (isset($_['ldap_quota_def'])) echo $_['ldap_quota_def']; ?>" />bytes</p>
<p><label for="ldap_email_attr">Email Attribute</label><input type="text" id="ldap_email_attr" name="ldap_email_attr" value="<?php echo $_['ldap_email_attr']; ?>" /></p>
<p><label for="ldap_cache_ttl">Cache Time-To-Live</label><input type="text" id="ldap_cache_ttl" name="ldap_cache_ttl" value="<?php echo $_['ldap_cache_ttl']; ?>" /><small><?php echo $l->t('in seconds');?></small></p>
</fieldset>
<input type="submit" value="Save" /> <a href="http://owncloud.org/support/ldap-backend/" target="_blank"><img src="<?php echo OCP\Util::imagePath('','actions/info.png'); ?>" style="height:1.75ex" /> <?php echo $l->t('Help');?></a>
</div>

View File

@ -27,9 +27,6 @@ namespace OCA\user_ldap;
class USER_LDAP extends lib\Access implements \OCP\UserInterface {
// cache getUsers()
protected $_users = null;
private function updateQuota($dn) {
$quota = null;
if(!empty($this->connection->ldapQuotaDefault)) {
@ -97,11 +94,13 @@ class USER_LDAP extends lib\Access implements \OCP\UserInterface {
* Get a list of all users.
*/
public function getUsers(){
if(is_null($this->_users)) {
$ldap_users = $this->connection->getFromCache('getUsers');
if(is_null($ldap_users)) {
$ldap_users = $this->fetchListOfUsers($this->connection->ldapUserFilter, array($this->connection->ldapUserDisplayName, 'dn'));
$this->_users = $this->ownCloudUserNames($ldap_users);
$ldap_users = $this->ownCloudUserNames($ldap_users);
$this->connection->writeToCache('getUsers', $ldap_users);
}
return $this->_users;
return $ldap_users;
}
/**
@ -110,18 +109,25 @@ class USER_LDAP extends lib\Access implements \OCP\UserInterface {
* @return boolean
*/
public function userExists($uid){
if($this->connection->isCached('userExists'.$uid)) {
return $this->connection->getFromCache('userExists'.$uid);
}
//getting dn, if false the user does not exist. If dn, he may be mapped only, requires more checking.
$dn = $this->username2dn($uid);
if(!$dn) {
$this->connection->writeToCache('userExists'.$uid, false);
return false;
}
//if user really still exists, we will be able to read his cn
$cn = $this->readAttribute($dn, 'cn');
if(!$cn || empty($cn)) {
$this->connection->writeToCache('userExists'.$uid, false);
return false;
}
$this->connection->writeToCache('userExists'.$uid, true);
return true;
}