Browse Source

Report "ESP Password Expired" to user

If a user's password is expired, report that error to the user instead of
misleading "Invalid Credentials" error.

Signed-off-by: William Whitehead <william.whitehead@lexisnexis.com>
William Whitehead 13 years ago
parent
commit
33c8b3b61f

+ 4 - 1
esp/bindings/http/platform/httpbinding.cpp

@@ -551,7 +551,10 @@ bool EspHttpBinding::basicAuth(IEspContext* ctx)
     bool authenticated = m_secmgr->authorize(*user, rlist);
     if(!authenticated)
     {
-        ctx->AuditMessage(AUDIT_TYPE_ACCESS_FAILURE, "Authentication", "Access Denied: User or password invalid", NULL);
+        if (user->getAuthenticateStatus() == AS_PASSWORD_EXPIRED)
+            ctx->AuditMessage(AUDIT_TYPE_ACCESS_FAILURE, "Authentication", "ESP password is expired", NULL);
+        else
+            ctx->AuditMessage(AUDIT_TYPE_ACCESS_FAILURE, "Authentication", "Access Denied: User or password invalid", NULL);
         return false;
     }
     bool authorized = true;

+ 33 - 10
esp/bindings/http/platform/httpservice.cpp

@@ -173,8 +173,19 @@ bool CEspHttpServer::rootAuth(IEspContext* ctx)
             ret=true;
         else
         {
-            DBGLOG("User authentication required");
-            m_response->sendBasicChallenge(thebinding->getChallengeRealm(), true);
+            ISecUser *user = ctx->queryUser();
+            if (user && user->getAuthenticateStatus() == AS_PASSWORD_EXPIRED)
+            {
+                DBGLOG("ESP password expired for %s", user->getName());
+                m_response->setContentType(HTTP_TYPE_TEXT_PLAIN);
+                m_response->setContent("Your ESP password has expired");
+                m_response->send();
+            }
+            else
+            {
+                DBGLOG("User authentication required");
+                m_response->sendBasicChallenge(thebinding->getChallengeRealm(), true);
+            }
         }
     }
 
@@ -422,16 +433,28 @@ int CEspHttpServer::processRequest()
                     
             if (authState==authRequired)
             {
-                DBGLOG("User authentication required");
-                StringBuffer realmbuf;
-                if(thebinding)
-                    realmbuf.append(thebinding->getChallengeRealm());
-                if(realmbuf.length() == 0)
-                    realmbuf.append("ESP");
-                m_response->sendBasicChallenge(realmbuf.str(), !isSoapPost);
+                ISecUser *user = ctx->queryUser();
+                if (user && user->getAuthenticateStatus() == AS_PASSWORD_EXPIRED)
+                {
+                    DBGLOG("ESP password expired for %s", user->getName());
+                    m_response->setContentType(HTTP_TYPE_TEXT_PLAIN);
+                    m_response->setContent("Your ESP password has expired");
+                    m_response->send();
+                }
+                else
+                {
+                    DBGLOG("User authentication required");
+                    StringBuffer realmbuf;
+                    if(thebinding)
+                        realmbuf.append(thebinding->getChallengeRealm());
+                    if(realmbuf.length() == 0)
+                        realmbuf.append("ESP");
+                    m_response->sendBasicChallenge(realmbuf.str(), !isSoapPost);
+                    break;
+                }
                 return 0;
             }
-                        
+
             // authenticate optional groups
             if (authenticateOptionalFailed(*ctx,thebinding))
                 throw createEspHttpException(401,"Unauthorized Access","Unauthorized Access");

+ 1 - 1
esp/services/ws_access/ws_accessService.cpp

@@ -649,7 +649,7 @@ bool Cws_accessEx::onAddUser(IEspContext &context, IEspAddUserRequest &req, IEsp
             resp.setRetmsg("username can't be empty");
             return false;
         }
-        if(strchr(username, (int)' '))
+        if(strchr(username, ' '))
         {
             resp.setRetcode(-1);
             resp.setRetmsg("Username can't contain spaces");

+ 1 - 1
esp/services/ws_account/ws_accountService.cpp

@@ -189,7 +189,7 @@ bool Cws_accountEx::onVerifyUser(IEspContext &context, IEspVerifyUserRequest &re
     try
     {
         ISecUser* usr = context.queryUser();
-        if(!usr || !usr->isAuthenticated())
+        if(!usr || usr->getAuthenticateStatus() != AS_AUTHENTICATED)
         {
             resp.setRetcode(-1);
             return false;

+ 19 - 7
system/security/LdapSecurity/ldapconnection.cpp

@@ -998,6 +998,7 @@ public:
             char        *attribute, **values;       
             BerElement  *ber;
             struct berval** bvalues = NULL;
+            user.setAuthenticateStatus(AS_UNEXPECTED_ERROR);//assume the worst
 
             const char* username = user.getName();
             const char* password = user.credentials().getPassword();
@@ -1016,11 +1017,12 @@ public:
                 if(strcmp(password, m_ldapconfig->getSysUserPassword()) == 0)
                 {
                     user.setFullName(m_ldapconfig->getSysUserCommonName());
-                    user.setAuthenticated(true);
+                    user.setAuthenticateStatus(AS_AUTHENTICATED);
                     return true;
                 }
                 else
                 {
+                    user.setAuthenticateStatus(AS_INVALID_CREDENTIALS);
                     return false;
                 }
             }
@@ -1066,6 +1068,7 @@ public:
                 if(result != LDAP_SUCCESS)
                 {
                     DBGLOG("ldap_search_ext_s error: %s, when searching %s under %s", ldap_err2string( result ), filter.str(), m_ldapconfig->getSysUserBasedn());
+                    user.setAuthenticateStatus(AS_INVALID_CREDENTIALS);
                     return false;
                 }
 
@@ -1073,6 +1076,7 @@ public:
                 if(entries == 0)
                 {
                     DBGLOG("LDAP: User %s not found", username);
+                    user.setAuthenticateStatus(AS_INVALID_CREDENTIALS);
                     return false;
                 }
             }
@@ -1104,11 +1108,10 @@ public:
                         user.setLastName(values[0]);
                     ldap_value_free( values );
                 }
-                else if((stricmp(attribute, "userAccountControl") == 0) && (bvalues = ldap_get_values_len(sys_ld, entry, attribute)) != NULL )
+                else if((stricmp(attribute, "userAccountControl") == 0) && ( values = ldap_get_values( sys_ld, entry, attribute))  != NULL )
                 {
-                    struct berval* val = bvalues[0];
-//                  //UF_DONT_EXPIRE_PASSWD 0x10000
-                    if (atoi(val->bv_val) & 0x10000)//this can be true at the account level, even if domain policy requires password
+                    //UF_DONT_EXPIRE_PASSWD 0x10000
+                    if (atoi((char*)values[0]) & 0x10000)//this can be true at the account level, even if domain policy requires password
                         m_passwordNeverExpires = true;
                     ldap_value_free( values );
                 }
@@ -1202,10 +1205,19 @@ public:
             }
             if(rc != LDAP_SUCCESS)
             {
-                DBGLOG("LDAP: Authentication for user %s failed - %s", username, ldap_err2string(rc));
+                if (user.getPasswordDaysRemaining() == -1)
+                {
+                    DBGLOG("ESP Password Expired for user %s", username);
+                    user.setAuthenticateStatus(AS_PASSWORD_EXPIRED);
+                }
+                else
+                {
+                    DBGLOG("LDAP: Authentication for user %s failed - %s", username, ldap_err2string(rc));
+                    user.setAuthenticateStatus(AS_INVALID_CREDENTIALS);
+                }
                 return false;
             }
-            user.setAuthenticated(true);
+            user.setAuthenticateStatus(AS_AUTHENTICATED);
         }
         //Always retrieve user info(SID, UID, fullname, etc) for Active Directory, when the user first logs in.
         if((m_ldapconfig->getServerType() == ACTIVE_DIRECTORY) && (m_pp != NULL))

+ 6 - 16
system/security/LdapSecurity/ldapsecurity.cpp

@@ -29,9 +29,9 @@
  *     CLdapSecUser                                       *
  **********************************************************/
 CLdapSecUser::CLdapSecUser(const char *name, const char *pw) : 
-    m_pw(pw), m_isAuthenticated(false)
+    m_pw(pw), m_authenticateStatus(AS_UNKNOWN)
 {
-    setName(name);  
+    setName(name);
 }
 
 CLdapSecUser::~CLdapSecUser()
@@ -39,10 +39,6 @@ CLdapSecUser::~CLdapSecUser()
 }
 
 //non-interfaced functions
-void CLdapSecUser::setAuthenticated(bool authenticated)
-{
-    m_isAuthenticated = authenticated;
-}
 void CLdapSecUser::setUserID(unsigned userid)
 {
     m_userid = userid;
@@ -156,12 +152,6 @@ bool CLdapSecUser::setPeer(const char *Peer)
 }
 
 
-bool CLdapSecUser::isAuthenticated()
-{
-    return m_isAuthenticated;
-}
-
-
 ISecCredentials & CLdapSecUser::credentials()
 {
     return *this;
@@ -201,7 +191,7 @@ void CLdapSecUser::copyTo(ISecUser& destination)
     if(!dest)
         return;
 
-    dest->setAuthenticated(isAuthenticated());
+    dest->setAuthenticateStatus(getAuthenticateStatus());
     dest->setName(getName());
     dest->setFullName(getFullName());
     dest->setFirstName(getFirstName());
@@ -585,12 +575,12 @@ bool CLdapSecManager::authenticate(ISecUser* user)
     if(!user)
         return false;
 
-    if(user->isAuthenticated())
+    if(user->getAuthenticateStatus() == AS_AUTHENTICATED)
         return true;
 
     if(m_permissionsCache.isCacheEnabled() && !m_usercache_off && m_permissionsCache.lookup(*user))
     {
-        user->setAuthenticated(true);
+        user->setAuthenticateStatus(AS_AUTHENTICATED);
         return true;
     }
 
@@ -600,7 +590,7 @@ bool CLdapSecManager::authenticate(ISecUser* user)
         if(m_permissionsCache.isCacheEnabled() && !m_usercache_off)
             m_permissionsCache.add(*user);
 
-        user->setAuthenticated(true);
+        user->setAuthenticateStatus(AS_AUTHENTICATED);
     }
 
     return ok;

+ 4 - 3
system/security/LdapSecurity/ldapsecurity.ipp

@@ -45,7 +45,7 @@ private:
     StringAttr   m_pw;
     StringAttr   m_Fqdn;
     StringAttr   m_Peer;
-    bool         m_isAuthenticated;
+    authStatus   m_authenticateStatus;
     CDateTime    m_passwordExpiration;//local time
     unsigned     m_userid;
     MemoryBuffer m_usersid;
@@ -70,7 +70,6 @@ public:
     virtual ~CLdapSecUser();
 
 //non-interfaced functions
-    virtual void setAuthenticated(bool authenticated);
     void setUserID(unsigned userid);
     void setUserSid(int sidlen, const char* sid);
     MemoryBuffer& getUserSid();
@@ -85,7 +84,6 @@ public:
     virtual bool setLastName(const char * lname);
     const char * getRealm();
     bool setRealm(const char * name);
-    bool isAuthenticated();
     ISecCredentials & credentials();
     virtual unsigned getUserID();
     virtual void copyTo(ISecUser& source);
@@ -131,6 +129,9 @@ public:
        return numDays;
    }
 
+   authStatus getAuthenticateStatus()           { return m_authenticateStatus; }
+   void setAuthenticateStatus(authStatus status){ m_authenticateStatus = status; }
+
    ISecUser * clone();
     virtual void setProperty(const char* name, const char* value){}
     virtual const char* getProperty(const char* name){ return "";}

+ 5 - 14
system/security/shared/SecureUser.hpp

@@ -32,7 +32,7 @@ private:
     StringBuffer    m_name;
     StringBuffer    m_pw;
     StringBuffer    m_encodedPw;
-    bool            m_isAuthenticated;
+    authStatus      m_authenticateStatus;
     StringBuffer    m_fullname;
     StringBuffer    m_firstname;
     StringBuffer    m_lastname;
@@ -47,7 +47,7 @@ public:
     IMPLEMENT_IINTERFACE
 
     CSecureUser(const char *name, const char *pw) : 
-        m_name(name), m_pw(pw), m_isAuthenticated(false),m_userID(0), m_status(SecUserStatus_Unknown)
+        m_name(name), m_pw(pw), m_authenticateStatus(AS_UNKNOWN), m_userID(0), m_status(SecUserStatus_Unknown)
     {
     }
 
@@ -55,11 +55,6 @@ public:
     {
     }
 
-    virtual void setAuthenticated(bool authenticated)
-    {
-        m_isAuthenticated = authenticated;
-    }
-
 //interface ISecUser
     const char * getName()
     {
@@ -148,11 +143,6 @@ public:
         return true;
     }
 
-    bool isAuthenticated()
-    {
-        return m_isAuthenticated;
-    }
-
     ISecCredentials & credentials()
     {
         return *this;
@@ -212,10 +202,12 @@ public:
     virtual CDateTime & getPasswordExpiration(CDateTime& expirationDate){ assertex(false); return expirationDate; }
     virtual bool setPasswordExpiration(CDateTime& expirationDate) { assertex(false);return true; }
     virtual int getPasswordDaysRemaining() {assertex(false);return -1;}
+    virtual authStatus getAuthenticateStatus() {return m_authenticateStatus;}
+    virtual void setAuthenticateStatus(authStatus status){m_authenticateStatus = status;}
 
     virtual void copyTo(ISecUser& destination)
     {
-        destination.setAuthenticated(isAuthenticated());
+        destination.setAuthenticateStatus(getAuthenticateStatus());
         destination.setName(getName());
         destination.setFullName(getFullName());
         destination.setFirstName(getFirstName());
@@ -227,7 +219,6 @@ public:
         CDateTime tmpTime;
         destination.setPasswordExpiration(getPasswordExpiration(tmpTime));
         destination.setStatus(getStatus());
-
         if(m_parameters.get()==NULL)
             return;
         CriticalBlock b(crit);

+ 5 - 5
system/security/shared/basesecurity.cpp

@@ -138,7 +138,7 @@ bool CBaseSecurityManager::unsubscribe(ISecAuthenticEvents & events)
 
 bool CBaseSecurityManager::authorize(ISecUser & sec_user, ISecResourceList * Resources)
 {   
-    if(!sec_user.isAuthenticated())
+    if(sec_user.getAuthenticateStatus() != AS_AUTHENTICATED)
     {
         bool bOk = ValidateUser(sec_user);
         if(bOk == false)
@@ -389,7 +389,7 @@ bool CBaseSecurityManager::ValidateUser(ISecUser & sec_user)
             {
                 //we seem to be coming from a different peer... this is not good
                 WARNLOG("Found user %d in cache, but have to re-validate IP, because it was coming from %s but is now coming from %s",sec_user.getUserID(), cachedclientip, clientip.str());
-                sec_user.setAuthenticated(false);
+                sec_user.setAuthenticateStatus(AS_INVALID_CREDENTIALS);
                 sec_user.setPeer(clientip.str());
                 m_permissionsCache.removeFromUserCache(sec_user);
                 bReturn =  false;
@@ -411,7 +411,7 @@ bool CBaseSecurityManager::ValidateUser(ISecUser & sec_user)
 
         if(bReturn)
         {
-            sec_user.setAuthenticated(true);
+            sec_user.setAuthenticateStatus(AS_AUTHENTICATED);
             return true;
         }
     }
@@ -428,13 +428,13 @@ bool CBaseSecurityManager::ValidateUser(ISecUser & sec_user)
             if(ValidateSourceIP(sec_user,m_safeIPList)==false)
             {
                 ERRLOG("IP check failed for user:%s coming from %s",sec_user.getName(),sec_user.getPeer());
-                sec_user.setAuthenticated(false);
+                sec_user.setAuthenticateStatus(AS_INVALID_CREDENTIALS);
                 return false;
             }
         }
         if(m_permissionsCache.isCacheEnabled())
             m_permissionsCache.add(sec_user);
-        sec_user.setAuthenticated(true);
+        sec_user.setAuthenticateStatus(AS_AUTHENTICATED);
     }
     return true;
 }

+ 11 - 2
system/security/shared/seclib.hpp

@@ -131,6 +131,15 @@ interface ISecCredentials : extends IInterface
     virtual int getPasswordDaysRemaining() = 0;
 };
 
+//LDAP authentication status
+enum authStatus
+{
+    AS_AUTHENTICATED = 0,
+    AS_UNKNOWN = 1,//have not attempted to authenticate
+    AS_UNEXPECTED_ERROR = 2,
+    AS_INVALID_CREDENTIALS = 3,
+    AS_PASSWORD_EXPIRED = 4
+};
 
 class CDateTime;
 interface ISecUser : extends IInterface
@@ -151,8 +160,8 @@ interface ISecUser : extends IInterface
     virtual bool setPeer(const char * Peer) = 0;
     virtual SecUserStatus getStatus() = 0;
     virtual bool setStatus(SecUserStatus Status) = 0;
-    virtual bool isAuthenticated() = 0;
-    virtual void setAuthenticated(bool authenticated) = 0;
+    virtual authStatus getAuthenticateStatus() = 0;
+    virtual void setAuthenticateStatus(authStatus status) = 0;
     virtual ISecCredentials & credentials() = 0;
     virtual unsigned getUserID() = 0;
     virtual void copyTo(ISecUser & destination) = 0;