Merge pull request #24052 from owncloud/fix-ldap-cache-race-conditions

Fix LDAP race conditions
This commit is contained in:
Thomas Müller 2016-04-25 14:55:20 +02:00
commit 6321596134
6 changed files with 32 additions and 48 deletions

View File

@ -72,8 +72,9 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
return false; return false;
} }
$cacheKey = 'inGroup'.$uid.':'.$gid; $cacheKey = 'inGroup'.$uid.':'.$gid;
if($this->access->connection->isCached($cacheKey)) { $inGroup = $this->access->connection->getFromCache($cacheKey);
return $this->access->connection->getFromCache($cacheKey); if(!is_null($inGroup)) {
return (bool)$inGroup;
} }
$userDN = $this->access->username2dn($uid); $userDN = $this->access->username2dn($uid);
@ -84,8 +85,8 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
} }
$cacheKeyMembers = 'inGroup-members:'.$gid; $cacheKeyMembers = 'inGroup-members:'.$gid;
if($this->access->connection->isCached($cacheKeyMembers)) { $members = $this->access->connection->getFromCache($cacheKeyMembers);
$members = $this->access->connection->getFromCache($cacheKeyMembers); if(!is_null($members)) {
$this->cachedGroupMembers[$gid] = $members; $this->cachedGroupMembers[$gid] = $members;
$isInGroup = in_array($userDN, $members); $isInGroup = in_array($userDN, $members);
$this->access->connection->writeToCache($cacheKey, $isInGroup); $this->access->connection->writeToCache($cacheKey, $isInGroup);
@ -204,8 +205,9 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
} }
// used extensively in cron job, caching makes sense for nested groups // used extensively in cron job, caching makes sense for nested groups
$cacheKey = '_groupMembers'.$dnGroup; $cacheKey = '_groupMembers'.$dnGroup;
if($this->access->connection->isCached($cacheKey)) { $groupMembers = $this->access->connection->getFromCache($cacheKey);
return $this->access->connection->getFromCache($cacheKey); if(!is_null($groupMembers)) {
return $groupMembers;
} }
$seen[$dnGroup] = 1; $seen[$dnGroup] = 1;
$members = $this->access->readAttribute($dnGroup, $this->access->connection->ldapGroupMemberAssocAttr, $members = $this->access->readAttribute($dnGroup, $this->access->connection->ldapGroupMemberAssocAttr,
@ -267,11 +269,9 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
*/ */
public function primaryGroupID2Name($gid, $dn) { public function primaryGroupID2Name($gid, $dn) {
$cacheKey = 'primaryGroupIDtoName'; $cacheKey = 'primaryGroupIDtoName';
if($this->access->connection->isCached($cacheKey)) { $groupNames = $this->access->connection->getFromCache($cacheKey);
$groupNames = $this->access->connection->getFromCache($cacheKey); if(!is_null($groupNames) && isset($groupNames[$gid])) {
if(isset($groupNames[$gid])) { return $groupNames[$gid];
return $groupNames[$gid];
}
} }
$domainObjectSid = $this->access->getSID($dn); $domainObjectSid = $this->access->getSID($dn);
@ -440,8 +440,9 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
return array(); return array();
} }
$cacheKey = 'getUserGroups'.$uid; $cacheKey = 'getUserGroups'.$uid;
if($this->access->connection->isCached($cacheKey)) { $userGroups = $this->access->connection->getFromCache($cacheKey);
return $this->access->connection->getFromCache($cacheKey); if(!is_null($userGroups)) {
return $userGroups;
} }
$userDN = $this->access->username2dn($uid); $userDN = $this->access->username2dn($uid);
if(!$userDN) { if(!$userDN) {
@ -861,8 +862,9 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
* @return bool * @return bool
*/ */
public function groupExists($gid) { public function groupExists($gid) {
if($this->access->connection->isCached('groupExists'.$gid)) { $groupExists = $this->access->connection->getFromCache('groupExists'.$gid);
return $this->access->connection->getFromCache('groupExists'.$gid); if(!is_null($groupExists)) {
return (bool)$groupExists;
} }
//getting dn, if false the group does not exist. If dn, it may be mapped //getting dn, if false the group does not exist. If dn, it may be mapped

View File

@ -364,8 +364,9 @@ class Access extends LDAPUtility implements user\IUserTools {
$validGroupDNs = []; $validGroupDNs = [];
foreach($groupDNs as $dn) { foreach($groupDNs as $dn) {
$cacheKey = 'groupsMatchFilter-'.$dn; $cacheKey = 'groupsMatchFilter-'.$dn;
if($this->connection->isCached($cacheKey)) { $groupMatchFilter = $this->connection->getFromCache($cacheKey);
if($this->connection->getFromCache($cacheKey)) { if(!is_null($groupMatchFilter)) {
if($groupMatchFilter) {
$validGroupDNs[] = $dn; $validGroupDNs[] = $dn;
} }
continue; continue;
@ -1503,8 +1504,9 @@ class Access extends LDAPUtility implements user\IUserTools {
public function getSID($dn) { public function getSID($dn) {
$domainDN = $this->getDomainDNFromDN($dn); $domainDN = $this->getDomainDNFromDN($dn);
$cacheKey = 'getSID-'.$domainDN; $cacheKey = 'getSID-'.$domainDN;
if($this->connection->isCached($cacheKey)) { $sid = $this->connection->getFromCache($cacheKey);
return $this->connection->getFromCache($cacheKey); if(!is_null($sid)) {
return $sid;
} }
$objectSid = $this->readAttribute($domainDN, 'objectsid'); $objectSid = $this->readAttribute($domainDN, 'objectsid');

View File

@ -207,30 +207,11 @@ class Connection extends LDAPUtility {
if(is_null($this->cache) || !$this->configuration->ldapCacheTTL) { if(is_null($this->cache) || !$this->configuration->ldapCacheTTL) {
return null; return null;
} }
if(!$this->isCached($key)) {
return null;
}
$key = $this->getCacheKey($key); $key = $this->getCacheKey($key);
return json_decode(base64_decode($this->cache->get($key)), true); return json_decode(base64_decode($this->cache->get($key)), true);
} }
/**
* @param string $key
* @return bool
*/
public function isCached($key) {
if(!$this->configured) {
$this->readConfiguration();
}
if(is_null($this->cache) || !$this->configuration->ldapCacheTTL) {
return false;
}
$key = $this->getCacheKey($key);
return $this->cache->hasKey($key);
}
/** /**
* @param string $key * @param string $key
* @param mixed $value * @param mixed $value

View File

@ -297,8 +297,9 @@ class User {
public function getMemberOfGroups() { public function getMemberOfGroups() {
$cacheKey = 'getMemberOf'.$this->getUsername(); $cacheKey = 'getMemberOf'.$this->getUsername();
if($this->connection->isCached($cacheKey)) { $memberOfGroups = $this->connection->getFromCache($cacheKey);
return $this->connection->getFromCache($cacheKey); if(!is_null($memberOfGroups)) {
return $memberOfGroups;
} }
$groupDNs = $this->access->readAttribute($this->getDN(), 'memberOf'); $groupDNs = $this->access->readAttribute($this->getDN(), 'memberOf');
$this->connection->writeToCache($cacheKey, $groupDNs); $this->connection->writeToCache($cacheKey, $groupDNs);

View File

@ -294,10 +294,6 @@ class Test_Group_Ldap extends \Test\TestCase {
$uid = 'someUser'; $uid = 'someUser';
$gid = 'someGroup'; $gid = 'someGroup';
$cacheKey = 'inGroup'.$uid.':'.$gid; $cacheKey = 'inGroup'.$uid.':'.$gid;
$access->connection->expects($this->once())
->method('isCached')
->with($cacheKey)
->will($this->returnValue(true));
$access->connection->expects($this->once()) $access->connection->expects($this->once())
->method('getFromCache') ->method('getFromCache')

View File

@ -250,8 +250,9 @@ class USER_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
* @throws \Exception when connection could not be established * @throws \Exception when connection could not be established
*/ */
public function userExists($uid) { public function userExists($uid) {
if($this->access->connection->isCached('userExists'.$uid)) { $userExists = $this->access->connection->getFromCache('userExists'.$uid);
return $this->access->connection->getFromCache('userExists'.$uid); if(!is_null($userExists)) {
return (bool)$userExists;
} }
//getting dn, if false the user does not exist. If dn, he may be mapped only, requires more checking. //getting dn, if false the user does not exist. If dn, he may be mapped only, requires more checking.
$user = $this->access->userManager->get($uid); $user = $this->access->userManager->get($uid);
@ -321,8 +322,9 @@ class USER_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
} }
$cacheKey = 'getHome'.$uid; $cacheKey = 'getHome'.$uid;
if($this->access->connection->isCached($cacheKey)) { $path = $this->access->connection->getFromCache($cacheKey);
return $this->access->connection->getFromCache($cacheKey); if(!is_null($path)) {
return $path;
} }
$user = $this->access->userManager->get($uid); $user = $this->access->userManager->get($uid);