]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Support Cross-Origin Requests for the cache manager API
authorAmos Jeffries <squid3@treenet.co.nz>
Fri, 30 Dec 2011 03:42:50 +0000 (16:42 +1300)
committerAmos Jeffries <squid3@treenet.co.nz>
Fri, 30 Dec 2011 03:42:50 +0000 (16:42 +1300)
Now that tools are being implemented to access the cache manager via
http:// scheme we need to accomodate the browser XSS protection
mechanisms which limit XHR based scripts abilities.

This adds CORS headers to manager responses. Permitting XHR to view the
Server header (to detect squid version for known capabilities) and to
flag that the XHR request may need access to credentials for
authenticating with the manager.

This also closes the feature bug 3407 requesting we support the
non-standard "Origin:" header, which is used by the CORS mechanisms.

Future work:
  Support the OPTIONS request used by CORS to detect requirements before
  POSTing. We do not yet use POST in the Squid code so that is left until
  needed.

src/HttpHeader.cc
src/HttpHeader.h
src/cache_manager.cc
src/mgr/Action.cc
src/mgr/ActionParams.cc
src/mgr/ActionParams.h

index 5e59aa4ec399a8bc212090bf1f1d14bc377265a9..e7e8da3d5a49ece6e981eb97cf694e8eae0235c9 100644 (file)
@@ -116,6 +116,7 @@ static const HttpHeaderFieldAttrs HeadersAttrs[] = {
     {"Max-Forwards", HDR_MAX_FORWARDS, ftInt64},
     {"Mime-Version", HDR_MIME_VERSION, ftStr}, /* for now */
     {"Negotiate", HDR_NEGOTIATE, ftStr},
+    {"Origin", HDR_ORIGIN, ftStr},
     {"Pragma", HDR_PRAGMA, ftStr},
     {"Proxy-Authenticate", HDR_PROXY_AUTHENTICATE, ftStr},
     {"Proxy-Authentication-Info", HDR_PROXY_AUTHENTICATION_INFO, ftStr},
@@ -231,6 +232,7 @@ static http_hdr_type ReplyHeadersArr[] = {
     HDR_ACCEPT_RANGES, HDR_AGE,
     HDR_LOCATION, HDR_MAX_FORWARDS,
     HDR_MIME_VERSION, HDR_PUBLIC, HDR_RETRY_AFTER, HDR_SERVER, HDR_SET_COOKIE, HDR_SET_COOKIE2,
+    HDR_ORIGIN,
     HDR_VARY,
     HDR_WARNING, HDR_PROXY_CONNECTION, HDR_X_CACHE,
     HDR_X_CACHE_LOOKUP,
@@ -249,7 +251,9 @@ static HttpHeaderMask RequestHeadersMask;   /* set run-time using RequestHeaders *
 static http_hdr_type RequestHeadersArr[] = {
     HDR_AUTHORIZATION, HDR_FROM, HDR_HOST,
     HDR_IF_MATCH, HDR_IF_MODIFIED_SINCE, HDR_IF_NONE_MATCH,
-    HDR_IF_RANGE, HDR_MAX_FORWARDS, HDR_PROXY_CONNECTION,
+    HDR_IF_RANGE, HDR_MAX_FORWARDS,
+    HDR_ORIGIN,
+    HDR_PROXY_CONNECTION,
     HDR_PROXY_AUTHORIZATION, HDR_RANGE, HDR_REFERER, HDR_REQUEST_RANGE,
     HDR_USER_AGENT, HDR_X_FORWARDED_FOR, HDR_SURROGATE_CAPABILITY
 };
index b54970a169e567b1cc9ddef853835d974a462e33..999e8345a20d18638da31c56ee2f5f3002042343 100644 (file)
@@ -101,6 +101,7 @@ typedef enum {
     HDR_MIME_VERSION,                   /**< RFC 2626 */
     HDR_NEGOTIATE,                      /**< experimental RFC 2295. Why only this one from 2295? */
     /*HDR_OVERWRITE,*/                  /* RFC 2518 */
+    HDR_ORIGIN,                         /* CORS Draft specification (see http://www.w3.org/TR/cors/) */
     HDR_PRAGMA,                         /**< deprecated RFC 2068,2616 header we may need to erase */
     HDR_PROXY_AUTHENTICATE,             /**< RFC 2608, 2616, 2617 */
     HDR_PROXY_AUTHENTICATION_INFO,      /**< RFC 2617 */
index 1197a7adac63f2975e5c36e761a4252319267f03..49535b29d78915a0fed5d97d483ce3341ec4432e 100644 (file)
@@ -371,6 +371,14 @@ CacheManager::Start(const Comm::ConnectionPointer &client, HttpRequest * request
          */
         rep->header.putAuth("Basic", actionName);
 #endif
+        // Allow cachemgr and other XHR scripts access to our version string
+        if (request->header.has(HDR_ORIGIN)) {
+            rep->header.putExt("Access-Control-Allow-Origin",request->header.getStr(HDR_ORIGIN));
+#if HAVE_AUTH_MODULE_BASIC
+            rep->header.putExt("Access-Control-Allow-Credentials","true");
+#endif
+            rep->header.putExt("Access-Control-Expose-Headers","Server");
+        }
 
         /* store the reply */
         entry->replaceHttpReply(rep);
@@ -382,6 +390,10 @@ CacheManager::Start(const Comm::ConnectionPointer &client, HttpRequest * request
         return;
     }
 
+    if (request->header.has(HDR_ORIGIN)) {
+        cmd->params.httpOrigin = request->header.getStr(HDR_ORIGIN);
+    }
+
     debugs(16, 2, "CacheManager: " <<
            userName << "@" <<
            client << " requesting '" <<
index 44b88a4b3cd6aa5f63987b31a86556ed3487a00d..83f4cd0adb6e8dabcc423cc8fa3920e0e032ec6f 100644 (file)
@@ -102,6 +102,15 @@ Mgr::Action::fillEntry(StoreEntry* entry, bool writeHttpHeader)
     if (writeHttpHeader) {
         HttpReply *rep = new HttpReply;
         rep->setHeaders(HTTP_OK, NULL, "text/plain", -1, squid_curtime, squid_curtime);
+        // Allow cachemgr and other XHR scripts access to our version string
+        const ActionParams &params = command().params;
+        if (params.httpOrigin.size() > 0) {
+            rep->header.putExt("Access-Control-Allow-Origin", params.httpOrigin.termedBuf());
+#if HAVE_AUTH_MODULE_BASIC
+            rep->header.putExt("Access-Control-Allow-Credentials","true");
+#endif
+            rep->header.putExt("Access-Control-Expose-Headers","Server");
+        }
         entry->replaceHttpReply(rep);
     }
 
index 79355ea3496d1092b3e094b4fbde47b8d22dc02a..e4c5746820050be7d259a0a5b6dca16a6cee8e7e 100644 (file)
@@ -23,6 +23,7 @@ Mgr::ActionParams::ActionParams(const Ipc::TypedMsgHdr &msg)
     httpMethod = static_cast<_method_t>(m);
 
     msg.getPod(httpFlags);
+    msg.getString(httpOrigin);
 
     msg.getString(actionName);
     msg.getString(userName);
@@ -36,6 +37,7 @@ Mgr::ActionParams::pack(Ipc::TypedMsgHdr &msg) const
     msg.putString(httpUri);
     msg.putInt(httpMethod);
     msg.putPod(httpFlags);
+    msg.putString(httpOrigin);
 
     msg.putString(actionName);
     msg.putString(userName);
index cb6e3d4befaec9c21026b0b54e43355671e7ce66..71b3fa4f9df7217d4327e722bfc009be154fea48 100644 (file)
@@ -29,6 +29,7 @@ public:
     String httpUri; ///< HTTP request URI
     _method_t httpMethod; ///< HTTP request method
     request_flags httpFlags; ///< HTTP request flags
+    String httpOrigin;       ///< HTTP Origin: header (if any)
 
     /* action parameters extracted from the client HTTP request */
     String actionName; ///< action name (and credentials realm)