浏览代码

HPCC-14493 Cross domaing scripting of ESP API

Adds CORS interoperability to ESP, but only for interoperability with
cross domain browser calls.  We do not treat the browser as a trusted
entity or rely on it to make security decisions for us.

Since we implement general purpose APIs and not just scripted pages
we need to be diligent and secure for every request whether it comes
from a cross domain browser, a REST or SOAP client, or any other source.

Signed-off-by: Anthony Fishbeck <anthony.fishbeck@lexisnexis.com>
Anthony Fishbeck 8 年之前
父节点
当前提交
a375617fed

+ 44 - 1
esp/bindings/http/platform/httpservice.cpp

@@ -215,6 +215,18 @@ EspHttpBinding* CEspHttpServer::getBinding()
     return thebinding;
 }
 
+//CORS allow headers for interoperability, we do not rely on this for security since
+//that only means treating the browser as a trusted entity.  We need to be diligent and secure
+//for every request whether it comes from a cross domain browser or any other source
+
+void checkSetCORSAllowOrigin(CHttpRequest *req, CHttpResponse *resp)
+{
+    StringBuffer origin;
+    req->getHeader("Origin", origin);
+    if (origin.length())
+        resp->setHeader("Access-Control-Allow-Origin", "*");
+}
+
 int CEspHttpServer::processRequest()
 {
     try
@@ -312,6 +324,8 @@ int CEspHttpServer::processRequest()
 #endif
                 if (!rootAuth(ctx) )
                     return 0;
+
+                checkSetCORSAllowOrigin(m_request, m_response);
                 if (methodName.charAt(methodName.length()-1)=='_')
                     methodName.setCharAt(methodName.length()-1, 0);
                 if (!stricmp(methodName.str(), "files"))
@@ -405,7 +419,7 @@ int CEspHttpServer::processRequest()
                         authState = authSucceeded;
                 }
             }
-                    
+
             if (authState==authRequired)
             {
                 ISecUser *user = ctx->queryUser();
@@ -433,6 +447,12 @@ int CEspHttpServer::processRequest()
             if (authenticateOptionalFailed(*ctx,thebinding))
                 throw createEspHttpException(401,"Unauthorized Access","Unauthorized Access");
 
+
+            if(strieq(method.str(), OPTIONS_METHOD))
+                return onOptions();
+
+            checkSetCORSAllowOrigin(m_request, m_response);
+
             if (thebinding!=NULL)
             {
                 if(stricmp(method.str(), POST_METHOD)==0)
@@ -854,6 +874,29 @@ int CEspHttpServer::unsupported()
     return 0;
 }
 
+int CEspHttpServer::onOptions()
+{
+    m_response->setVersion(HTTP_VERSION);
+    m_response->setStatus(HTTP_STATUS_OK);
+
+    //CORS allow headers for interoperability, we do not rely on this for security since
+    //that only means treating the browser as a trusted entity.  We need to be diligent and secure
+    //for every request whether it comes from a cross domain browser or any other source
+    StringBuffer allowHeaders;
+    m_request->getHeader("Access-Control-Request-Headers", allowHeaders);
+    if (allowHeaders.length())
+        m_response->setHeader("Access-Control-Allow-Headers", allowHeaders);
+    m_response->setHeader("Access-Control-Allow-Origin", "*");
+    m_response->setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
+    m_response->setHeader("Access-Control-Max-Age", "86400"); //arbitrary 24 hours
+    m_response->setContentType("text/plain");
+    m_response->setContent("");
+
+    m_response->send();
+
+    return 0;
+}
+
 int CEspHttpServer::onPost()
 {
     HtmlPage page("Enterprise Services Platform");

+ 1 - 0
esp/bindings/http/platform/httpservice.hpp

@@ -67,6 +67,7 @@ public:
 
     virtual int onPost();
     virtual int onGet();
+    virtual int onOptions();
 
     virtual int onGetFile(CHttpRequest* request, CHttpResponse* response, const char *path);
     virtual int onGetXslt(CHttpRequest* request, CHttpResponse* response, const char *path);

+ 4 - 0
esp/bindings/http/platform/httptransport.cpp

@@ -1235,6 +1235,10 @@ int CHttpRequest::parseFirstLine(char* oneline)
     {
         setMethod(HEAD_METHOD);
     }
+    else if(!stricmp(method.str(), OPTIONS_METHOD))
+    {
+        setMethod(OPTIONS_METHOD);
+    }
 
     StringBuffer pathbuf;
     curptr = Utils::getWord(curptr, pathbuf);

+ 1 - 0
esp/bindings/http/platform/httptransport.ipp

@@ -35,6 +35,7 @@
 #define POST_METHOD "POST"
 #define GET_METHOD "GET"
 #define HEAD_METHOD "HEAD"
+#define OPTIONS_METHOD "OPTIONS"
 
 #define UNKNOWN_METHOD_ERROR -1;