diff --git a/esp/bindings/http/platform/httpbinding.cpp b/esp/bindings/http/platform/httpbinding.cpp index 482e8304f52..33ad63bbd67 100644 --- a/esp/bindings/http/platform/httpbinding.cpp +++ b/esp/bindings/http/platform/httpbinding.cpp @@ -593,6 +593,8 @@ bool EspHttpBinding::basicAuth(IEspContext* ctx) ctx->getUserID(userid); if(userid.length() == 0) { + ctx->setAuthError(EspAuthErrorEmptyUserID); + ctx->AuditMessage(AUDIT_TYPE_ACCESS_FAILURE, "Authentication", "Access Denied: No username provided"); return false; } @@ -603,6 +605,7 @@ bool EspHttpBinding::basicAuth(IEspContext* ctx) if(user == NULL) { WARNLOG("Can't find user in context"); + ctx->setAuthError(EspAuthErrorUserNotFoundInContext); ctx->AuditMessage(AUDIT_TYPE_ACCESS_FAILURE, "Authentication", "Access Denied: No username provided"); return false; } @@ -610,20 +613,29 @@ bool EspHttpBinding::basicAuth(IEspContext* ctx) if(m_secmgr.get() == NULL) { WARNLOG("No mechanism established for authentication"); + ctx->setAuthError(EspAuthErrorNoAuthMechanism); return false; } ISecResourceList* rlist = ctx->queryResources(); if(rlist == NULL) + { + WARNLOG("No Security Resource"); + ctx->setAuthError(EspAuthErrorEmptySecResource); return false; + } bool authenticated = m_secmgr->authorize(*user, rlist, ctx->querySecureContext()); if(!authenticated) { + const char *desc = nullptr; if (user->getAuthenticateStatus() == AS_PASSWORD_EXPIRED || user->getAuthenticateStatus() == AS_PASSWORD_VALID_BUT_EXPIRED) - ctx->AuditMessage(AUDIT_TYPE_ACCESS_FAILURE, "Authentication", "ESP password is expired"); + desc = "ESP password is expired"; else - ctx->AuditMessage(AUDIT_TYPE_ACCESS_FAILURE, "Authentication", "Access Denied: User or password invalid"); + desc = "Access Denied: User or password invalid"; + ctx->AuditMessage(AUDIT_TYPE_ACCESS_FAILURE, "Authentication", desc); + ctx->setAuthError(EspAuthErrorNotAuthenticated); + ctx->setRespMsg(desc); return false; } bool authorized = true; @@ -637,8 +649,11 @@ bool EspHttpBinding::basicAuth(IEspContext* ctx) if(access < required) { const char *desc=curres->getDescription(); - ESPLOG(LogMin, "Access for user '%s' denied to: %s. Access=%d, Required=%d", user->getName(), desc?desc:"", access, required); + VStringBuffer msg("Access for user '%s' denied to: %s. Access=%d, Required=%d", user->getName(), desc?desc:"", access, required); + ESPLOG(LogMin, "%s", msg.str()); ctx->AuditMessage(AUDIT_TYPE_ACCESS_FAILURE, "Authorization", "Access Denied: Not Authorized", "Resource: %s [%s]", curres->getName(), (desc) ? desc : ""); + ctx->setAuthError(EspAuthErrorNotAuthorized); + ctx->setRespMsg(msg.str()); authorized = false; break; } diff --git a/esp/bindings/http/platform/httpservice.cpp b/esp/bindings/http/platform/httpservice.cpp index 0f0e622fcd1..fac81f4c528 100644 --- a/esp/bindings/http/platform/httpservice.cpp +++ b/esp/bindings/http/platform/httpservice.cpp @@ -1201,7 +1201,7 @@ EspAuthState CEspHttpServer::authNewSession(EspAuthRequest& authReq, const char* authReq.ctx->setUserID(_userName); authReq.ctx->setPassword(_password); authReq.authBinding->populateRequest(m_request.get()); - if (!authReq.authBinding->doAuth(authReq.ctx)) + if (!authReq.authBinding->doAuth(authReq.ctx) && (authReq.ctx->getAuthError() != EspAuthErrorNotAuthorized)) { ESPLOG(LogMin, "Authentication failed for %s@%s", _userName, peer.str()); return handleAuthFailed(true, authReq, unlock, "User authentication failed."); @@ -1221,6 +1221,11 @@ EspAuthState CEspHttpServer::authNewSession(EspAuthRequest& authReq, const char* addCookie(SESSION_TIMEOUT_COOKIE, cookieStr.str(), 0, false); clearCookie(SESSION_AUTH_MSG_COOKIE); clearCookie(SESSION_START_URL_COOKIE); + if (authReq.ctx->getAuthError() == EspAuthErrorNotAuthorized) + { + sendAuthorizationMsg(authReq); + return authSucceeded; + } if (unlock) { sendLockResponse(false, false, "Unlocked"); @@ -1231,6 +1236,33 @@ EspAuthState CEspHttpServer::authNewSession(EspAuthRequest& authReq, const char* return authSucceeded; } +void CEspHttpServer::sendAuthorizationMsg(EspAuthRequest& authReq) +{ + StringBuffer resp; + const char* errMsg = authReq.ctx->getRespMsg(); + ESPSerializationFormat format = m_request->queryContext()->getResponseFormat(); + if (format == ESPSerializationJSON) + { + resp.set("{ "); + resp.append(" \"LoginResponse\": { "); + if (isEmptyString(errMsg)) + resp.append("\"Error\": \"Access Denied.\""); + else + resp.appendf("\"Error\": \"%s\"", errMsg); + resp.append(" }"); + resp.append(" }"); + } + else + { + resp.set(""); + resp.append("Access Denied."); + if (!isEmptyString(errMsg)) + resp.append(" ").append(errMsg); + resp.append(""); + } + sendMessage(resp.str(), (format == ESPSerializationJSON) ? "application/json" : "text/xml"); +} + void CEspHttpServer::sendLockResponse(bool lock, bool error, const char* msg) { StringBuffer resp; diff --git a/esp/bindings/http/platform/httpservice.hpp b/esp/bindings/http/platform/httpservice.hpp index 67d051a2bf4..fc51887d982 100644 --- a/esp/bindings/http/platform/httpservice.hpp +++ b/esp/bindings/http/platform/httpservice.hpp @@ -94,6 +94,7 @@ class CEspHttpServer : implements IHttpServerService, public CInterface unsigned readCookie(const char* cookieName); const char* readCookie(const char* cookieName, StringBuffer& cookieValue); void sendLockResponse(bool lock, bool error, const char* msg); + void sendAuthorizationMsg(EspAuthRequest& authReq); void createGetSessionTimeoutResponse(StringBuffer& resp, ESPSerializationFormat format, IPropertyTree* sessionTree); void resetSessionTimeout(EspAuthRequest& authReq, unsigned sessionID, StringBuffer& resp, ESPSerializationFormat format, IPropertyTree* sessionTree); void sendMessage(const char* msg, const char* msgType); diff --git a/esp/platform/espcontext.cpp b/esp/platform/espcontext.cpp index eaf64dbbc2d..f95b7c9e991 100755 --- a/esp/platform/espcontext.cpp +++ b/esp/platform/espcontext.cpp @@ -78,8 +78,10 @@ class CEspContext : public CInterface, implements IEspContext unsigned m_exceptionTime; bool m_hasException; int m_exceptionCode; + StringAttr respMsg; StringAttr authenticationMethod; AuthType domainAuthType; + AuthError authError = EspAuthErrorNone; ESPSerializationFormat respSerializationFormat; @@ -523,6 +525,17 @@ class CEspContext : public CInterface, implements IEspContext virtual void setDomainAuthType(AuthType type) { domainAuthType = type; } virtual AuthType getDomainAuthType(){ return domainAuthType; } + virtual void setAuthError(AuthError error) { authError = error; } + virtual AuthError getAuthError(){ return authError; } + virtual void setRespMsg(const char* msg) + { + respMsg.set(msg); + } + + virtual const char* getRespMsg() + { + return respMsg.get(); + } virtual ESPSerializationFormat getResponseFormat(){return respSerializationFormat;} virtual void setResponseFormat(ESPSerializationFormat fmt){respSerializationFormat = fmt;} diff --git a/esp/scm/esp.ecm b/esp/scm/esp.ecm index bb0de261631..c1416cbdcc2 100755 --- a/esp/scm/esp.ecm +++ b/esp/scm/esp.ecm @@ -63,6 +63,17 @@ typedef enum AuthType_ AuthUserNameOnly } AuthType; +typedef enum AuthError_ +{ + EspAuthErrorNone, + EspAuthErrorEmptyUserID, + EspAuthErrorUserNotFoundInContext, + EspAuthErrorNoAuthMechanism, + EspAuthErrorEmptySecResource, + EspAuthErrorNotAuthenticated, + EspAuthErrorNotAuthorized +} AuthError; + #define ESPCTX_NO_NAMESPACES 0x00000001 #define ESPCTX_WSDL 0x00000010 #define ESPCTX_WSDL_EXT 0x00000100 @@ -186,6 +197,10 @@ interface IEspContext : extends IInterface virtual void setAuthenticationMethod(const char * method)=0; virtual void setDomainAuthType(AuthType type)=0; virtual AuthType getDomainAuthType()=0; + virtual void setAuthError(AuthError error)=0; + virtual AuthError getAuthError()=0; + virtual const char * getRespMsg()=0; + virtual void setRespMsg(const char * msg)=0; };