[CalendarServer-changes] [73] CalendarServer/branches/users/cdaboo/acl-merge/patches/Twisted/twisted.web2.dav.resource.patch

source_changes at macosforge.org source_changes at macosforge.org
Mon Aug 28 07:19:34 PDT 2006


Revision: 73
Author:   cdaboo at apple.com
Date:     2006-08-28 07:19:31 -0700 (Mon, 28 Aug 2006)

Log Message:
-----------
Latest merges with twisted branch.

Modified Paths:
--------------
    CalendarServer/branches/users/cdaboo/acl-merge/patches/Twisted/twisted.web2.dav.resource.patch

Modified: CalendarServer/branches/users/cdaboo/acl-merge/patches/Twisted/twisted.web2.dav.resource.patch
===================================================================
--- CalendarServer/branches/users/cdaboo/acl-merge/patches/Twisted/twisted.web2.dav.resource.patch	2006-08-28 14:19:10 UTC (rev 72)
+++ CalendarServer/branches/users/cdaboo/acl-merge/patches/Twisted/twisted.web2.dav.resource.patch	2006-08-28 14:19:31 UTC (rev 73)
@@ -1,390 +1,121 @@
 Index: twisted/web2/dav/resource.py
 ===================================================================
---- twisted/web2/dav/resource.py	(revision 17940)
+--- twisted/web2/dav/resource.py	(revision 17967)
 +++ twisted/web2/dav/resource.py	(working copy)
-@@ -34,7 +34,6 @@
- ]
- 
- import urllib
--import itertools
- 
- from zope.interface import implements
- from twisted.python import log
-@@ -262,7 +261,8 @@
-                 if name == "acl":
-                     return ifAllowed(
-                         (davxml.ReadACL(),),
--                        lambda: self.accessControlList(request)
-+                        # TODO: Merge change from original patch
-+                        lambda: self.safeAccessControlList(request)
-                     )
- 
-             if namespace == twisted_dav_namespace:
-@@ -582,17 +582,28 @@
- 
-         authHeader = request.headers.getHeader('authorization')
-         if authHeader is not None:
--            if authHeader[0] in request.credentialFactories:
-+            if authHeader[0] not in request.credentialFactories:
-                 log.err("Client authentication scheme %s is not provided by server %s"
-                         % (authHeader[0], request.credentialFactories.keys()))
--                return succeed((True, False))
-+                raise HTTPError(responsecode.FORBIDDEN)
-             else:
+@@ -593,9 +593,6 @@
                  factory = request.credentialFactories[authHeader[0]]
  
--                # FIXME: response, req are not defined
--                creds = factory.decode(response, req.method)
-+                creds = factory.decode(authHeader[1], request.method)
-+
-+                # Try to match principals in each principal collection on the resource
-+                pdetails = self.findPrincipalForAuthID(request, creds.username)
-+                assert pdetails.called
-+                pdetails = pdetails.result
-+                if pdetails:
-+                    principal = IDAVPrincipalResource(pdetails[0])
-+                    principalURI = pdetails[1]
-+                else:
-+                   raise HTTPError(responsecode.FORBIDDEN) 
-+                from twisted.web2.dav.auth import PrincipalCredentials
-+                pcreds = PrincipalCredentials(principal, principalURI, creds)
+                 creds = factory.decode(authHeader[1], request.method)
+-                
+-
+-                creds = factory.decode(authHeader[1], request.method)
  
--                d = request.portal.login(creds, None, *request.loginInterfaces)
-+                d = request.portal.login(pcreds, None, *request.loginInterfaces)
-                 d.addCallback(loginSuccess)
-                 return d
-         else:
-@@ -609,7 +620,7 @@
+                 # Try to match principals in each principal collection on 
+                 # the resource
+@@ -635,7 +632,7 @@
          @return: the current principal, as derived from the given request.
          """
          if hasattr(request, "user"):
--            return request.user
-+            return request.user.element
+-            return request.user.element
++            return request.user
          else:
              return unauthenticatedPrincipal
  
-@@ -716,6 +727,10 @@
-         yield oldacl
-         oldacl = oldacl.getResult()
+@@ -760,7 +757,10 @@
+                 elif isinstance(item, davxml.SupportedPrivilege):
+                     addSupportedPrivilege(item)
  
-+        # Check disabled
-+        if oldacl is None:
-+            yield None
-+
-         # Need to get list of supported privileges
-         supported = []
-         def addSupportedPrivilege(sp):
-@@ -747,10 +762,18 @@
-                         yield (davxml.dav_namespace, "no-protected-ace-conflict")
-                         return
-                     # Step 2
--                    elif oldace.inherited:
--                        log.err("Attempt to overwrite inherited ace %r on resource %r" % (oldace, self))
--                        yield (davxml.dav_namespace, "no-inherited-ace-conflict")
--                        return
-+                    """
-+                    RFC3744 says that we either enforce the inherited ace conflict or we ignore it
-+                    # but use access control evaluation to determine whether there us any impact. Given that we
-+                    # have the 'inheritable' behavior it does not make sense to disallow overrides of inherited ACEs
-+                    # since 'inheritable' cannot itself be controlled via protocol.
-+                    
-+                    So the following lines have been commented out for now.
-+                    """
-+                    #elif oldace.inherited:
-+                    #    log.err("Attempt to overwrite inherited ace %r on resource %r" % (oldace, self))
-+                    #    yield (davxml.dav_namespace, "no-inherited-ace-conflict")
-+                    #    return
- 
-             # Step 3
-             if ace.allow and got_deny:
-@@ -806,7 +829,7 @@
-         # FIXME: verify acl is self-consistent
- 
-         # Step 11
--        self.writeDeadProperty(TwistedACLProperty(davxml.ACL(*newset)))
-+        self.writeNewACEs(newset)
-         yield None
- 
-     mergeAccessControlList = deferredGenerator(mergeAccessControlList)
-@@ -811,7 +834,24 @@
- 
-     mergeAccessControlList = deferredGenerator(mergeAccessControlList)
-         
--    def checkAccess(self, request, privileges, recurse=False, principal=None):
-+    def writeNewACEs(self, newaces):
-+        """
-+        Write a new ACL to the resource's property store.
-+        NB We have this as a separate method so that it can be overridden by resources that need to do extra
-+        processing of ACLs being set via the ACL command.
-+        
-+        @param newaces: C{list} of L{ACE} for ACL being set.
-+        """
-+        self.writeDeadProperty(TwistedACLProperty(davxml.ACL(*newaces)))
-+
-+    def matchPrivilege(self, privilege, ace_privileges, supportedPrivileges):
-+        for ace_privilege in ace_privileges:
-+            if privilege == ace_privilege or ace_privilege.isAggregateOf(privilege, supportedPrivileges):
-+                return True
-+
-+        return False
-+
-+    def checkAccess(self, request, privileges, recurse=False, principal=None, inheritedaces=None):
-         """
-         Check whether the given principal has the given privileges.
-         (RFC 3744, section 5.5)
-@@ -821,6 +861,8 @@
-         @param recurse: a boolean.  C{True} if a recursive check on all child
-             resources should be performed as well, C{False} otherwise.  (Has
-             no effect if this resource is not a collection resource.)
-+        @param inheritedaces: a list of L{Aces} corresponding to the precomputed
-+            inheritable aces from the parent resource hierarchy.
-         @return: A L{Deferred} that callbacks with C{None} or errbacks with an
-             L{twisted.web2.dav.acl.AccessDeniedError}
-         """
-@@ -828,7 +870,9 @@
-         from twisted.web2.dav.acl import AccessDeniedError
-         if principal is None:
-             principal = self.currentPrincipal(request)
--        supportedPrivileges = self.supportedPrivileges(request)
+-        for item in self.supportedPrivileges(request).children:
 +        supportedPrivs = waitForDeferred(self.supportedPrivileges(request))
 +        yield supportedPrivs
 +        supportedPrivs = supportedPrivs.getResult()
++        for item in supportedPrivs.children:
+             assert (
+                 isinstance(item, davxml.SupportedPrivilege),
+                 "Not a SupportedPrivilege: %r" % (item,)
+@@ -920,7 +920,7 @@
+         yield ign
+         ign.getResult()
  
-         # Other principals types don't make sense as actors.
-         assert (
-@@ -838,7 +882,7 @@
+-        for resource, subpath in resources:
++        for resource, uri in resources:
+             acl = waitForDeferred(resource.accessControlList(request))
+             yield acl
+             acl = acl.getResult()
+@@ -930,7 +930,7 @@
  
-         def match_privilege(privilege, ace_privileges):
-             for ace_privilege in ace_privileges:
--                if privilege == ace_privilege or ace_privilege.isAggregateOf(privilege, supportedPrivileges):
-+                if privilege == ace_privilege or ace_privilege.isAggregateOf(privilege, supportedPrivs):
-                     return True
+             for ace in acl.children:
+                 for privilege in tuple(pending):
+-                    if not match_privilege(privilege, ace.privileges):
++                    if not match_privilege(davxml.Privilege(privilege), ace.privileges):
+                         continue
  
-             return False
-@@ -906,7 +950,7 @@
-         This implementation returns a supported privilege set containing only
-         the DAV:all privilege.
-         """
--        return allPrivilegeSet
-+        return succeed(allPrivilegeSet)
+                     match = waitForDeferred(self.matchPrincipal(principal, ace.principal, request))
+@@ -952,7 +952,7 @@
+             denied += pending # If no matching ACE, then denied
  
-     def currentPrivileges(self, request):
-         """
-@@ -918,7 +962,13 @@
-         current = self.currentPrincipal(request)
-         return self.privilegesForPrincipal(current, request)
+             if denied: 
+-                errors.append((subpath, denied))
++                errors.append((uri, denied))
  
--    def accessControlList(self, request, inheritance=True, expanding=False):
-+    def safeAccessControlList(self, request):
-+        acl = self.accessControlList(request)
-+        if acl is None:
-+            acl = davxml.ACL()
-+        return acl
-+
-+    def accessControlList(self, request, inheritance=True, expanding=False, inheritedaces=None):
-         """
-         See L{IDAVResource.accessControlList}.
- 
-@@ -926,6 +976,7 @@
-         C{(L{twisted_private_namespace}, "acl")}.
-         If no ACL has been stored for this resource, it returns the value
-         returned by C{defaultAccessControlList}.
-+        If access is disabled it will return C{None}.
-         """
-         #
-         # Inheritance is problematic. Here is what we do:
-@@ -941,6 +992,12 @@
-         # If those are defined, the relevant ace is applied to the ACL on the
-         # current resource.
-         #
-+
-+        # Check disabled
-+        disabled = self.hasDeadProperty(TwistedAccessDisabledProperty)
-+        if disabled:
-+            yield None
-+
-         myURL = None
- 
-         def getMyURL():
-@@ -976,29 +1033,36 @@
-             if myURL is None:
-                 myURL = getMyURL()
- 
--            if myURL != "/":
--                parentURL = parentForURL(myURL)
--
--                parent = waitForDeferred(request.locateResource(parentURL))
--                yield parent
--                parent = parent.getResult()
--
--                if parent:
--                    parent_acl = waitForDeferred(
--                        parent.accessControlList(request, inheritance=True, expanding=True)
--                    )
--                    yield parent_acl
--                    parent_acl = parent_acl.getResult()
--
--                    for ace in parent_acl.children:
--                        if ace.inherited:
--                            aces.append(ace)
--                        elif TwistedACLInheritable() in ace.children:
--                            # Adjust ACE for inherit on this resource
--                            children = list(ace.children)
--                            children.remove(TwistedACLInheritable())
--                            children.append(davxml.Inherited(davxml.HRef.fromString(parentURL)))
--                            aces.append(davxml.ACE(*children))
-+            if inheritedaces is None:
-+                if myURL != "/":
-+                    parentURL = parentForURL(myURL)
-+    
-+                    parent = waitForDeferred(request.locateResource(parentURL))
-+                    yield parent
-+                    parent = parent.getResult()
-+    
-+                    if parent:
-+                        parent_acl = waitForDeferred(
-+                            parent.accessControlList(request, inheritance=True, expanding=True)
-+                        )
-+                        yield parent_acl
-+                        parent_acl = parent_acl.getResult()
-+    
-+                        # Check disabled
-+                        if parent_acl is None:
-+                            yield None
-+    
-+                        for ace in parent_acl.children:
-+                            if ace.inherited:
-+                                aces.append(ace)
-+                            elif TwistedACLInheritable() in ace.children:
-+                                # Adjust ACE for inherit on this resource
-+                                children = list(ace.children)
-+                                children.remove(TwistedACLInheritable())
-+                                children.append(davxml.Inherited(davxml.HRef.fromString(parentURL)))
-+                                aces.append(davxml.ACE(*children))
-+            else:
-+                aces.extend(inheritedaces)
- 
-             # Always filter out any remaining private properties when we are
-             # returning the ACL for the final resource after doing parent
-@@ -1018,6 +1082,49 @@
- 
-     accessControlList = deferredGenerator(accessControlList)
- 
-+    # TODO: Convert to deferredGenerator
-+    def inheritedACEsforChildren(self, request):
-+        """
-+        Do some optimisation of access control calculation by determining any inherited ACLs outside of
-+        the child resource loop and supply those to the checkAccess on each child.
-+
-+        @param request: the L{IRequest} for the request in progress.
-+        @return:        a C{list} of L{Ace}s that child resources of this one will
-+            inherit and which will match the currently authenticated principal.
-+        """
-+        
-+        # Get the parent ACLs with inheritance and preserve the <inheritable> element.
-+        parent_acl = self.accessControlList(request, inheritance=True, expanding=True)
-+        
-+        # Check disabled
-+        if parent_acl is None:
-+            return None
-+
-+        # Filter out those that are not inheritable (and remove the inheritable element from those that are)
-+        aces = []
-+        for ace in parent_acl.children:
-+            if ace.inherited:
-+                aces.append(ace)
-+            elif TwistedACLInheritable() in ace.children:
-+                # Adjust ACE for inherit on this resource
-+                children = list(ace.children)
-+                children.remove(TwistedACLInheritable())
-+                children.append(davxml.Inherited(davxml.HRef.fromString(request.urlForResource(self))))
-+                aces.append(davxml.ACE(*children))
-+                
-+        # Filter out those that do not have a principal match with the current principal
-+        principal = self.currentPrincipal(request)
-+        filteredaces = []
-+        for ace in aces:
-+            if self.matchPrincipal(principal, ace.principal, request):
-+                if ace.invert:
-+                    continue
-+            else:
-+                if not ace.invert:
-+                    continue
-+            filteredaces.append(ace)
-+        return filteredaces
-+
-     def inheritedACLSet(self):
-         """
-         @return: a sequence of L{davxml.HRef}s from which ACLs are inherited.
-@@ -1054,6 +1161,10 @@
+         if errors:
+             raise AccessDeniedError(errors,)
+@@ -1180,6 +1180,14 @@
                  yield (principal, principalURI)
                  return
          else:
-+            if len(self.principalCollections(request)) == 0:
++            principalCollections = waitForDeferred(self.principalCollections(request))
++            yield principalCollections
++            principalCollections = principalCollections.getResult()
++
++            if len(principalCollections) == 0:
 +                log.msg("<DAV:principal-collection-set> property cannot be found on the resource being authorized: %s" % self)
 +            else:
 +                log.msg("Could not find principal matching user id: %s" % authid)
-             yield None
+             raise HTTPError(responsecode.FORBIDDEN)
  
      findPrincipalForAuthID = deferredGenerator(findPrincipalForAuthID)
-@@ -1135,12 +1246,17 @@
+@@ -1261,7 +1269,7 @@
+         assert principal2 is not None, "principal2 is None"
  
-         # Now principal2 is an HRef
  
+-         # Compare two HRefs and do group membership test as well
 +        # Compare two HRefs and do group membership test as well
          if principal1 == principal2:
              yield True
              return
+@@ -1301,7 +1309,7 @@
+         d = request.locateResource(principal2)
+         d.addCallback(_testGroup)
+         return d
 -
--        # FIXME: We still need to handle the case where principal2 is a group
--        # containing principal1.
 +        
-+        ismember = waitForDeferred(self.principalIsGroupMember(str(principal1), str(principal2), request))
-+        yield ismember
-+        ismember = ismember.getResult()
-+        if ismember:
-+            yield True
-+            return
- 
-         yield False
- 
-@@ -1146,6 +1262,30 @@
- 
-     matchPrincipal = deferredGenerator(matchPrincipal)
- 
-+    def principalIsGroupMember(self, principal1, principal2, request):
-+        """
-+        Check whether one principal is a group member of another.
-+        
-+        @param principal1: C{str} principalURL for principal to test.
-+        @param principal2: C{str} principalURL for possible group principal to test against.
-+        @param request: the request being processed.
-+        @return: L{Deferred} with result C{True} if principal1 is a member of principal2, C{False} otherwise
-+        """
-+        
-+        def _testGroup(group):
-+            # Get principal resource for principal2
-+            from twisted.web2.dav.acl import DAVPrincipalResource
-+            if group and isinstance(group, DAVPrincipalResource):
-+                members = group.groupMembers()
-+                if principal1 in members:
-+                    return True
-+                
-+            return False
-+
-+        d = request.locateResource(principal2)
-+        d.addCallback(_testGroup)
-+        return d
-+        
      def validPrincipal(self, ace_principal, request):
          """
          Check whether the supplied principal is valid for this resource.
-@@ -1207,11 +1347,10 @@
-         All other principals, including meta-principals (eg. L{davxml.All}),
-         resolve to C{None}.
+@@ -1317,16 +1325,16 @@
+             # We know that the element contains a valid element type, so all
+             # we need to do is check for a valid property and a valid href.
+             #
+-            ace_principal = ace_principal.children[0]
++            real_principal = ace_principal.children[0]
  
--        @param principal: the L{davxml.Principal} element to resolve.
-+        @param principal: the L{davxml.Principal} child element to resolve.
+-            if isinstance(ace_principal, davxml.Property):
++            if isinstance(real_principal, davxml.Property):
+                 # See comments in matchPrincipal().  We probably need some common code.
+                 log.err("Encountered a property principal (%s), but handling is not implemented.  Invalid for ACL use."
+-                        % (ace_principal,))
++                        % (real_principal,))
+                 return False
+ 
+-            if isinstance(ace_principal, davxml.HRef):
+-                return self.validHrefPrincipal(ace_principal, request)
++            if isinstance(real_principal, davxml.HRef):
++                return self.validHrefPrincipal(real_principal, request)
+ 
+             return True
+ 
+@@ -1367,7 +1375,6 @@
          @param request: the request being processed.
          @return: a deferred L{davxml.HRef} element or C{None}.
          """
@@ -392,55 +123,19 @@
  
          if isinstance(principal, davxml.Property):
              # raise NotImplementedError("Property principals are not implemented.")
-@@ -1291,6 +1430,10 @@
-         yield acl
-         acl = acl.getResult()
+@@ -1428,15 +1435,6 @@
+         if isinstance(principal, davxml.HRef):
+             yield principal
+         else:
+-            principalCollections = waitForDeferred(
+-                self.principalCollections(request))
+-            yield principalCollections
+-            principalCollections = principalCollections.getResult()
+-
+-            if len(principalCollections) == 0:
+-                log.msg("<DAV:principal-collection-set> property cannot be found on the resource being authorized: %s" % self)
+-            else:
+-                log.msg("Could not find principal matching user id: %s" % authid)
+             yield None
  
-+        # Check disabled
-+        if acl is None:
-+            yield []
-+
-         granted = []
-         denied = []
-         for ace in acl.children:
-@@ -1304,8 +1447,11 @@
-             if match:
-                 # Expand aggregate privileges
-                 ps = []
-+                supportedPrivs = waitForDeferred(self.supportedPrivileges(request))
-+                yield supportedPrivs
-+                supportedPrivs = supportedPrivs.getResult()
-                 for p in ace.privileges:
--                    ps.extend(p.expandAggregate(self.supportedPrivileges(request)))
-+                    ps.extend(p.expandAggregate(supportedPrivs))
- 
-                 # Merge grant/deny privileges
-                 if ace.allow:
-@@ -1430,6 +1576,10 @@
- davxml.registerElement(TwistedPrincipalCollectionSetProperty)
- 
- class TwistedACLInheritable (davxml.WebDAVEmptyElement):
-+    """
-+    When set on an ACE, this indicates that the ACE privileges should be inherited by
-+    all child resources within the resource with this ACE.
-+    """
-     namespace = twisted_dav_namespace
-     name = "inheritable"
- 
-@@ -1436,6 +1586,16 @@
- davxml.registerElement(TwistedACLInheritable)
- davxml.ACE.allowed_children[(twisted_dav_namespace, "inheritable")] = (0, 1)
- 
-+"""
-+When set on a resource, this property indicates that all access to the resource and any of its children
-+is completely disabled - irrespective of any other privileges directly set or inherited.
-+"""
-+class TwistedAccessDisabledProperty (davxml.WebDAVEmptyElement):
-+    namespace = twisted_private_namespace
-+    name = "access-disabled"
-+
-+davxml.registerElement(TwistedAccessDisabledProperty)
-+
- allACL = davxml.ACL(
-     davxml.ACE(
-         davxml.Principal(davxml.All()),
+         assert (

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20060828/432d4e42/attachment.html


More information about the calendarserver-changes mailing list