[CalendarServer-changes] [5608] CalendarServer/trunk/twistedcaldav/client

source_changes at macosforge.org source_changes at macosforge.org
Mon May 17 13:37:03 PDT 2010


Revision: 5608
          http://trac.macosforge.org/projects/calendarserver/changeset/5608
Author:   cdaboo at apple.com
Date:     2010-05-17 13:37:00 -0700 (Mon, 17 May 2010)
Log Message:
-----------
Prevent request forwarding loops with partitioning.

Modified Paths:
--------------
    CalendarServer/trunk/twistedcaldav/client/__init__.py
    CalendarServer/trunk/twistedcaldav/client/reverseproxy.py

Added Paths:
-----------
    CalendarServer/trunk/twistedcaldav/client/test/
    CalendarServer/trunk/twistedcaldav/client/test/__init__.py
    CalendarServer/trunk/twistedcaldav/client/test/test_reverseproxy.py

Modified: CalendarServer/trunk/twistedcaldav/client/__init__.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/client/__init__.py	2010-05-15 05:04:39 UTC (rev 5607)
+++ CalendarServer/trunk/twistedcaldav/client/__init__.py	2010-05-17 20:37:00 UTC (rev 5608)
@@ -14,3 +14,16 @@
 # limitations under the License.
 ##
 
+from twext.web2.http_headers import DefaultHTTPHandler, tokenize, generateList, singleHeader
+
+DefaultHTTPHandler.updateParsers({
+    "x-forwarded-for": (tokenize, list),
+    "x-forwarded-host": (tokenize, list),
+    "x-forwarded-server": (tokenize, list),
+})
+DefaultHTTPHandler.updateGenerators({
+    "x-forwarded-for": (generateList, singleHeader),
+    "x-forwarded-host": (generateList, singleHeader),
+    "x-forwarded-server": (generateList, singleHeader),
+})
+

Modified: CalendarServer/trunk/twistedcaldav/client/reverseproxy.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/client/reverseproxy.py	2010-05-15 05:04:39 UTC (rev 5607)
+++ CalendarServer/trunk/twistedcaldav/client/reverseproxy.py	2010-05-17 20:37:00 UTC (rev 5608)
@@ -18,12 +18,11 @@
     "ReverseProxyResource",
 ]
 
-import urllib
-
 from zope.interface.declarations import implements
 
-from twext.web2 import iweb
+from twext.web2 import iweb, responsecode
 from twext.web2.client.http import ClientRequest
+from twext.web2.http import StatusResponse, HTTPError
 from twext.web2.resource import LeafResource
 
 from twext.python.log import LoggingMixIn
@@ -47,6 +46,7 @@
         self.poolID = poolID
         self._args   = args
         self._kwargs = kwargs
+        self.allowMultiHop = False
 
     def isCollection(self):
         return True
@@ -65,13 +65,26 @@
         """
             
         self.logger.info("%s %s %s" % (request.method, request.uri, "HTTP/%s.%s" % request.clientproto))
+
+        # Check for multi-hop
+        if not self.allowMultiHop:
+            x_server =  request.headers.getHeader("x-forwarded-server")
+            if x_server:
+                for item in x_server:
+                    if item == config.ServerHostName:
+                        raise HTTPError(StatusResponse(responsecode.BAD_GATEWAY, "Too many x-forwarded-server hops"))
+                
+            
         clientPool = getHTTPClientPool(self.poolID)
         proxyRequest = ClientRequest(request.method, request.uri, request.headers, request.stream)
         
-        # Need x-forwarded-(for|host) headers. First strip any existing ones out, then add ours
+        # Need x-forwarded-(for|host|server) headers. First strip any existing ones out, then add ours
         proxyRequest.headers.removeHeader("x-forwarded-host")
         proxyRequest.headers.removeHeader("x-forwarded-for")
-        proxyRequest.headers.addRawHeader("x-forwarded-host", config.ServerHostName)
+        proxyRequest.headers.removeHeader("x-forwarded-server")
+        proxyRequest.headers.addRawHeader("x-forwarded-host", request.host)
         proxyRequest.headers.addRawHeader("x-forwarded-for", request.remoteAddr.host)
+        proxyRequest.headers.addRawHeader("x-forwarded-server", config.ServerHostName)
 
         return clientPool.submitRequest(proxyRequest)
+

Added: CalendarServer/trunk/twistedcaldav/client/test/__init__.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/client/test/__init__.py	                        (rev 0)
+++ CalendarServer/trunk/twistedcaldav/client/test/__init__.py	2010-05-17 20:37:00 UTC (rev 5608)
@@ -0,0 +1,19 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+"""
+Tests for the twistedcaldav.client module.
+"""

Added: CalendarServer/trunk/twistedcaldav/client/test/test_reverseproxy.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/client/test/test_reverseproxy.py	                        (rev 0)
+++ CalendarServer/trunk/twistedcaldav/client/test/test_reverseproxy.py	2010-05-17 20:37:00 UTC (rev 5608)
@@ -0,0 +1,75 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+from twext.web2.client.http import ClientRequest
+from twext.web2.http import HTTPError
+from twext.web2.test.test_server import SimpleRequest
+from twistedcaldav.client.pool import _clientPools 
+from twistedcaldav.client.reverseproxy import ReverseProxyResource
+from twistedcaldav.config import config
+import twistedcaldav.test.util
+
+class ReverseProxyNoLoop (twistedcaldav.test.util.TestCase):
+    """
+    Prevent loops in reverse proxy
+    """
+
+    def setUp(self):
+        
+        class DummyPool(object):
+            
+            def submitRequest(self, request):
+                return request
+
+        _clientPools["pool"] = DummyPool()
+
+        super(ReverseProxyNoLoop, self).setUp()
+
+    def test_No_Header(self):
+        proxy = ReverseProxyResource("pool")
+        request = SimpleRequest(proxy, "GET", "/")
+        self.assertIsInstance(proxy.renderHTTP(request), ClientRequest)
+
+    def test_Header_Other_Server(self):
+        proxy = ReverseProxyResource("pool")
+        request = SimpleRequest(proxy, "GET", "/")
+        request.headers.addRawHeader("x-forwarded-server", "foobar.example.com")
+        self.assertIsInstance(proxy.renderHTTP(request), ClientRequest)
+
+    def test_Header_Other_Servers(self):
+        proxy = ReverseProxyResource("pool")
+        request = SimpleRequest(proxy, "GET", "/")
+        request.headers.setHeader("x-forwarded-server", ("foobar.example.com", "bar.example.com",))
+        self.assertIsInstance(proxy.renderHTTP(request), ClientRequest)
+
+    def test_Header_Our_Server(self):
+        proxy = ReverseProxyResource("pool")
+        request = SimpleRequest(proxy, "GET", "/")
+        request.headers.addRawHeader("x-forwarded-server", config.ServerHostName)
+        self.assertRaises(HTTPError, proxy.renderHTTP, request)
+
+    def test_Header_Our_Server_Moxied(self):
+        proxy = ReverseProxyResource("pool")
+        request = SimpleRequest(proxy, "GET", "/")
+        request.headers.setHeader("x-forwarded-server", ("foobar.example.com", "bar.example.com", config.ServerHostName,))
+        self.assertRaises(HTTPError, proxy.renderHTTP, request)
+
+    def test_Header_Our_Server_Allowed(self):
+        proxy = ReverseProxyResource("pool")
+        proxy.allowMultiHop = True
+        request = SimpleRequest(proxy, "GET", "/")
+        request.headers.addRawHeader("x-forwarded-server", config.ServerHostName)
+        self.assertIsInstance(proxy.renderHTTP(request), ClientRequest)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100517/07909cd8/attachment.html>


More information about the calendarserver-changes mailing list