[CalendarServer-changes] [8101] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Wed Sep 14 13:08:59 PDT 2011


Revision: 8101
          http://trac.macosforge.org/projects/calendarserver/changeset/8101
Author:   cdaboo at apple.com
Date:     2011-09-14 13:08:58 -0700 (Wed, 14 Sep 2011)
Log Message:
-----------
Handle the case where an SSL decoder in front of the server hands us a non-SSL request but we need to
ensure absolute URIs have scheme/host/port set for SSL.

Modified Paths:
--------------
    CalendarServer/trunk/calendarserver/tap/caldav.py
    CalendarServer/trunk/twext/web2/server.py
    CalendarServer/trunk/twext/web2/test/test_server.py

Modified: CalendarServer/trunk/calendarserver/tap/caldav.py
===================================================================
--- CalendarServer/trunk/calendarserver/tap/caldav.py	2011-09-14 18:01:07 UTC (rev 8100)
+++ CalendarServer/trunk/calendarserver/tap/caldav.py	2011-09-14 20:08:58 UTC (rev 8101)
@@ -1,6 +1,6 @@
 # -*- test-case-name: calendarserver.tap.test.test_caldav -*-
 ##
-# Copyright (c) 2005-2010 Apple Inc. All rights reserved.
+# Copyright (c) 2005-2011 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.
@@ -162,7 +162,7 @@
 
 
 class ErrorLoggingMultiService(MultiService):
-    """ Registers a rotating file logger for error logging, iff
+    """ Registers a rotating file logger for error logging, if
         config.ErrorLogEnabled is True. """
 
     def setServiceParent(self, app):
@@ -261,7 +261,7 @@
     def opt_option(self, option):
         """
         Set an option to override a value in the config file. True, False, int,
-        and float options are supported, as well as comma seperated lists. Only
+        and float options are supported, as well as comma separated lists. Only
         one option may be given for each --option flag, however multiple
         --option flags may be specified.
         """
@@ -592,7 +592,7 @@
 
             import signal
             def sighup_handler(num, frame):
-                self.log_info("SIGHUP recieved at %s" % (location(frame),))
+                self.log_info("SIGHUP received at %s" % (location(frame),))
 
                 # Reload the config file
                 try:
@@ -725,6 +725,13 @@
         rootResource = getRootResource(config, store, additional)
 
         underlyingSite = Site(rootResource)
+        
+        # Need to cache SSL port info here so we can access it in a Request to deal with the
+        # possibility of being behind an SSL decoder
+        underlyingSite.EnableSSL = config.EnableSSL
+        underlyingSite.SSLPort = config.SSLPort
+        underlyingSite.BindSSLPorts = config.BindSSLPorts
+        
         requestFactory = underlyingSite
 
         if config.RedirectHTTPToHTTPS:
@@ -891,7 +898,7 @@
         main service.
 
         This has the effect of delaying any child process spawning or
-        standalone port-binding until the backing for the selected data store
+        stand alone port-binding until the backing for the selected data store
         implementation is ready to process requests.
 
         @param createMainService: This is the service that will be doing the main
@@ -1439,7 +1446,7 @@
 
 
     def startService(self):
-        # Now we're ready to build the command lines and actualy add the
+        # Now we're ready to build the command lines and actually add the
         # processes to procmon.
         super(DelayedStartupProcessMonitor, self).startService()
         for name in self.processes:
@@ -1513,7 +1520,7 @@
         del self.protocols[name]
 
         if self._reactor.seconds() - self.timeStarted[name] < self.threshold:
-            # The process died too fast - backoff
+            # The process died too fast - back off
             nextDelay = self.delay[name]
             self.delay[name] = min(self.delay[name] * 2, self.maxRestartDelay)
 

Modified: CalendarServer/trunk/twext/web2/server.py
===================================================================
--- CalendarServer/trunk/twext/web2/server.py	2011-09-14 18:01:07 UTC (rev 8100)
+++ CalendarServer/trunk/twext/web2/server.py	2011-09-14 20:08:58 UTC (rev 8101)
@@ -1,7 +1,7 @@
 # -*- test-case-name: twext.web2.test.test_server -*-
 ##
 # Copyright (c) 2001-2008 Twisted Matrix Laboratories.
-# Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2010-2011 Apple Computer, Inc. All rights reserved.
 #
 # Permission is hereby granted, free of charge, to any person obtaining a copy
 # of this software and associated documentation files (the "Software"), to deal
@@ -296,6 +296,31 @@
             self.postpath = path
         #print "_parseURL", self.uri, (self.uri, self.scheme, self.host, self.path, self.params, self.querystring)
 
+    def _schemeFromPort(self, port):
+        """
+        Try to determine the scheme matching the supplied server port. This is needed in case
+        where a device in front of the server is changing the scheme (e.g. decoding SSL) but not
+        rewriting the scheme in URIs returned in responses (e.g. in Location headers). This could trick
+        clients into using an inappropriate scheme for subsequent requests. What we should do is
+        take the port number from the Host header or request-URI and map that to the scheme that
+        matches the service we configured to listen on that port.
+ 
+        @param port: the port number to test
+        @type port: C{int}
+        
+        @return: C{True} if scheme is https (secure), C{False} otherwise
+        @rtype: C{bool}
+        """
+
+        #from twistedcaldav.config import config
+        if hasattr(self.site, "EnableSSL") and self.site.EnableSSL:
+            if port == self.site.SSLPort:
+                return True
+            elif port in self.site.BindSSLPorts:
+                return True
+        
+        return False
+
     def _fixupURLParts(self):
         hostaddr, secure = self.chanRequest.getHostInfo()
         if not self.scheme:
@@ -303,11 +328,13 @@
 
         if self.host:
             self.host, self.port = http.splitHostPort(self.scheme, self.host)
+            self.scheme = ('http', 'https')[self._schemeFromPort(self.port)]
         else:
             # If GET line wasn't an absolute URL
             host = self.headers.getHeader('host')
             if host:
                 self.host, self.port = http.splitHostPort(self.scheme, host)
+                self.scheme = ('http', 'https')[self._schemeFromPort(self.port)]
             else:
                 # When no hostname specified anywhere, either raise an
                 # error, or use the interface hostname, depending on
@@ -465,7 +492,7 @@
         nor whether the same URL is returned in subsequent calls.
 
         @param resource: the resource to find a URI for.  This resource must
-            have been obtained from the request (ie. via its C{uri} attribute, or
+            have been obtained from the request (i.e. via its C{uri} attribute, or
             through its C{locateResource} or C{locateChildResource} methods).
         @return: a valid URL for C{resource} in this request.
         @raise NoURLForResourceError: if C{resource} has no URL in this request
@@ -544,7 +571,7 @@
         resource.  This is similar to locateResource(), but doesn't have to
         start the lookup from the root resource, so it is potentially faster.
         @param parent: the parent of the resource being looked up.  This resource
-            must have been obtained from the request (ie. via its C{uri} attribute,
+            must have been obtained from the request (i.e. via its C{uri} attribute,
             or through its C{locateResource} or C{locateChildResource} methods).
         @param childName: the name of the child of C{parent} to looked up.
             to C{parent}.
@@ -599,7 +626,7 @@
         log.err(origReason)
 
         body = ("<html><head><title>Internal Server Error</title></head>"
-                "<body><h1>Internal Server Error</h1>An error occurred rendering the requested page. Additionally, an error occured rendering the error page.</body></html>")
+                "<body><h1>Internal Server Error</h1>An error occurred rendering the requested page. Additionally, an error occurred rendering the error page.</body></html>")
 
         response = http.Response(
             responsecode.INTERNAL_SERVER_ERROR,

Modified: CalendarServer/trunk/twext/web2/test/test_server.py
===================================================================
--- CalendarServer/trunk/twext/web2/test/test_server.py	2011-09-14 18:01:07 UTC (rev 8100)
+++ CalendarServer/trunk/twext/web2/test/test_server.py	2011-09-14 20:08:58 UTC (rev 8101)
@@ -116,7 +116,7 @@
 
 class SimpleRequest(server.Request):
     """I can be used in cases where a Request object is necessary
-    but it is benificial to bypass the chanRequest
+    but it is beneficial to bypass the chanRequest
     """
 
     clientproto = (1,1)
@@ -362,7 +362,58 @@
             (redirectResource, 'http://localhost/'),
             (301, {'location': 'https://localhost/foo?bar=baz'}, None))
 
+    def test_redirectResourceWithSchemeRemapping(self):
 
+        def chanrequest2(root, uri, length, headers, method, version, prepath, content):
+            site = server.Site(root)
+            site.EnableSSL = True
+            site.SSLPort = 8443
+            site.BindSSLPorts = []
+            return TestChanRequest(site, method, prepath, uri, length, headers, version, content)
+    
+        self.patch(self, "chanrequest", chanrequest2)
+
+        redirectResource = resource.RedirectResource(path='/foo')
+
+        return self.assertResponse(
+            (redirectResource, 'http://localhost:8443/'),
+            (301, {'location': 'https://localhost:8443/foo'}, None))
+
+    def test_redirectResourceWithoutSchemeRemapping(self):
+
+        def chanrequest2(root, uri, length, headers, method, version, prepath, content):
+            site = server.Site(root)
+            site.EnableSSL = True
+            site.SSLPort = 8443
+            site.BindSSLPorts = []
+            return TestChanRequest(site, method, prepath, uri, length, headers, version, content)
+    
+        self.patch(self, "chanrequest", chanrequest2)
+
+        redirectResource = resource.RedirectResource(path='/foo')
+
+        return self.assertResponse(
+            (redirectResource, 'http://localhost:8008/'),
+            (301, {'location': 'http://localhost:8008/foo'}, None))
+
+    def test_redirectResourceWithoutSSLSchemeRemapping(self):
+
+        def chanrequest2(root, uri, length, headers, method, version, prepath, content):
+            site = server.Site(root)
+            site.EnableSSL = False
+            site.SSLPort = 8443
+            site.BindSSLPorts = []
+            return TestChanRequest(site, method, prepath, uri, length, headers, version, content)
+    
+        self.patch(self, "chanrequest", chanrequest2)
+
+        redirectResource = resource.RedirectResource(path='/foo')
+
+        return self.assertResponse(
+            (redirectResource, 'http://localhost:8443/'),
+            (301, {'location': 'http://localhost:8443/foo'}, None))
+
+
 class URLParsingTest(BaseCase):
     class TestResource(resource.LeafResource):
         def render(self, req):
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20110914/3f0e713c/attachment-0001.html>


More information about the calendarserver-changes mailing list