[CalendarServer-changes] [1339] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Tue Mar 6 15:58:59 PST 2007


Revision: 1339
          http://trac.macosforge.org/projects/calendarserver/changeset/1339
Author:   dreid at apple.com
Date:     2007-03-06 15:58:59 -0800 (Tue, 06 Mar 2007)

Log Message:
-----------
Merge new-twisted to pick up dav-acl-1608-4 with a variety of improvements including better Web2 auth.

Modified Paths:
--------------
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.resource.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.static.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.server.patch
    CalendarServer/trunk/run

Removed Paths:
-------------
    CalendarServer/trunk/lib-patches/Twisted/twisted.python.procutils.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.auth.digest.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.iweb.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.test.test_httpauth.patch

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.python.procutils.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.python.procutils.patch	2007-03-06 23:47:08 UTC (rev 1338)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.python.procutils.patch	2007-03-06 23:58:59 UTC (rev 1339)
@@ -1,13 +0,0 @@
-Index: twisted/python/procutils.py
-===================================================================
---- twisted/python/procutils.py	(revision 18545)
-+++ twisted/python/procutils.py	(working copy)
-@@ -33,7 +33,7 @@
-     """
-     result = []
-     exts = filter(None, os.environ.get('PATHEXT', '').split(os.pathsep))
--    for p in os.environ['PATH'].split(os.pathsep):
-+    for p in os.environ.get('PATH', '').split(os.pathsep):
-         p = os.path.join(p, name)
-         if os.access(p, flags):
-             result.append(p)

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.auth.digest.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.auth.digest.patch	2007-03-06 23:47:08 UTC (rev 1338)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.auth.digest.patch	2007-03-06 23:58:59 UTC (rev 1339)
@@ -1,92 +0,0 @@
-Index: twisted/web2/auth/digest.py
-===================================================================
---- twisted/web2/auth/digest.py	(revision 18545)
-+++ twisted/web2/auth/digest.py	(working copy)
-@@ -5,6 +5,7 @@
- 
- http://www.faqs.org/rfcs/rfc2617.html
- """
-+import time
- 
- from twisted.cred import credentials, error
- from zope.interface import implements
-@@ -118,10 +119,12 @@
- class DigestCredentialFactory:
-     implements(ICredentialFactory)
- 
--    CHALLENGE_LIFETIME = 15
-+    CHALLENGE_LIFETIME_SECS = 15 * 60    # 15 minutes
- 
-     scheme = "digest"
- 
-+    pkey = '%d%d%d' %  tuple([random.randrange(sys.maxint) for _ in range(3)])
-+
-     def __init__(self, algorithm, realm):
-         """@type algorithm: C{str}
-            @param algorithm: case insensitive string that specifies
-@@ -132,7 +135,6 @@
-            @param realm: case sensitive string that specifies the realm
-                          portion of the challenge
-         """
--        self.outstanding = {}
-         self.algorithm = algorithm
-         self.realm = realm
- 
-@@ -141,13 +143,41 @@
-         c = '%d%d%d' % c
-         return c
- 
--    def generateOpaque(self):
--        return str(random.randrange(sys.maxint))
-+    def generateOpaque(self, nonce, clientip):
-+        # Now, what we do is encode the nonce, client ip and a timestamp in the opaque value
-+        # with a suitable digest
-+        key = "%s,%s,%s" % (nonce, clientip, str(int(time.time())))
-+        digest = md5.new(key + DigestCredentialFactory.pkey).hexdigest()
-+        ekey = key.encode('base64')
-+        return "%s-%s" % (digest, ekey.replace('\n', ''),)
- 
-+    def verifyOpaque(self, opaque, nonce, clientip):
-+        # First split the digest from the key
-+        opaque_parts = opaque.split('-')
-+        if len(opaque_parts) != 2:
-+            raise error.LoginFailed('Invalid response, invalid opaque value')
-+        
-+        # Verify the key
-+        key = opaque_parts[1].decode('base64')
-+        key_parts = key.split(',')
-+        if len(key_parts) != 3:
-+            raise error.LoginFailed('Invalid response, invalid opaque value')
-+        if key_parts[0] != nonce:
-+            raise error.LoginFailed('Invalid response, incompatible opaque/nonce values')
-+        if key_parts[1] != clientip:
-+            raise error.LoginFailed('Invalid response, incompatible opaque/client values')
-+        if int(time.time()) - int(key_parts[2]) > DigestCredentialFactory.CHALLENGE_LIFETIME_SECS:
-+            raise error.LoginFailed('Invalid response, incompatible opaque/nonce too old')
-+
-+        # Verify the digest
-+        digest = md5.new(key + DigestCredentialFactory.pkey).hexdigest()
-+        if digest != opaque_parts[0]:
-+            raise error.LoginFailed('Invalid response, invalid opaque value')
-+        
-     def getChallenge(self, peer):
-         c = self.generateNonce()
--        o = self.generateOpaque()
--        self.outstanding[o] = c
-+        o = self.generateOpaque(c, peer.host)
-+
-         return {'nonce': c,
-                 'opaque': o,
-                 'qop': 'auth',
-@@ -167,9 +197,7 @@
-         if not username:
-             raise error.LoginFailed('Invalid response, no username given')
- 
--        if auth.get('opaque') not in self.outstanding:
--            raise error.LoginFailed('Invalid response, opaque not outstanding')
--
--        del self.outstanding[auth['opaque']]
-+        # Now verify the nonce/opaque values for this client
-+        self.verifyOpaque(auth.get('opaque'), auth.get('nonce'), request.remoteAddr.host)
-             
-         return DigestedCredentials(username, request.method, self.realm, auth)

Modified: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.resource.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.resource.patch	2007-03-06 23:47:08 UTC (rev 1338)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.resource.patch	2007-03-06 23:58:59 UTC (rev 1339)
@@ -1,6 +1,6 @@
 Index: twisted/web2/dav/resource.py
 ===================================================================
---- twisted/web2/dav/resource.py	(revision 18545)
+--- twisted/web2/dav/resource.py	(revision 19773)
 +++ twisted/web2/dav/resource.py	(working copy)
 @@ -40,10 +40,18 @@
      "unauthenticatedPrincipal",
@@ -171,57 +171,7 @@
      ##
      # DAV
      ##
-@@ -509,6 +583,9 @@
-             reactor.callLater(0, getChild)
- 
-         def checkPrivileges(child):
-+            if child is None:
-+                return None
-+
-             if privileges is None:
-                 return child
-    
-@@ -517,14 +594,17 @@
-             return d
- 
-         def gotChild(child, childpath):
--            if child.isCollection():
--                callback(child, childpath + "/")
--                if depth == "infinity":
--                    d = child.findChildren(depth, request, callback, privileges)
--                    d.addCallback(lambda x: reactor.callLater(0, getChild))
--                    return d
-+            if child is None:
-+                callback(None, childpath + "/")
-             else:
--                callback(child, childpath)
-+                if child.isCollection():
-+                    callback(child, childpath + "/")
-+                    if depth == "infinity":
-+                        d = child.findChildren(depth, request, callback, privileges)
-+                        d.addCallback(lambda x: reactor.callLater(0, getChild))
-+                        return d
-+                else:
-+                    callback(child, childpath)
- 
-             reactor.callLater(0, getChild)
- 
-@@ -535,10 +615,10 @@
-                 completionDeferred.callback(None)
-             else:
-                 childpath = joinURL(basepath, childname)
--                child = request.locateResource(childpath)
--                child.addCallback(checkPrivileges)
--                child.addCallbacks(gotChild, checkPrivilegesError, (childpath,))
--                child.addErrback(completionDeferred.errback)
-+                d = request.locateChildResource(self, childname)
-+                d.addCallback(checkPrivileges)
-+                d.addCallbacks(gotChild, checkPrivilegesError, (childpath,))
-+                d.addErrback(completionDeferred.errback)
- 
-         getChild()
- 
-@@ -564,19 +644,21 @@
+@@ -570,19 +644,21 @@
          See L{IDAVResource.authorize}.
          """
          def onError(failure):
@@ -248,7 +198,7 @@
                      response = UnauthorizedResponse(request.credentialFactories,
                                                      request.remoteAddr)
                  else:
-@@ -587,7 +669,7 @@
+@@ -593,7 +669,7 @@
                  # class is supposed to be a FORBIDDEN status code and
                  # "Authorization will not help" according to RFC2616
                  #
@@ -257,7 +207,7 @@
  
              d = self.checkPrivileges(request, privileges, recurse)
              d.addErrback(onErrors)
-@@ -600,16 +682,21 @@
+@@ -606,16 +682,21 @@
  
      def authenticate(self, request):
          def loginSuccess(result):
@@ -283,7 +233,7 @@
  
          authHeader = request.headers.getHeader('authorization')
  
-@@ -625,9 +712,10 @@
+@@ -631,9 +712,10 @@
  
                  # Try to match principals in each principal collection on the resource
                  def gotDetails(details):
@@ -297,7 +247,7 @@
  
                  def login(pcreds):
                      d = request.portal.login(pcreds, None, *request.loginInterfaces)
-@@ -635,13 +723,15 @@
+@@ -641,13 +723,15 @@
  
                      return d
  
@@ -317,7 +267,7 @@
  
      ##
      # ACL
-@@ -650,49 +740,23 @@
+@@ -656,49 +740,23 @@
      def currentPrincipal(self, request):
          """
          @param request: the request being processed.
@@ -376,7 +326,7 @@
          """
          @return: the L{davxml.ACL} element containing the default access control
              list for this resource.
-@@ -704,6 +768,17 @@
+@@ -710,6 +768,17 @@
          #
          return readonlyACL
  
@@ -394,7 +344,7 @@
      def setAccessControlList(self, acl):
          """
          See L{IDAVResource.setAccessControlList}.
-@@ -1032,9 +1107,9 @@
+@@ -1038,9 +1107,9 @@
  
              if myURL == "/":
                  # If we get to the root without any ACLs, then use the default.
@@ -406,7 +356,7 @@
  
          # Dynamically update privileges for those ace's that are inherited.
          if inheritance:
-@@ -1070,7 +1145,7 @@
+@@ -1076,7 +1145,7 @@
                                  # Adjust ACE for inherit on this resource
                                  children = list(ace.children)
                                  children.remove(TwistedACLInheritable())
@@ -415,7 +365,7 @@
                                  aces.append(davxml.ACE(*children))
              else:
                  aces.extend(inherited_aces)
-@@ -1122,7 +1197,7 @@
+@@ -1128,7 +1197,7 @@
                  # Adjust ACE for inherit on this resource
                  children = list(ace.children)
                  children.remove(TwistedACLInheritable())
@@ -424,7 +374,7 @@
                  aces.append(davxml.ACE(*children))
                  
          # Filter out those that do not have a principal match with the current principal
-@@ -1146,49 +1221,69 @@
+@@ -1152,49 +1221,69 @@
  
          This implementation returns an empty set.
          """
@@ -522,7 +472,7 @@
      def samePrincipal(self, principal1, principal2):
          """
          Check whether the two prinicpals are exactly the same in terms of
-@@ -1213,7 +1308,6 @@
+@@ -1219,7 +1308,6 @@
              return False
                  
      def matchPrincipal(self, principal1, principal2, request):
@@ -530,7 +480,7 @@
          """
          Check whether the principal1 is a principal in the set defined by
          principal2.
-@@ -1238,6 +1332,9 @@
+@@ -1244,6 +1332,9 @@
              if isinstance(principal1, davxml.Unauthenticated):
                  yield False
                  return
@@ -540,7 +490,7 @@
              else:
                  yield True
                  return
-@@ -1265,7 +1362,6 @@
+@@ -1271,7 +1362,6 @@
  
          assert principal2 is not None, "principal2 is None"
  
@@ -548,7 +498,7 @@
          # Compare two HRefs and do group membership test as well
          if principal1 == principal2:
              yield True
-@@ -1296,9 +1392,9 @@
+@@ -1302,9 +1392,9 @@
          def testGroup(group):
              # Get principal resource for principal2
              if group and isinstance(group, DAVPrincipalResource):
@@ -561,7 +511,7 @@
                  
              return False
  
-@@ -1426,7 +1522,7 @@
+@@ -1432,7 +1522,7 @@
                  log.err("DAV:self ACE is set on non-principal resource %r" % (self,))
                  yield None
                  return
@@ -570,7 +520,7 @@
  
          if isinstance(principal, davxml.HRef):
              yield principal
-@@ -1511,6 +1607,265 @@
+@@ -1517,6 +1607,265 @@
          return None
  
      ##
@@ -836,12 +786,8 @@
      # HTTP
      ##
  
-@@ -1558,10 +1913,10 @@
-     """
-     DAV resource with no children.
-     """
--    def findChildren(self, depth, request, callback, privileges=None):
-+    def findChildren(self, depth, request, callback, privileges=None, inherited_aces=None):
+@@ -1567,7 +1916,7 @@
+     def findChildren(self, depth, request, callback, privileges=None, inherited_aces=None):
          return succeed(None)
  
 -class DAVPrincipalResource (DAVLeafResource):
@@ -849,7 +795,7 @@
      """
      Resource representing a WebDAV principal.  (RFC 3744, section 2)
      """
-@@ -1571,7 +1926,7 @@
+@@ -1577,7 +1926,7 @@
      # WebDAV
      ##
  
@@ -858,7 +804,7 @@
          (dav_namespace, "alternate-URI-set"),
          (dav_namespace, "principal-URL"    ),
          (dav_namespace, "group-member-set" ),
-@@ -1579,14 +1934,11 @@
+@@ -1585,14 +1934,11 @@
      )
  
      def davComplianceClasses(self):
@@ -874,7 +820,7 @@
      def readProperty(self, property, request):
          def defer():
              if type(property) is tuple:
-@@ -1604,10 +1956,10 @@
+@@ -1610,10 +1956,10 @@
                      return davxml.PrincipalURL(davxml.HRef(self.principalURL()))
  
                  if name == "group-member-set":
@@ -887,7 +833,7 @@
  
                  if name == "resourcetype":
                      if self.isCollection():
-@@ -1671,8 +2023,27 @@
+@@ -1677,8 +2023,27 @@
          if self.principalURL() == uri:
              return True
          else:
@@ -916,7 +862,7 @@
  class AccessDeniedError(Exception):
      def __init__(self, errors):
          """ 
-@@ -1712,6 +2083,37 @@
+@@ -1718,6 +2083,37 @@
  davxml.registerElement(TwistedACLInheritable)
  davxml.ACE.allowed_children[(twisted_dav_namespace, "inheritable")] = (0, 1)
  

Modified: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.static.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.static.patch	2007-03-06 23:47:08 UTC (rev 1338)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.static.patch	2007-03-06 23:58:59 UTC (rev 1339)
@@ -1,6 +1,6 @@
 Index: twisted/web2/dav/static.py
 ===================================================================
---- twisted/web2/dav/static.py	(revision 18545)
+--- twisted/web2/dav/static.py	(revision 19773)
 +++ twisted/web2/dav/static.py	(working copy)
 @@ -28,16 +28,16 @@
  
@@ -131,71 +131,14 @@
      # Workarounds for issues with File
      ##
  
-@@ -132,63 +186,11 @@
+@@ -132,7 +186,9 @@
          return (self.createSimilarFile(self.fp.child(path).path), segments[1:])
  
      def createSimilarFile(self, path):
 -        return self.__class__(path, defaultType=self.defaultType, indexNames=self.indexNames[:])
 +        return self.__class__(
-+            path, self.defaultType, self.indexNames[:],
-+            principalCollections=self.principalCollections()
-+        )
++            path, defaultType=self.defaultType, indexNames=self.indexNames[:],
++            principalCollections=self.principalCollections())
  
--    def render(self, request):
--        """
--        This is a direct copy of web2.static.render with the
--        listChildren behavior replaced with findChildren to ensure
--        that the current authenticated principal can only list
--        directory contents that they have read permissions for.
--        """
--        if not self.fp.exists():
--            yield responsecode.NOT_FOUND
--            return
--
--        if self.fp.isdir():
--            if request.uri[-1] != "/":
--                # Redirect to include trailing '/' in URI
--                yield RedirectResponse(
--                    request.unparseURL(path=request.path+'/'))
--                return
--            else:
--                ifp = self.fp.childSearchPreauth(*self.indexNames)
--                if ifp:
--                    # Render from the index file
--                    standin = self.createSimilarFile(ifp.path)
--                else:
--                    filtered_aces = waitForDeferred(self.inheritedACEsforChildren(request))
--                    yield filtered_aces
--                    filtered_aces = filtered_aces.getResult()
--
--                    children = []
--
--                    def found(request, uri):
--                        children.append(uri.split("/")[-1].rstrip("/"))
--
--                    x = waitForDeferred(
--                        self.findChildren("1", request, found, (davxml.Read(),),
--                                          inherited_aces=filtered_aces)
--                    )
--                    yield x
--                    x = x.getResult()
--
--                    # Render from a DirectoryLister
--                    standin = dirlist.DirectoryLister(
--                        self.fp.path,
--                        children,
--                        self.contentTypes,
--                        self.contentEncodings,
--                        self.defaultType
--                    )
--                yield standin.render(request)
--                return
--
--        # Do regular resource behavior from superclass
--        yield super(DAVFile, self).render(request)
--    
--    render = deferredGenerator(render)
--
  #
  # Attach method handlers to DAVFile
- #

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.iweb.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.iweb.patch	2007-03-06 23:47:08 UTC (rev 1338)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.iweb.patch	2007-03-06 23:58:59 UTC (rev 1339)
@@ -1,32 +0,0 @@
-Index: twisted/web2/iweb.py
-===================================================================
---- twisted/web2/iweb.py	(revision 18545)
-+++ twisted/web2/iweb.py	(working copy)
-@@ -41,14 +41,23 @@
-         """
- 
- # Is there a better way to do this than this funky extra class?
-+NotSpecified = object()
- class SpecialAdaptInterfaceClass(interface.InterfaceClass):
-     # A special adapter for IResource to handle the extra step of adapting
-     # from IOldNevowResource-providing resources.
--    def __call__(self, other, alternate=None):
--        result = super(SpecialAdaptInterfaceClass, self).__call__(other, alternate)
--        if result is not alternate:
--            return result
-+    def __call__(self, other, alternate=NotSpecified):
-+        if alternate == NotSpecified:
-+            try:
-+                return super(SpecialAdaptInterfaceClass, self).__call__(other)
-+            except TypeError:
-+                pass
-+        else:
-+            result = super(SpecialAdaptInterfaceClass, self).__call__(other, alternate)
-+            if result is not alternate:
-+                return result
-         
-+        if alternate == NotSpecified:
-+            return IOldNevowResource(other)
-         result = IOldNevowResource(other, alternate)
-         if result is not alternate:
-             return IResource(result)

Modified: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.server.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.server.patch	2007-03-06 23:47:08 UTC (rev 1338)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.server.patch	2007-03-06 23:58:59 UTC (rev 1339)
@@ -1,6 +1,6 @@
 Index: twisted/web2/server.py
 ===================================================================
---- twisted/web2/server.py	(revision 18545)
+--- twisted/web2/server.py	(revision 19773)
 +++ twisted/web2/server.py	(working copy)
 @@ -26,6 +26,7 @@
  from twisted.web2 import http_headers
@@ -64,50 +64,31 @@
          d.addCallback(lambda res, req: res.renderHTTP(req), self)
          d.addCallback(self._cbFinishRender)
          d.addErrback(self._processingFailed)
-@@ -320,8 +340,6 @@
-                     url = "/" + "/".join(path)
-                 else:
-                     url = "/"
--        
--                self._rememberURLForResource(quote(url), res)
+@@ -321,7 +341,6 @@
+         if newpath is StopTraversal:
+             # We need to rethink how to do this.
+             #if newres is res:
+-                self._rememberResource(res, url)
                  return res
              #else:
              #    raise ValueError("locateChild must not return StopTraversal with a resource other than self.")
-@@ -342,17 +360,16 @@
+@@ -337,7 +356,6 @@
                  self.prepath.append(self.postpath.pop(0))
  
          child = self._getChild(None, newres, newpath, updatepaths=updatepaths)
--        self._rememberURLForResource(quote(url), child)
+-        self._rememberResource(child, url)
  
          return child
  
--    _resourcesByURL = weakref.WeakKeyDictionary()
--
--    def _rememberURLForResource(self, url, resource):
-+    def _rememberResource(self, resource, url):
+@@ -347,6 +365,7 @@
          """
--        Remember the URL of visited resources.
-+        Remember the URL of a visited resources.
+         Remember the URL of a visited resource.
          """
-         self._resourcesByURL[resource] = url
-+        self._urlsByResource[url] = resource
-+        return resource
++        self._resourcesByURL[url] = resource
+         self._urlsByResource[resource] = url
+         return resource
  
-     def urlForResource(self, resource):
-         """
-@@ -367,10 +384,7 @@
- 
-         @return: the URL of C{resource} if known, otherwise C{None}.
-         """
--        try:
--            return self._resourcesByURL[resource]
--        except KeyError:
--            return None
-+        return self._resourcesByURL.get(resource, None)
- 
-     def locateResource(self, url):
-         """
-@@ -385,7 +399,8 @@
+@@ -386,7 +405,8 @@
              The contained response will have a status code of
              L{responsecode.BAD_REQUEST}.
          """
@@ -117,80 +98,19 @@
  
          #
          # Parse the URL
-@@ -406,19 +421,71 @@
+@@ -407,9 +427,13 @@
                  "URL is not on this site (%s://%s/): %s" % (scheme, self.headers.getHeader("host"), url)
              ))
  
 -        segments = path.split("/")
-+        # Looked for cached value
-+        cached = self._urlsByResource.get(path, None)
++        # Look for cached value
++        cached = self._resourcesByURL.get(path, None)
 +        if cached is not None:
 +            return defer.succeed(cached)
 +
 +        segments = unquote(path).split("/")
          assert segments[0] == "", "URL path didn't begin with '/': %s" % (path,)
-         segments = segments[1:]
--        segments = map(unquote, segments)
+-        segments = map(unquote, segments[1:])
  
          def notFound(f):
              f.trap(http.HTTPError)
--            if f.response.code != responsecode.NOT_FOUND:
--                raise f
-+            if f.value.response.code != responsecode.NOT_FOUND:
-+                return f
-             return None
- 
--        return defer.maybeDeferred(self._getChild, None, self.site.resource, segments, updatepaths=False)
-+        d = defer.maybeDeferred(self._getChild, None, self.site.resource, segments, updatepaths=False)
-+        d.addCallback(self._rememberResource, path)
-+        d.addErrback(notFound)
-+        return d
- 
-+    def locateChildResource(self, parent, child_name):
-+        """
-+        Looks up the child resource with the given name given the parent
-+        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.
-+        @param child_name: the name of the child of C{parent} to looked up.
-+            to C{parent}.
-+        @return: a L{Deferred} resulting in the L{IResource} at the
-+            given URL or C{None} if no such resource can be located.
-+        @raise HTTPError: If C{url} is not a URL on the site that this
-+            request is being applied to.  The contained response will
-+            have a status code of L{responsecode.BAD_GATEWAY}.
-+        @raise HTTPError: If C{url} contains a query or fragment.
-+            The contained response will have a status code of
-+            L{responsecode.BAD_REQUEST}.
-+        """
-+        if parent is None or child_name is None:
-+            return defer.succeed(None)
-+
-+        parent_resource = self.urlForResource(parent)
-+
-+        assert parent_resource is not None
-+
-+        url = joinURL(parent_resource, child_name)
-+
-+        cached = self._urlsByResource.get(url, None)
-+        if cached is not None:
-+            return defer.succeed(cached)
-+
-+        assert "/" not in child_name, "Child name may not contain '/': %s" % (child_name,)
-+
-+        segment = unquote(child_name)
-+
-+        def notFound(f):
-+            f.trap(http.HTTPError)
-+            if f.value.response.code != responsecode.NOT_FOUND:
-+                return f
-+            return None
-+
-+        d = defer.maybeDeferred(self._getChild, None, parent, [segment], updatepaths=False)
-+        d.addCallback(self._rememberResource, url)
-+        d.addErrback(notFound)
-+        return d
-+
-     def _processingFailed(self, reason):
-         if reason.check(http.HTTPError) is not None:
-             # If the exception was an HTTPError, leave it alone

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.test.test_httpauth.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.test.test_httpauth.patch	2007-03-06 23:47:08 UTC (rev 1338)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.test.test_httpauth.patch	2007-03-06 23:58:59 UTC (rev 1339)
@@ -1,110 +0,0 @@
-Index: twisted/web2/test/test_httpauth.py
-===================================================================
---- twisted/web2/test/test_httpauth.py	(revision 18545)
-+++ twisted/web2/test/test_httpauth.py	(working copy)
-@@ -1,3 +1,6 @@
-+import md5
-+import time
-+from twisted.internet import address
- from twisted.trial import unittest
- from twisted.internet import defer
- from twisted.cred import error
-@@ -12,8 +15,13 @@
-     def generateNonce(self):
-         return '178288758716122392881254770685'
- 
--    def generateOpaque(self):
--        return '1041524039'
-+    def generateOpaque(self, nonce, clientip):
-+        # Now, what we do is encode the nonce, client ip and a timestamp in the opaque value
-+        # with a suitable digest
-+        key = "%s,%s,%s" % (nonce, clientip, str(int(0)))
-+        digest = md5.new(key + "0").hexdigest()
-+        ekey = key.encode('base64')
-+        return "%s-%s" % (digest, ekey.replace('\n', ''),)
- 
- class BasicAuthTestCase(unittest.TestCase):
-     def setUp(self):
-@@ -56,32 +64,63 @@
- 
- challengeResponse = ('digest', {'nonce': '178288758716122392881254770685', 
-                                 'qop': 'auth', 'realm': 'test realm', 
--                                'algorithm': 'md5', 'opaque': '1041524039'})
-+                                'algorithm': 'md5',
-+                                'opaque': '75c4bd95b96b7b7341c646c6502f0833-MTc4Mjg4NzU4NzE2MTIyMzkyODgxMjU0NzcwNjg1LHJlbW90ZWhvc3QsMA=='})
- 
--authRequest = 'username="username", realm="test realm", nonce="178288758716122392881254770685", uri="/write/", response="62f388be1cf678fbdfce87910871bcc5", opaque="1041524039", algorithm="md5", cnonce="29fc54aa1641c6fa0e151419361c8f23", nc=00000001, qop="auth"'
-+cnonce = "29fc54aa1641c6fa0e151419361c8f23"
- 
-+authRequest1 = 'username="username", realm="test realm", nonce="%s", uri="/write/", response="%s", opaque="%s", algorithm="md5", cnonce="29fc54aa1641c6fa0e151419361c8f23", nc=00000001, qop="auth"'
-+authRequest2 = 'username="username", realm="test realm", nonce="%s", uri="/write/", response="%s", opaque="%s", algorithm="md5", cnonce="29fc54aa1641c6fa0e151419361c8f23", nc=00000002, qop="auth"'
-+
- namelessAuthRequest = 'realm="test realm",nonce="doesn\'t matter"'
- 
- class DigestAuthTestCase(unittest.TestCase):
-     def setUp(self):
--        self.credentialFactory = FakeDigestCredentialFactory('md5', 
-+        self.credentialFactory = digest.DigestCredentialFactory('md5', 
-                                                              'test realm')
- 
-+    def getDigestResponse(self, challenge, ncount):
-+        nonce = challenge.get('nonce')
-+        algo = challenge.get('algorithm').lower()
-+        qop = challenge.get('qop')
-+        
-+        expected = digest.calcResponse(
-+            digest.calcHA1(algo, "username", "test realm", "password", nonce, cnonce),
-+            algo, nonce, ncount, cnonce, qop, "GET", "/write/", None
-+        )
-+        return expected
-+
-     def testGetChallenge(self):
--        self.assertEquals(
--            self.credentialFactory.getChallenge(None),
--            challengeResponse[1])
-+        challenge = self.credentialFactory.getChallenge(address.IPv4Address('TCP', "127.0.0.1", 80))
-+        self.assertEquals(challenge['qop'], 'auth')
-+        self.assertEquals(challenge['realm'], 'test realm')
-+        self.assertEquals(challenge['algorithm'], 'md5')
-+        self.assertTrue(challenge.has_key("nonce"))
-+        self.assertTrue(challenge.has_key("opaque"))
- 
-     def testResponse(self):
--        challenge = self.credentialFactory.getChallenge(None)
-+        challenge = self.credentialFactory.getChallenge(address.IPv4Address('TCP', "127.0.0.1", 80))
- 
--        creds = self.credentialFactory.decode(authRequest, _trivial_GET)
-+        clientResponse = authRequest1 % (challenge['nonce'], self.getDigestResponse(challenge, "00000001"), challenge['opaque'])
-+        creds = self.credentialFactory.decode(clientResponse, _trivial_GET)
-         self.failUnless(creds.checkPassword('password'))
- 
-+    def testMultiResponse(self):
-+        challenge = self.credentialFactory.getChallenge(address.IPv4Address('TCP', "127.0.0.1", 80))
-+
-+        clientResponse = authRequest1 % (challenge['nonce'], self.getDigestResponse(challenge, "00000001"), challenge['opaque'])
-+        creds = self.credentialFactory.decode(clientResponse, _trivial_GET)
-+        self.failUnless(creds.checkPassword('password'))
-+
-+        clientResponse = authRequest2 % (challenge['nonce'], self.getDigestResponse(challenge, "00000002"), challenge['opaque'])
-+        creds = self.credentialFactory.decode(clientResponse, _trivial_GET)
-+        self.failUnless(creds.checkPassword('password'))
-+
-     def testFailsWithDifferentMethod(self):
--        challenge = self.credentialFactory.getChallenge(None)
-+        challenge = self.credentialFactory.getChallenge(address.IPv4Address('TCP', "127.0.0.1", 80))
-         
--        creds = self.credentialFactory.decode(authRequest, SimpleRequest(None, 'POST', '/'))
-+        clientResponse = authRequest1 % (challenge['nonce'], self.getDigestResponse(challenge, "00000001"), challenge['opaque'])
-+        creds = self.credentialFactory.decode(clientResponse, SimpleRequest(None, 'POST', '/'))
-         self.failIf(creds.checkPassword('password'))
- 
-     def testNoUsername(self):
-@@ -221,7 +260,7 @@
- 
-         def respond(ign):
-             d = self.assertResponse((root, 'http://localhost/',
--                                     {'authorization': authRequest}),
-+                                     {'authorization': authRequest1}),
-                                     (200,
-                                      {},
-                                      None))

Modified: CalendarServer/trunk/run
===================================================================
--- CalendarServer/trunk/run	2007-03-06 23:47:08 UTC (rev 1338)
+++ CalendarServer/trunk/run	2007-03-06 23:58:59 UTC (rev 1339)
@@ -476,8 +476,8 @@
     proto="svn";
     ;;
 esac;
-svn_uri="${proto}://svn.twistedmatrix.com/svn/Twisted/branches/dav-acl-1608-2";
-svn_get "Twisted" "${twisted}" "${svn_uri}" 18545;
+svn_uri="${proto}://svn.twistedmatrix.com/svn/Twisted/branches/dav-acl-1608-4";
+svn_get "Twisted" "${twisted}" "${svn_uri}" 19773;
 
 # No py_build step, since we tend to do edit Twisted, we want the sources in
 # PYTHONPATH, not a build directory.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20070306/9c6af545/attachment.html


More information about the calendarserver-changes mailing list