Переглянути джерело

HPCC-15439 Implement a single permissions cache shared by all sec mgrs

Implement a new "sharedCache" config option that controls if the security
manager cache is share between all instances, or is private to a each
instance.  Also create a new singleton cache factory that returns a single
shared instance of the cache if the sharedCache option is chosen

Signed-off-by: Russ Whitehead <william.whitehead@lexisnexis.com>
Russ Whitehead 9 роки тому
батько
коміт
611f2f721f

+ 7 - 0
initfiles/componentfiles/configxml/ldapserver.xsd

@@ -169,6 +169,13 @@
                     </xs:appinfo>
                 </xs:annotation>
             </xs:attribute>
+            <xs:attribute name="sharedCache" type="xs:boolean" use="optional" default="true">
+                <xs:annotation>
+                    <xs:appinfo>
+                        <tooltip>Use a single, shared LDAP cache.</tooltip>
+                    </xs:appinfo>
+                </xs:annotation>
+            </xs:attribute>
             <xs:attribute name="systemUser" type="xs:string" use="optional">
                 <xs:annotation>
                     <xs:appinfo>

+ 1 - 0
initfiles/componentfiles/configxml/ldapserver.xsl

@@ -37,5 +37,6 @@
  systemBasedn="<xsl:value-of select="@systemBasedn"/>"
  usersBasedn="<xsl:value-of select="@usersBasedn"/>"
  workunitsBasedn="<xsl:value-of select="@workunitsBasedn"/>"
+ sharedCache="<xsl:value-of select="@sharedCache"/>"
    </xsl:template>
 </xsl:stylesheet>

+ 35 - 27
system/security/LdapSecurity/ldapsecurity.cpp

@@ -534,9 +534,15 @@ void CLdapSecManager::init(const char *serviceName, IPropertyTree* cfg)
     m_ldap_client.setown(ldap_client);
     m_pp.setown(pp);
     int cachetimeout = cfg->getPropInt("@cacheTimeout", 5);
-    m_permissionsCache.setCacheTimeout( 60 * cachetimeout);
-    m_permissionsCache.setTransactionalEnabled(true);
-    m_permissionsCache.setSecManager(this);
+
+    if (cfg->getPropBool("@sharedCache", true))
+        m_permissionsCache = CPermissionsCache::queryInstance();
+    else
+        m_permissionsCache = new CPermissionsCache();
+
+    m_permissionsCache->setCacheTimeout( 60 * cachetimeout);
+    m_permissionsCache->setTransactionalEnabled(true);
+    m_permissionsCache->setSecManager(this);
     m_passwordExpirationWarningDays = cfg->getPropInt(".//@passwordExpirationWarningDays", 10); //Default to 10 days
 };
 
@@ -548,6 +554,8 @@ CLdapSecManager::CLdapSecManager(const char *serviceName, IPropertyTree &config)
 
 CLdapSecManager::~CLdapSecManager()
 {
+    if (!m_cfg->getPropBool("@sharedCache", true))
+        delete m_permissionsCache;
 }
 
 //interface ISecManager : extends IInterface
@@ -584,7 +592,7 @@ bool CLdapSecManager::authenticate(ISecUser* user)
     if(user->getAuthenticateStatus() == AS_AUTHENTICATED)
         return true;
 
-    if(m_permissionsCache.isCacheEnabled() && !m_usercache_off && m_permissionsCache.lookup(*user))
+    if(m_permissionsCache->isCacheEnabled() && !m_usercache_off && m_permissionsCache->lookup(*user))
     {
         user->setAuthenticateStatus(AS_AUTHENTICATED);
         return true;
@@ -593,8 +601,8 @@ bool CLdapSecManager::authenticate(ISecUser* user)
     bool ok = m_ldap_client->authenticate(*user);
     if(ok)
     {
-        if(m_permissionsCache.isCacheEnabled() && !m_usercache_off)
-            m_permissionsCache.add(*user);
+        if(m_permissionsCache->isCacheEnabled() && !m_usercache_off)
+            m_permissionsCache->add(*user);
 
         user->setAuthenticateStatus(AS_AUTHENTICATED);
     }
@@ -628,10 +636,10 @@ bool CLdapSecManager::authorizeEx(SecResourceType rtype, ISecUser& sec_user, ISe
     bool rc;
 
     time_t tctime = getThreadCreateTime();
-    if ((m_permissionsCache.isCacheEnabled() || (m_permissionsCache.isTransactionalEnabled() && tctime > 0)) && (!m_cache_off[rtype]))
+    if ((m_permissionsCache->isCacheEnabled() || (m_permissionsCache->isTransactionalEnabled() && tctime > 0)) && (!m_cache_off[rtype]))
     {
         bool* cached_found = (bool*)alloca(nResources*sizeof(bool));
-        int nFound = m_permissionsCache.lookup(sec_user, rlist, cached_found);
+        int nFound = m_permissionsCache->lookup(sec_user, rlist, cached_found);
         if (nFound < nResources)
         {
             IArrayOf<ISecResource> rlist2;
@@ -649,7 +657,7 @@ bool CLdapSecManager::authorizeEx(SecResourceType rtype, ISecUser& sec_user, ISe
 
             rc = m_ldap_client->authorize(rtype, sec_user, rlist2);
             if (rc)
-                m_permissionsCache.add(sec_user, rlist2);
+                m_permissionsCache->add(sec_user, rlist2);
         }
         else
             rc = true;  
@@ -703,10 +711,10 @@ bool CLdapSecManager::authorizeEx(SecResourceType rtype, ISecUser& sec_user, ISe
     bool rc;
 
     time_t tctime = getThreadCreateTime();
-    if ((m_permissionsCache.isCacheEnabled() || (m_permissionsCache.isTransactionalEnabled() && tctime > 0)) && (!m_cache_off[rtype]))
+    if ((m_permissionsCache->isCacheEnabled() || (m_permissionsCache->isTransactionalEnabled() && tctime > 0)) && (!m_cache_off[rtype]))
     {
         bool* cached_found = (bool*)alloca(nResources*sizeof(bool));
-        int nFound = m_permissionsCache.lookup(sec_user, rlist, cached_found);
+        int nFound = m_permissionsCache->lookup(sec_user, rlist, cached_found);
         if (nFound < nResources)
         {
             IArrayOf<ISecResource> rlist2;
@@ -724,7 +732,7 @@ bool CLdapSecManager::authorizeEx(SecResourceType rtype, ISecUser& sec_user, ISe
 
             rc = m_ldap_client->authorize(rtype, sec_user, rlist2);
             if (rc)
-                m_permissionsCache.add(sec_user, rlist2);
+                m_permissionsCache->add(sec_user, rlist2);
         }
         else
             rc = true;  
@@ -780,10 +788,10 @@ int CLdapSecManager::getAccessFlagsEx(SecResourceType rtype, ISecUser & user, co
     bool ok = false;
 
     time_t tctime = getThreadCreateTime();
-    if ((m_permissionsCache.isCacheEnabled() || (m_permissionsCache.isTransactionalEnabled() && tctime > 0)) && (!m_cache_off[rtype]))
+    if ((m_permissionsCache->isCacheEnabled() || (m_permissionsCache->isTransactionalEnabled() && tctime > 0)) && (!m_cache_off[rtype]))
     {
         bool* cached_found = (bool*)alloca(nResources*sizeof(bool));
-        int nFound = m_permissionsCache.lookup(user, rlist, cached_found);
+        int nFound = m_permissionsCache->lookup(user, rlist, cached_found);
         if (nFound < nResources)
         {
             IArrayOf<ISecResource> rlist2;
@@ -801,7 +809,7 @@ int CLdapSecManager::getAccessFlagsEx(SecResourceType rtype, ISecUser & user, co
 
             ok = m_ldap_client->authorize(rtype, user, rlist2);
             if (ok)
-                m_permissionsCache.add(user, rlist2);
+                m_permissionsCache->add(user, rlist2);
         }
         else
             ok = true;  
@@ -830,14 +838,14 @@ int CLdapSecManager::authorizeFileScope(ISecUser & user, const char * filescope)
         return SecAccess_Full;
 
     StringBuffer managedFilescope;
-    if(m_permissionsCache.isCacheEnabled() && !m_usercache_off)
+    if(m_permissionsCache->isCacheEnabled() && !m_usercache_off)
     {
         int accessFlags;
         //See if file scope in question is managed by LDAP permissions.
         //  If not, return default file permission (dont call out to LDAP)
         //  If is, look in cache for permission of longest matching managed scope strings. If found return that permission (no call to LDAP),
         //  otherwise a call to LDAP "authorizeFileScope" is necessary, specifying the longest matching managed scope string
-        bool gotPerms = m_permissionsCache.queryPermsManagedFileScope(user, filescope, managedFilescope, &accessFlags);
+        bool gotPerms = m_permissionsCache->queryPermsManagedFileScope(user, filescope, managedFilescope, &accessFlags);
         if (gotPerms)
             return accessFlags;
     }
@@ -1114,9 +1122,9 @@ bool CLdapSecManager::updateUserPassword(ISecUser& user, const char* newPassword
 
     //Update password if authenticated
     bool ok = m_ldap_client->updateUserPassword(user, newPassword, currPassword);
-    if(ok && m_permissionsCache.isCacheEnabled() && !m_usercache_off)
+    if(ok && m_permissionsCache->isCacheEnabled() && !m_usercache_off)
     {
-        m_permissionsCache.removeFromUserCache(user);
+        m_permissionsCache->removeFromUserCache(user);
     }
     return ok;
 }
@@ -1124,8 +1132,8 @@ bool CLdapSecManager::updateUserPassword(ISecUser& user, const char* newPassword
 bool CLdapSecManager::updateUser(const char* type, ISecUser& user)
 {
     bool ok = m_ldap_client->updateUser(type, user);
-    if(ok && m_permissionsCache.isCacheEnabled() && !m_usercache_off)
-        m_permissionsCache.removeFromUserCache(user);
+    if(ok && m_permissionsCache->isCacheEnabled() && !m_usercache_off)
+        m_permissionsCache->removeFromUserCache(user);
 
     return ok;
 }
@@ -1197,8 +1205,8 @@ void CLdapSecManager::deleteResource(SecResourceType rtype, const char * name, c
     m_ldap_client->deleteResource(rtype, name, basedn);
 
     time_t tctime = getThreadCreateTime();
-    if ((m_permissionsCache.isCacheEnabled() || (m_permissionsCache.isTransactionalEnabled() && tctime > 0)) && (!m_cache_off[rtype]))
-        m_permissionsCache.remove(rtype, name);
+    if ((m_permissionsCache->isCacheEnabled() || (m_permissionsCache->isTransactionalEnabled() && tctime > 0)) && (!m_cache_off[rtype]))
+        m_permissionsCache->remove(rtype, name);
 }
 
 void CLdapSecManager::renameResource(SecResourceType rtype, const char * oldname, const char * newname, const char * basedn)
@@ -1206,8 +1214,8 @@ void CLdapSecManager::renameResource(SecResourceType rtype, const char * oldname
     m_ldap_client->renameResource(rtype, oldname, newname, basedn);
 
     time_t tctime = getThreadCreateTime();
-    if ((m_permissionsCache.isCacheEnabled() || (m_permissionsCache.isTransactionalEnabled() && tctime > 0)) && (!m_cache_off[rtype]))
-        m_permissionsCache.remove(rtype, oldname);
+    if ((m_permissionsCache->isCacheEnabled() || (m_permissionsCache->isTransactionalEnabled() && tctime > 0)) && (!m_cache_off[rtype]))
+        m_permissionsCache->remove(rtype, oldname);
 }
 
 void CLdapSecManager::copyResource(SecResourceType rtype, const char * oldname, const char * newname, const char * basedn)
@@ -1285,7 +1293,7 @@ int CLdapSecManager::queryDefaultPermission(ISecUser& user)
 
 bool CLdapSecManager::clearPermissionsCache(ISecUser& user)
 {
-    if(m_permissionsCache.isCacheEnabled())
+    if(m_permissionsCache->isCacheEnabled())
     {
         if (!authenticate(&user))
         {
@@ -1297,7 +1305,7 @@ bool CLdapSecManager::clearPermissionsCache(ISecUser& user)
             PROGLOG("User %s denied, only a superuser can clear permissions cache", user.getName());
             return false;
         }
-        m_permissionsCache.flush();
+        m_permissionsCache->flush();
     }
     return true;
 }

+ 1 - 1
system/security/LdapSecurity/ldapsecurity.ipp

@@ -335,7 +335,7 @@ private:
     IUserArray m_user_array;
     Monitor m_monitor;
     Owned<IProperties> m_extraparams;
-    CPermissionsCache m_permissionsCache;
+    CPermissionsCache * m_permissionsCache;
     bool m_cache_off[RT_SCOPE_MAX];
     bool m_usercache_off;
     bool authenticate(ISecUser* user);

+ 18 - 6
system/security/shared/caching.cpp

@@ -73,8 +73,9 @@ int CResPermissionsCache::lookup( IArrayOf<ISecResource>& resources, bool* pFoun
             *pFound++ = false;
             continue;
         }
-        //DBGLOG("CACHE: Looking up %s:%s", m_user.c_str(), resource);
-
+#ifdef _DEBUG
+        DBGLOG("CACHE: Looking up resource(%d) %s:%s", i, m_user.c_str(), resource);
+#endif
         MapResAccess::iterator it = m_resAccessMap.find(SecCacheKeyEntry(resource, secResource.getResourceType()));
         if (it != m_resAccessMap.end())//exists in cache
         {
@@ -93,6 +94,9 @@ int CResPermissionsCache::lookup( IArrayOf<ISecResource>& resources, bool* pFoun
                 else
                 {
                     secResource.copy(resParamCacheEntry.second);
+#ifdef _DEBUG
+                    DBGLOG("CACHE: FoundA %s:%s=>%d", m_user.c_str(), resource, ((ISecResource*)resParamCacheEntry.second)->getAccessFlags());
+#endif
                     *pFound++ = true;
                     nFound++;
                 }
@@ -100,7 +104,9 @@ int CResPermissionsCache::lookup( IArrayOf<ISecResource>& resources, bool* pFoun
             else
             {
                 secResource.copy(resParamCacheEntry.second);
-                //DBGLOG("CACHE: Found %s:%s=>%d", m_user.c_str(), resource, resParamCacheEntry.second);
+#ifdef _DEBUG
+                DBGLOG("CACHE: FoundB %s:%s=>%d", m_user.c_str(), resource, ((ISecResource*)resParamCacheEntry.second)->getAccessFlags());
+#endif
                 *pFound++ = true;
                 nFound++;
             }
@@ -154,7 +160,9 @@ void CResPermissionsCache::add( IArrayOf<ISecResource>& resources )
             }
             m_resAccessMap.erase(SecCacheKeyEntry(resource, resourcetype));
         }
-        //DBGLOG("CACHE: Adding %s:%s(%d)", m_user.c_str(), resource, permissions);
+#ifdef _DEBUG
+        DBGLOG("CACHE: Adding %s:%s(%d)", m_user.c_str(), resource, permissions);
+#endif
         m_resAccessMap.insert( pair<SecCacheKeyEntry, ResPermCacheEntry>(SecCacheKeyEntry(resource, resourcetype),  ResPermCacheEntry(tstamp, secResource->clone())));
         m_timestampMap.insert( pair<time_t, SecCacheKeyEntry>(tstamp, SecCacheKeyEntry(resource, resourcetype)));
     }
@@ -222,9 +230,11 @@ int CPermissionsCache::lookup( ISecUser& sec_user, IArrayOf<ISecResource>& resou
     {
         nFound = 0;
         memset(pFound, 0, sizeof(bool)*resources.ordinality());
-        //DBGLOG("CACHE: Looking up %s:*", userId);
     }
 
+#ifdef _DEBUG
+    DBGLOG("CACHE: Looking up resources for %s:*, found %d matches", userId, nFound);
+#endif
     return nFound;
 }
 
@@ -239,7 +249,9 @@ void CPermissionsCache::add( ISecUser& sec_user, IArrayOf<ISecResource>& resourc
 
     if (i == m_resPermissionsMap.end())
     {
-        //DBGLOG("CACHE: Adding cache for %s", user);
+#ifdef _DEBUG
+        DBGLOG("CACHE: Adding resources to cache for %s", user);
+#endif
         pResPermissionsCache = new CResPermissionsCache(this, user);
         m_resPermissionsMap.insert(pair<string, CResPermissionsCache*>(user, pResPermissionsCache));
     }

+ 17 - 3
system/security/shared/caching.hpp

@@ -134,19 +134,34 @@ public:
 
 // main cache that stores all user-specific caches (defined by CResPermissionsCache above)
 //
+static CriticalSection PCCritSect;//guards instance factory
+static CPermissionsCache* instance = nullptr;//accessed via CPermissionsCache::queryInstance()
 class CPermissionsCache
 {
 public:
     CPermissionsCache()
-    { 
+    {
         m_cacheTimeout = 300;
         m_transactionalEnabled = false;
         m_secMgr = NULL;
         m_lastManagedFileScopesRefresh = 0;
         m_defaultPermission = SecAccess_Unknown;
     }
+
     virtual ~CPermissionsCache();
 
+    static CPermissionsCache* queryInstance()
+    {
+        {
+            CriticalBlock block(PCCritSect);
+            if (instance == nullptr)
+            {
+                instance = new CPermissionsCache();
+            }
+        }
+        return instance;
+    }
+
     //finds cached permissions for a number of resources and sets them in
     //and also returns status in the boolean array passed in
     //
@@ -181,8 +196,6 @@ private:
     typedef std::map<string, CResPermissionsCache*> MapResPermissionsCache;
     typedef std::map<string, CachedUser*> MapUserCache;
 
-    CPermissionsCache(const CPermissionsCache&);
-
     MapResPermissionsCache m_resPermissionsMap;  //user specific resource permissions cache
     Monitor m_cachemonitor;                               //for thread safety
     int m_cacheTimeout; //cleanup cycle period
@@ -202,4 +215,5 @@ private:
 
 time_t getThreadCreateTime();
 
+
 #endif