فهرست منبع

Merge pull request #11021 from RussWhitehead/userAuth

HPCC-19261 Authentication should include digital signature check

Reviewed-By: Kevin Wang <kevin.wang@lexisnexis.com>
Reviewed-By: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman 7 سال پیش
والد
کامیت
bfba7d000b

+ 2 - 0
system/security/LdapSecurity/CMakeLists.txt

@@ -41,6 +41,7 @@ set (    SRCS
 include_directories ( 
          ./../../include 
          ./../shared 
+         ./../digisign
          ./../../jlib 
          ./../../../esp/platform 
 	     ./../../../dali/base
@@ -54,6 +55,7 @@ HPCC_ADD_LIBRARY( LdapSecurity SHARED ${SRCS} )
 install ( TARGETS LdapSecurity RUNTIME DESTINATION ${EXEC_DIR} LIBRARY DESTINATION ${LIB_DIR} )
 target_link_libraries ( LdapSecurity
          jlib
+         digisign
          dalibase
          ${OPENLDAP_LIBRARIES}
     )

+ 49 - 15
system/security/LdapSecurity/ldapsecurity.cpp

@@ -20,6 +20,7 @@
 #include "ldapsecurity.ipp"
 #include "ldapsecurity.hpp"
 #include "authmap.ipp"
+#include "digisign.hpp"
 
 /**********************************************************
  *     CLdapSecUser                                       *
@@ -33,6 +34,7 @@ CLdapSecUser::CLdapSecUser(const char *name, const char *pw) :
     setSudoersEnabled(false);
     setInSudoers(false);
     setSessionToken(0);
+    setSignature(nullptr);
 }
 
 CLdapSecUser::~CLdapSecUser()
@@ -654,32 +656,66 @@ bool CLdapSecManager::authenticate(ISecUser* user)
         return false;
     }
 
-    if(user->getAuthenticateStatus() == AS_AUTHENTICATED)
-        return true;
+    user->setAuthenticateStatus(AS_UNKNOWN);
 
-    if(m_permissionsCache->isCacheEnabled() && !m_usercache_off && m_permissionsCache->lookup(*user))
+    bool isCaching = m_permissionsCache->isCacheEnabled() && !m_usercache_off;//caching enabled?
+    bool isUserCached = false;
+    Owned<ISecUser> cachedUser = new CLdapSecUser(user->getName(), "");
+    if(isCaching)
     {
-        user->setAuthenticateStatus(AS_AUTHENTICATED);
-        return true;
+        user->copyTo(*(cachedUser.get()));//copy user to cachedUser
+        isUserCached = m_permissionsCache->lookup(*cachedUser);//populate cachedUser with cached values
     }
 
-    if ((user->credentials().getSessionToken() != 0) || !isEmptyString(user->credentials().getSignature()))//Already authenticated it token or signature exist
+    //Verify provided signature if present
+    IDigitalSignatureManager * pDSM = createDigitalSignatureManagerInstanceFromEnv();
+    if (pDSM && pDSM->isDigiVerifierConfigured() && !isEmptyString(user->credentials().getSignature()))
+    {
+        StringBuffer b64Signature(user->credentials().getSignature());
+        if (!pDSM->digiVerify(user->getName(), b64Signature))//digital signature valid?
+        {
+            user->setAuthenticateStatus(AS_INVALID_CREDENTIALS);
+            WARNLOG("Invalid digital signature for user %s", user->getName());
+            return false;
+        }
+        else
+        {
+            user->setAuthenticateStatus(AS_AUTHENTICATED);
+            if(isCaching && !isUserCached)
+                m_permissionsCache->add(*user);
+            return true;
+        }
+    }
+
+    if (isUserCached && cachedUser->getAuthenticateStatus() == AS_AUTHENTICATED)//only authenticated users will be cached
     {
-        user->setAuthenticateStatus(AS_AUTHENTICATED);
-        if(m_permissionsCache->isCacheEnabled() && !m_usercache_off)
-            m_permissionsCache->add(*user);
         return true;
     }
 
-    bool ok = m_ldap_client->authenticate(*user);
-    if(ok)
+    //User not in cache. Look for session token, or call LDAP to authenticate
+
+    if (0 != user->credentials().getSessionToken())//check for token existence
     {
         user->setAuthenticateStatus(AS_AUTHENTICATED);
-        if(m_permissionsCache->isCacheEnabled() && !m_usercache_off)
+    }
+    else if (m_ldap_client->authenticate(*user)) //call LDAP to authenticate
+        user->setAuthenticateStatus(AS_AUTHENTICATED);
+
+    if (AS_AUTHENTICATED == user->getAuthenticateStatus())
+    {
+        if (pDSM && pDSM->isDigiSignerConfigured() && isEmptyString(user->credentials().getSignature()))
+        {
+            //Set user digital signature
+            StringBuffer b64Signature;
+            pDSM->digiSign(user->getName(), b64Signature);
+            user->credentials().setSignature(b64Signature);
+        }
+
+        if (isCaching)
             m_permissionsCache->add(*user);
     }
 
-    return ok;
+    return AS_AUTHENTICATED == user->getAuthenticateStatus();
 }
 
 bool CLdapSecManager::authorizeEx(SecResourceType rtype, ISecUser& sec_user, ISecResourceList * Resources, IEspSecureContext* secureContext)
@@ -1453,8 +1489,6 @@ bool CLdapSecManager::logoutUser(ISecUser & user)
     return true;
 }
 
-
-
 //Data View related interfaces
 void CLdapSecManager::createView(const char* viewName, const char * viewDescription)
 {

+ 1 - 0
system/security/digisign/digisign.cpp

@@ -18,6 +18,7 @@
 #ifdef _USE_OPENSSL
 #include <openssl/pem.h>
 #include <openssl/err.h>
+#include <openssl/evp.h>
 #endif
 #include "jencrypt.hpp"
 #include "digisign.hpp"

+ 1 - 1
system/security/digisign/digisign.hpp

@@ -41,7 +41,7 @@ public:
 extern "C"
 {
     //Uses the HPCCPublicKey/HPCCPrivateKey key files specified in environment.conf
-    DIGISIGN_API IDigitalSignatureManager * staticDigitalSignatureManagerInstance();
+    DIGISIGN_API IDigitalSignatureManager * createDigitalSignatureManagerInstanceFromEnv();
 
     //Create using the given key files
     DIGISIGN_API IDigitalSignatureManager * createDigitalSignatureManagerInstanceFromFiles(const char * _pubKey, const char *_privKey, const char * _passPhrase);

+ 1 - 1
system/security/plugins/htpasswdSecurity/htpasswdSecurity.cpp

@@ -158,7 +158,7 @@ protected:
 		if (0 == user.length())
 			throw MakeStringException(-1, "htpasswd User name is NULL");
 
-        if (sec_user.credentials().getSessionToken() != 0  || !isEmptyString(sec_user.credentials().getSignature()))//Already authenticated it token or signature exist
+        if (sec_user.credentials().getSessionToken() != 0)//Already authenticated it token
 		    return true;
 
 		CriticalBlock block(crit);