[CalendarServer-changes] [9803] CalendarServer/trunk/twistedcaldav/directory

source_changes at macosforge.org source_changes at macosforge.org
Tue Sep 11 10:21:17 PDT 2012


Revision: 9803
          http://trac.macosforge.org/projects/calendarserver/changeset/9803
Author:   sagen at apple.com
Date:     2012-09-11 10:21:15 -0700 (Tue, 11 Sep 2012)
Log Message:
-----------
Protect against user-existence attacks by turning certain unauthenticated 404s into 401s

Modified Paths:
--------------
    CalendarServer/trunk/twistedcaldav/directory/common.py
    CalendarServer/trunk/twistedcaldav/directory/principal.py
    CalendarServer/trunk/twistedcaldav/directory/test/test_calendar.py
    CalendarServer/trunk/twistedcaldav/directory/util.py

Modified: CalendarServer/trunk/twistedcaldav/directory/common.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/common.py	2012-09-11 15:26:56 UTC (rev 9802)
+++ CalendarServer/trunk/twistedcaldav/directory/common.py	2012-09-11 17:21:15 UTC (rev 9803)
@@ -19,7 +19,7 @@
 from twext.web2.http import HTTPError
 from twext.web2 import responsecode
 from twext.web2.dav.util import joinURL
-from twistedcaldav.directory.util import transactionFromRequest
+from twistedcaldav.directory.util import transactionFromRequest, NotFoundResource
 from twistedcaldav.directory.resource import DirectoryReverseProxyResource
 
 from twext.python.log import Logger
@@ -147,7 +147,9 @@
 
         record = self.directory.recordWithShortName(self.recordType, name)
         if record is None:
-            returnValue((None, []))
+            returnValue(
+                (NotFoundResource(principalCollections=self._parent.principalCollections()), [])
+            )
 
         child = yield self._parent.homeForDirectoryRecord(record, request)
         returnValue((child, segments[1:]))

Modified: CalendarServer/trunk/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/principal.py	2012-09-11 15:26:56 UTC (rev 9802)
+++ CalendarServer/trunk/twistedcaldav/directory/principal.py	2012-09-11 17:21:15 UTC (rev 9803)
@@ -36,6 +36,7 @@
 from twisted.internet.defer import inlineCallbacks, returnValue
 from twisted.internet.defer import succeed
 from twisted.web.template import XMLFile, Element, renderer, tags
+from twistedcaldav.directory.util import NotFoundResource
 
 from twext.web2.auth.digest import DigestedCredentials
 from twext.web2 import responsecode
@@ -46,6 +47,7 @@
 
 from twext.python.log import Logger
 
+
 try:
     from twistedcaldav.authkerb import NegotiateCredentials
     NegotiateCredentials # sigh, pyflakes
@@ -130,6 +132,7 @@
             (origCUAddr,))
 
 
+
 class DirectoryProvisioningResource (
     PermissionsMixIn,
     CalendarPrincipalCollectionResource,
@@ -153,7 +156,7 @@
         child = self.getChild(segments[0])
         if child is not None:
             return (child, segments[1:])
-        return (None, ())
+        return (NotFoundResource(principalCollections=self.principalCollections()),())
 
     def deadProperties(self):
         if not hasattr(self, "_dead_properties"):

Modified: CalendarServer/trunk/twistedcaldav/directory/test/test_calendar.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/test/test_calendar.py	2012-09-11 15:26:56 UTC (rev 9802)
+++ CalendarServer/trunk/twistedcaldav/directory/test/test_calendar.py	2012-09-11 17:21:15 UTC (rev 9803)
@@ -21,7 +21,7 @@
 
 from twistedcaldav.test.util import TestCase
 from twext.web2.test.test_server import SimpleRequest
-from twistedcaldav.directory.util import transactionFromRequest
+from twistedcaldav.directory.util import transactionFromRequest, NotFoundResource
 
 class ProvisionedCalendars (TestCase):
     """
@@ -55,10 +55,14 @@
 
 
     def test_NonExistentCalendarHome(self):
+        """
+        Requests for missing homes and principals should return
+        NotFoundResources so that we have the opportunity to
+        turn 404s into 401s to protect against user-existence attacks.
+        """
 
         def _response(resource):
-            if resource is not None:
-                self.fail("Incorrect response to GET on non-existent calendar home.")
+            self.assertTrue(isinstance(resource, NotFoundResource))
 
         request = self.oneRequest("/calendars/users/12345/")
         d = request.locateResource(request.uri)

Modified: CalendarServer/trunk/twistedcaldav/directory/util.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/util.py	2012-09-11 15:26:56 UTC (rev 9802)
+++ CalendarServer/trunk/twistedcaldav/directory/util.py	2012-09-11 17:21:15 UTC (rev 9803)
@@ -22,12 +22,21 @@
 __all__ = [
     "normalizeUUID",
     "uuidFromName",
+    "NotFoundResource",
 ]
 
 from twext.enterprise.ienterprise import AlreadyFinishedError
-
+from twext.python.log import Logger
+from twext.web2 import responsecode
+from twext.web2.auth.wrapper import UnauthorizedResponse
+from twext.web2.dav.resource import DAVResource
+from twext.web2.http import StatusResponse
+from twisted.internet.defer import inlineCallbacks, returnValue
+from txdav.xml import element as davxml
 from uuid import UUID, uuid5
 
+log = Logger()
+
 def uuidFromName(namespace, name):
     """
     Generate a version 5 (SHA-1) UUID from a namespace UUID and a name.
@@ -108,3 +117,31 @@
         yield set(data[:size])
         del data[:size]
 
+
+class NotFoundResource(DAVResource):
+    """
+    In order to prevent unauthenticated discovery of existing users via 401/404
+    response codes, this resource can be returned from locateChild, and it will
+    perform an authentication; if the user is unauthenticated, 404 responses are
+    turned into 401s.
+    """
+
+    @inlineCallbacks
+    def renderHTTP(self, request):
+
+        try:
+            authnUser, authzUser = yield self.authenticate(request)
+        except Exception:
+            authzUser = davxml.Principal(davxml.Unauthenticated())
+
+        # Turn 404 into 401
+        if authzUser == davxml.Principal(davxml.Unauthenticated()):
+            response = (yield UnauthorizedResponse.makeResponse(
+                request.credentialFactories,
+                request.remoteAddr
+            ))
+            returnValue(response)
+        else:
+            response = StatusResponse(responsecode.NOT_FOUND, "Resource not found")
+            returnValue(response)
+
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120911/e805b4ad/attachment.html>


More information about the calendarserver-changes mailing list