[CalendarServer-changes] [346]
CalendarServer/branches/users/cdaboo/dropbox
source_changes at macosforge.org
source_changes at macosforge.org
Wed Nov 1 10:45:20 PST 2006
Revision: 346
http://trac.macosforge.org/projects/calendarserver/changeset/346
Author: cdaboo at apple.com
Date: 2006-11-01 10:45:19 -0800 (Wed, 01 Nov 2006)
Log Message:
-----------
Merge from trunk.
Modified Paths:
--------------
CalendarServer/branches/users/cdaboo/dropbox/conf/repository-static.xml
CalendarServer/branches/users/cdaboo/dropbox/conf/repository.dtd
CalendarServer/branches/users/cdaboo/dropbox/lib-patches/Twisted/twisted.web2.dav.resource.patch
CalendarServer/branches/users/cdaboo/dropbox/lib-patches/Twisted/twisted.web2.dav.static.patch
CalendarServer/branches/users/cdaboo/dropbox/lib-patches/Twisted/twisted.web2.server.patch
CalendarServer/branches/users/cdaboo/dropbox/support/submit
CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/authkerb.py
CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/caldavxml.py
CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/customxml.py
CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/directory.py
CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/logging.py
CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/method/__init__.py
CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/repository.py
CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/resource.py
CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/static.py
Added Paths:
-----------
CalendarServer/branches/users/cdaboo/dropbox/conf/repository-proxy.xml
CalendarServer/branches/users/cdaboo/dropbox/lib-patches/Twisted/twisted.dav.auth.patch
CalendarServer/branches/users/cdaboo/dropbox/lib-patches/Twisted/twisted.web2.dav.test.test_resource.patch
Removed Paths:
-------------
CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/method/schedule.py
Copied: CalendarServer/branches/users/cdaboo/dropbox/conf/repository-proxy.xml (from rev 341, CalendarServer/trunk/conf/repository-proxy.xml)
===================================================================
--- CalendarServer/branches/users/cdaboo/dropbox/conf/repository-proxy.xml (rev 0)
+++ CalendarServer/branches/users/cdaboo/dropbox/conf/repository-proxy.xml 2006-11-01 18:45:19 UTC (rev 346)
@@ -0,0 +1,224 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+Copyright (c) 2006 Apple Computer, 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.
+ -->
+
+<!DOCTYPE repository SYSTEM "repository.dtd">
+
+<repository>
+
+ <docroot auto-principal-collection-set="no">
+ <collection>
+ <pytype>twisted.web2.dav.static.DAVFile</pytype>
+ <properties>
+ <acl>
+ <ace>
+ <principal><authenticated/></principal>
+ <grant><privilege><read/></privilege></grant>
+ <protected/>
+ </ace>
+ <ace>
+ <principal><href>/principals/users/admin</href></principal>
+ <grant><privilege><all/></privilege></grant>
+ <protected/>
+ <inheritable/>
+ </ace>
+ </acl>
+ <!--
+ Must explicitly set which principal hierarchies will be
+ listed in WebDAV properties. The order of these will
+ determine how a user id will map to a principal in a
+ particular hierarchy if an id appears in more than one.
+ -->
+ <prop><principal-collection-set xmlns="DAV:"><href>/principals/localusers/</href><href>/principals/users/</href><href>/principals/users/</href><href>/principals/groups/</href><href>/principals/resources/</href></principal-collection-set></prop>
+ </properties>
+ <members>
+ <!--
+ We must define the calendar home location before the
+ principals as auto-provisioning of accounts occurs when the
+ principal collections are created and we need to have the
+ calendar home path setup by then.
+ -->
+ <collection name="calendars" tag="calendars">
+ <pytype>twistedcaldav.static.CalDAVFile</pytype>
+ <properties>
+ <acl>
+ <ace>
+ <principal><authenticated/></principal>
+ <grant><privilege><read/></privilege></grant>
+ <protected/>
+ </ace>
+ </acl>
+ </properties>
+ <members>
+ <collection name="users">
+ <pytype>twistedcaldav.static.CalendarHomeProvisioningFile</pytype>
+ <properties>
+ <acl>
+ <ace>
+ <principal><authenticated/></principal>
+ <grant><privilege><read/></privilege></grant>
+ <protected/>
+ </ace>
+ </acl>
+ </properties>
+ <members/>
+ </collection>
+ <collection name="groups">
+ <pytype>twistedcaldav.static.CalendarHomeProvisioningFile</pytype>
+ <properties>
+ <acl>
+ <ace>
+ <principal><authenticated/></principal>
+ <grant><privilege><read/></privilege></grant>
+ <protected/>
+ </ace>
+ </acl>
+ </properties>
+ <members/>
+ </collection>
+ <collection name="resources">
+ <pytype>twistedcaldav.static.CalendarHomeProvisioningFile</pytype>
+ <properties>
+ <acl>
+ <ace>
+ <principal><authenticated/></principal>
+ <grant><privilege><read/></privilege></grant>
+ <protected/>
+ </ace>
+ </acl>
+ </properties>
+ <members/>
+ </collection>
+ <collection name="public">
+ <properties>
+ <acl>
+ <ace>
+ <principal><unauthenticated/></principal>
+ <grant><privilege><read/></privilege></grant>
+ <protected/>
+ <inheritable/>
+ </ace>
+ <ace>
+ <principal><authenticated/></principal>
+ <grant><privilege><read/></privilege></grant>
+ <protected/>
+ <inheritable/>
+ </ace>
+ </acl>
+ </properties>
+ <members/>
+ </collection>
+ </members>
+ </collection>
+ <collection name="principals">
+ <pytype>twistedcaldav.directory.DirectoryPrincipalProvisioningResource</pytype>
+ <params>
+ <param>
+ <key>DirectoryNode</key>
+ <value>/Search</value>
+ </param>
+ </params>
+ <properties>
+ <acl>
+ <ace>
+ <principal><authenticated/></principal>
+ <grant><privilege><read/></privilege></grant>
+ <protected/>
+ </ace>
+ </acl>
+ </properties>
+ <members>
+ <collection name="users">
+ <pytype>twistedcaldav.directory.DirectoryUserPrincipalProvisioningResource</pytype>
+ <properties>
+ <acl>
+ <ace>
+ <principal><authenticated/></principal>
+ <grant><privilege><read/></privilege></grant>
+ <protected/>
+ </ace>
+ </acl>
+ </properties>
+ <members/>
+ </collection>
+ <collection name="groups">
+ <pytype>twistedcaldav.directory.DirectoryGroupPrincipalProvisioningResource</pytype>
+ <properties>
+ <acl>
+ <ace>
+ <principal><authenticated/></principal>
+ <grant><privilege><read/></privilege></grant>
+ <protected/>
+ </ace>
+ </acl>
+ </properties>
+ <members/>
+ </collection>
+ <collection name="resources">
+ <pytype>twistedcaldav.directory.DirectoryResourcePrincipalProvisioningResource</pytype>
+ <properties>
+ <acl>
+ <ace>
+ <principal><authenticated/></principal>
+ <grant><privilege><read/></privilege></grant>
+ <protected/>
+ </ace>
+ </acl>
+ </properties>
+ <members/>
+ </collection>
+ <collection name="localusers" tag="principals">
+ <pytype>twistedcaldav.static.CalendarPrincipalCollectionFile</pytype>
+ <properties>
+ <acl>
+ <ace>
+ <principal><href>/principals/users/admin</href></principal>
+ <grant><privilege><read/></privilege></grant>
+ <protected/>
+ </ace>
+ </acl>
+ </properties>
+ <members/>
+ </collection>
+ </members>
+ </collection>
+ </members>
+ </collection>
+ </docroot>
+
+ <authentication>
+ <basic enable="yes" onlyssl="yes" credentials="directory">
+ <realm></realm>
+ </basic>
+ <digest enable="no" onlyssl="no" credentials="property">
+ <realm></realm>
+ </digest>
+ <kerberos enable="no" onlyssl="no">
+ <service></service>
+ </kerberos>
+ </authentication>
+
+<accounts>
+ <user>
+ <uid>proxy</uid>
+ <pswd>proxy</pswd>
+ <name>User who can authorize as someone else</name>
+ <canproxy/>
+ </user>
+</accounts>
+
+</repository>
Modified: CalendarServer/branches/users/cdaboo/dropbox/conf/repository-static.xml
===================================================================
--- CalendarServer/branches/users/cdaboo/dropbox/conf/repository-static.xml 2006-11-01 00:07:35 UTC (rev 345)
+++ CalendarServer/branches/users/cdaboo/dropbox/conf/repository-static.xml 2006-11-01 18:45:19 UTC (rev 346)
@@ -52,7 +52,7 @@
</properties>
<members>
<collection name="users" tag="principals">
- <pytype>twistedcaldav.static.CalendarUserPrincipalProvisioningResource</pytype>
+ <pytype>twistedcaldav.static.CalendarPrincipalCollectionFile</pytype>
<properties>
<acl>
<ace>
@@ -134,6 +134,12 @@
<pswd>admin</pswd>
<name>Super User</name>
</user>
+ <user>
+ <uid>proxy</uid>
+ <pswd>proxy</pswd>
+ <name>User who can authorize as someone else</name>
+ <canproxy/>
+ </user>
<user repeat='99'>
<uid>user%02d</uid>
<pswd>user%02d</pswd>
Modified: CalendarServer/branches/users/cdaboo/dropbox/conf/repository.dtd
===================================================================
--- CalendarServer/branches/users/cdaboo/dropbox/conf/repository.dtd 2006-11-01 00:07:35 UTC (rev 345)
+++ CalendarServer/branches/users/cdaboo/dropbox/conf/repository.dtd 2006-11-01 18:45:19 UTC (rev 346)
@@ -66,7 +66,7 @@
<!ELEMENT accounts (user*) >
- <!ELEMENT user (uid, pswd, name, cuaddr*, calendar*, acl?, quota?, autorespond?)>
+ <!ELEMENT user (uid, pswd, name, cuaddr*, calendar*, acl?, quota?, autorespond?, canproxy?)>
<!ATTLIST user repeat CDATA "1">
<!ELEMENT uid (#PCDATA)>
<!ELEMENT pswd (#PCDATA)>
@@ -76,3 +76,5 @@
<!ELEMENT calendar (#PCDATA)>
<!ELEMENT quota (#PCDATA)>
<!ELEMENT autorespond EMPTY>
+ <!ELEMENT canproxy EMPTY>
+
\ No newline at end of file
Copied: CalendarServer/branches/users/cdaboo/dropbox/lib-patches/Twisted/twisted.dav.auth.patch (from rev 341, CalendarServer/trunk/lib-patches/Twisted/twisted.dav.auth.patch)
===================================================================
--- CalendarServer/branches/users/cdaboo/dropbox/lib-patches/Twisted/twisted.dav.auth.patch (rev 0)
+++ CalendarServer/branches/users/cdaboo/dropbox/lib-patches/Twisted/twisted.dav.auth.patch 2006-11-01 18:45:19 UTC (rev 346)
@@ -0,0 +1,66 @@
+Index: twisted/web2/dav/auth.py
+===================================================================
+--- twisted/web2/dav/auth.py (revision 18545)
++++ twisted/web2/dav/auth.py (working copy)
+@@ -40,7 +40,7 @@
+
+ def requestAvatar(self, avatarId, mind, *interfaces):
+ if IPrincipal in interfaces:
+- return IPrincipal, davxml.Principal(davxml.HRef(avatarId))
++ return IPrincipal, davxml.Principal(davxml.HRef(avatarId[0])), davxml.Principal(davxml.HRef(avatarId[1]))
+
+ raise NotImplementedError("Only IPrincipal interface is supported")
+
+@@ -52,9 +52,23 @@
+ class PrincipalCredentials(object):
+ implements(IPrincipalCredentials)
+
+- def __init__(self, principal, principalURI, credentials):
+- self.principal = principal
+- self.principalURI = principalURI
++ def __init__(self, authnPrincipal, authnURI, authzPrincipal, authzURI, credentials):
++ """
++ Initialize with both authentication and authorization values. Note that in most cases theses will be the same
++ since HTTP auth makes no distinction between the two - but we may be layering some addition auth on top of this
++ (.e.g.. proxy auth, cookies, forms etc) that make result in authentication and authorization being different.
++
++ @param authnPrincipal: L{IDAVPrincipalResource} for the authenticated principal.
++ @param authnURI: C{str} containing the URI of the authenticated principal.
++ @param authzPrincipal: L{IDAVPrincipalResource} for the authorized principal.
++ @param authzURI: C{str} containing the URI of the authorized principal.
++ @param credentials: L{IPrincipalCredentials} for the authentication credentials.
++ """
++
++ self.authnPrincipal = authnPrincipal
++ self.authnURI = authnURI
++ self.authzPrincipal = authzPrincipal
++ self.authzURI = authzURI
+ self.credentials = credentials
+
+ def checkPassword(self, password):
+@@ -66,19 +80,20 @@
+
+ credentialInterfaces = (IPrincipalCredentials,)
+
+- def _cbPasswordMatch(self, matched, principalURI):
++ def _cbPasswordMatch(self, matched, principalURIs):
+ if matched:
+- return principalURI
++ # We return both URIs
++ return principalURIs
+ else:
+ raise error.UnauthorizedLogin(
+- "Bad credentials for: %s" % (principalURI,))
++ "Bad credentials for: %s" % (principalURIs[0],))
+
+ def requestAvatarId(self, credentials):
+ pcreds = IPrincipalCredentials(credentials)
+- pswd = str(pcreds.principal.readDeadProperty(TwistedPasswordProperty))
++ pswd = str(pcreds.authnPrincipal.readDeadProperty(TwistedPasswordProperty))
+
+ d = defer.maybeDeferred(credentials.checkPassword, pswd)
+- d.addCallback(self._cbPasswordMatch, pcreds.principalURI)
++ d.addCallback(self._cbPasswordMatch, (pcreds.authnURI, pcreds.authzURI,))
+ return d
+
+ ##
Modified: CalendarServer/branches/users/cdaboo/dropbox/lib-patches/Twisted/twisted.web2.dav.resource.patch
===================================================================
--- CalendarServer/branches/users/cdaboo/dropbox/lib-patches/Twisted/twisted.web2.dav.resource.patch 2006-11-01 00:07:35 UTC (rev 345)
+++ CalendarServer/branches/users/cdaboo/dropbox/lib-patches/Twisted/twisted.web2.dav.resource.patch 2006-11-01 18:45:19 UTC (rev 346)
@@ -98,7 +98,212 @@
child.addCallback(checkPrivileges)
child.addCallbacks(gotChild, checkPrivilegesError, (childpath,))
child.addErrback(completionDeferred.errback)
-@@ -1511,6 +1561,265 @@
+@@ -574,9 +624,9 @@
+ def onErrors(failure):
+ failure.trap(AccessDeniedError)
+
+- # If we were unauthorized to start with (no Authorization header from client) then
++ # If we were unauthenticated to start with (no Authorization header from client) then
+ # we should return an unauthorized response instead to force the client to login if it can
+- if request.user == davxml.Principal(davxml.Unauthenticated()):
++ if request.authnUser == davxml.Principal(davxml.Unauthenticated()):
+ response = UnauthorizedResponse(request.credentialFactories,
+ request.remoteAddr)
+ else:
+@@ -600,8 +650,13 @@
+
+ def authenticate(self, request):
+ def loginSuccess(result):
+- request.user = result[1]
+- return request.user
++ """
++ @param result: returned tuple from auth.DAVRealm.requestAvatar.
++ """
++
++ request.authnUser = result[1]
++ request.authzUser = result[2]
++ return (request.authnUser, request.authzUser,)
+
+ if not (
+ hasattr(request, 'portal') and
+@@ -608,8 +663,9 @@
+ hasattr(request, 'credentialFactories') and
+ hasattr(request, 'loginInterfaces')
+ ):
+- request.user = davxml.Principal(davxml.Unauthenticated())
+- return request.user
++ request.authnUser = davxml.Principal(davxml.Unauthenticated())
++ request.authzUser = davxml.Principal(davxml.Unauthenticated())
++ return (request.authnUser, request.authzUser,)
+
+ authHeader = request.headers.getHeader('authorization')
+
+@@ -625,9 +681,11 @@
+
+ # Try to match principals in each principal collection on the resource
+ def gotDetails(details):
+- principal = IDAVPrincipalResource(details[0])
+- principalURI = details[1]
+- return PrincipalCredentials(principal, principalURI, creds)
++ authnPrincipal = IDAVPrincipalResource(details[0][0])
++ authnURI = details[0][1]
++ authzPrincipal = IDAVPrincipalResource(details[1][0])
++ authzURI = details[1][1]
++ return PrincipalCredentials(authnPrincipal, authnURI, authzPrincipal, authzURI, creds)
+
+ def login(pcreds):
+ d = request.portal.login(pcreds, None, *request.loginInterfaces)
+@@ -635,7 +693,7 @@
+
+ return d
+
+- d = self.findPrincipalForAuthID(request, creds.username)
++ d = self.principalsForAuthID(request, creds.username)
+ d.addCallback(gotDetails).addCallback(login)
+
+ return d
+@@ -640,8 +698,9 @@
+
+ return d
+ else:
+- request.user = davxml.Principal(davxml.Unauthenticated())
+- return request.user
++ request.authnUser = davxml.Principal(davxml.Unauthenticated())
++ request.authzUser = davxml.Principal(davxml.Unauthenticated())
++ return (request.authnUser, request.authzUser,)
+
+ ##
+ # ACL
+@@ -650,10 +709,10 @@
+ def currentPrincipal(self, request):
+ """
+ @param request: the request being processed.
+- @return: the current principal, as derived from the given request.
++ @return: the current authorized principal, as derived from the given request.
+ """
+- if hasattr(request, "user"):
+- return request.user
++ if hasattr(request, "authzUser"):
++ return request.authzUser
+ else:
+ return unauthenticatedPrincipal
+
+@@ -1149,8 +1208,12 @@
+
+ return []
+
+- def findPrincipalForAuthID(self, request, authid):
++ def principalsForAuthID(self, request, authid):
+ """
++ Return authentication and authorization prinicipal identifiers for the
++ authentication identifer passed in. In this implementation authn and authz
++ principals are the same.
++
+ @param request: the L{IRequest} for the request in progress.
+ @param authid: a string containing the
+ authentication/authorization identifier for the principal
+@@ -1155,12 +1218,55 @@
+ @param authid: a string containing the
+ authentication/authorization identifier for the principal
+ to lookup.
+- @return: a deferred tuple of C{(principal, principalURI)}
+- where: C{principal} is the L{Principal} that is found;
+- C{principalURI} is the C{str} URI of the principal.
++ @return: a deferred tuple of two tuples. Each tuple is
++ C{(principal, principalURI)} where: C{principal} is the L{Principal}
++ that is found; {principalURI} is the C{str} URI of the principal.
++ The first tuple corresponds to authentication identifiers,
++ the second to authorization identifiers.
+ It will errback with an HTTPError(responsecode.FORBIDDEN) if
+ the principal isn't found.
+ """
++
++ # Try to match principals in each principal collection on the resource
++ d = waitForDeferred(self.findPrincipalForAuthID(request, authid))
++ yield d
++ result = d.getResult()
++
++ if result is not None:
++ authnPrincipal = result[0]
++ authnURI = result[1]
++ d = waitForDeferred(self.authorizationPrincipal(request, authid, authnPrincipal, authnURI))
++ yield d
++ authzPrincipal, authzURI = d.getResult()
++ yield ((authnPrincipal, authnURI), (authzPrincipal, authzURI),)
++ return
++ 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)
++ raise HTTPError(responsecode.FORBIDDEN)
++
++ principalsForAuthID = deferredGenerator(principalsForAuthID)
++
++ def findPrincipalForAuthID(self, request, authid):
++ """
++ Return authentication and authoirization prinicipal identifiers for the
++ authentication identifer passed in. In this implementation authn and authz
++ principals are the same.
++
++ @param request: the L{IRequest} for the request in progress.
++ @param authid: a string containing the
++ authentication/authorization identifier for the principal
++ to lookup.
++ @return: a tuple of C{(principal, principalURI)} where: C{principal} is the L{Principal}
++ that is found; {principalURI} is the C{str} URI of the principal.
++ If not found return None.
++ """
+ # Try to match principals in each principal collection on the resource
+ collections = waitForDeferred(self.principalCollections(request))
+ yield collections
+@@ -1173,22 +1279,30 @@
+ yield principal
+ principal = principal.getResult()
+
+- if isPrincipalResource(principal):
+- yield (principal, principalURI)
++ if isPrincipalResource(principal) and principal.exists():
++ yield principal, principalURI
+ return
+ 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)
+- raise HTTPError(responsecode.FORBIDDEN)
++ yield None
++ return
+
+ findPrincipalForAuthID = deferredGenerator(findPrincipalForAuthID)
+
++ def authorizationPrincipal(self, request, authid, authnPrincipal, authnURI):
++ """
++ Determine the authorization principal for the given request and authentication principal.
++ This implementation simply uses aht authentication principalk as the authoization principal.
++
++ @param request: the L{IRequest} for the request in progress.
++ @param authid: a string containing the uthentication/authorization identifier
++ for the principal to lookup.
++ @param authnPrincipal: the L{IDAVPrincipal} for the authenticated principal
++ @param authnURI: a C{str} containing the URI of the authenticated principal
++ @return: a deferred result C{tuple} of (L{IDAVPrincipal}, C{str}) containing the authorization principal
++ resource and URI respectively.
++ """
++ return succeed((authnPrincipal, authnURI,))
++
+ def samePrincipal(self, principal1, principal2):
+ """
+ Check whether the two prinicpals are exactly the same in terms of
+@@ -1511,6 +1625,265 @@
return None
##
@@ -364,7 +569,7 @@
# HTTP
##
-@@ -1558,7 +1867,7 @@
+@@ -1558,7 +1931,7 @@
"""
DAV resource with no children.
"""
@@ -373,7 +578,7 @@
return succeed(None)
class DAVPrincipalResource (DAVLeafResource):
-@@ -1712,6 +2021,37 @@
+@@ -1712,6 +2085,37 @@
davxml.registerElement(TwistedACLInheritable)
davxml.ACE.allowed_children[(twisted_dav_namespace, "inheritable")] = (0, 1)
Modified: CalendarServer/branches/users/cdaboo/dropbox/lib-patches/Twisted/twisted.web2.dav.static.patch
===================================================================
--- CalendarServer/branches/users/cdaboo/dropbox/lib-patches/Twisted/twisted.web2.dav.static.patch 2006-11-01 00:07:35 UTC (rev 345)
+++ CalendarServer/branches/users/cdaboo/dropbox/lib-patches/Twisted/twisted.web2.dav.static.patch 2006-11-01 18:45:19 UTC (rev 346)
@@ -96,3 +96,12 @@
# Workarounds for issues with File
##
+@@ -164,7 +213,7 @@
+ children = []
+
+ def found(request, uri):
+- children.append(uri.split("/")[-1].rstrip("/"))
++ children.append(uri.rstrip("/").split("/")[-1])
+
+ x = waitForDeferred(
+ self.findChildren("1", request, found, (davxml.Read(),),
Copied: CalendarServer/branches/users/cdaboo/dropbox/lib-patches/Twisted/twisted.web2.dav.test.test_resource.patch (from rev 341, CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_resource.patch)
===================================================================
--- CalendarServer/branches/users/cdaboo/dropbox/lib-patches/Twisted/twisted.web2.dav.test.test_resource.patch (rev 0)
+++ CalendarServer/branches/users/cdaboo/dropbox/lib-patches/Twisted/twisted.web2.dav.test.test_resource.patch 2006-11-01 18:45:19 UTC (rev 346)
@@ -0,0 +1,25 @@
+Index: twisted/web2/dav/test/test_resource.py
+===================================================================
+--- twisted/web2/dav/test/test_resource.py (revision 18545)
++++ twisted/web2/dav/test/test_resource.py (working copy)
+@@ -282,7 +282,8 @@
+ # Has auth; should allow
+
+ request = SimpleRequest(site, "GET", "/")
+- request.user = davxml.Principal(davxml.HRef("/users/d00d"))
++ request.authnUser = davxml.Principal(davxml.HRef("/users/d00d"))
++ request.authzUser = davxml.Principal(davxml.HRef("/users/d00d"))
+ d = request.locateResource('/')
+ d.addCallback(_checkPrivileges)
+ d.addCallback(expectOK)
+@@ -380,8 +381,8 @@
+ return succeed(davPrivilegeSet)
+
+ def currentPrincipal(self, request):
+- if hasattr(request, "user"):
+- return request.user
++ if hasattr(request, "authzUser"):
++ return request.authzUser
+ else:
+ return davxml.Principal(davxml.Unauthenticated())
+
Modified: CalendarServer/branches/users/cdaboo/dropbox/lib-patches/Twisted/twisted.web2.server.patch
===================================================================
--- CalendarServer/branches/users/cdaboo/dropbox/lib-patches/Twisted/twisted.web2.server.patch 2006-11-01 00:07:35 UTC (rev 345)
+++ CalendarServer/branches/users/cdaboo/dropbox/lib-patches/Twisted/twisted.web2.server.patch 2006-11-01 18:45:19 UTC (rev 346)
@@ -11,96 +11,139 @@
"""This is a web-sever which integrates with the twisted.internet
-@@ -150,6 +152,9 @@
+@@ -150,17 +152,32 @@
self._initialprepath = kw['prepathuri']
del kw['prepathuri']
+ self._resourcesByURL = {}
-+ self._resourcesFromURL = {}
++ self._urlsByResource = {}
+
# Copy response filters from the class
self.responseFilters = self.responseFilters[:]
self.files = {}
-@@ -156,7 +161,9 @@
self.resources = []
http.Request.__init__(self, *args, **kw)
- def addResponseFilter(self, f, atEnd=False):
-+ def addResponseFilter(self, f, atEnd=False, onlyOnce = False):
-+ if onlyOnce and f in self.responseFilters:
++ def addResponseFilter(self, filter, atEnd=False, onlyOnce=False):
++ """
++ Add a response filter to this request.
++ Response filters are applied to the response to this request in order.
++ @param filter: a callable which takes an response argument and returns
++ a response object.
++ @param atEnd: if C{True}, C{filter} is added at the end of the list of
++ response filters; if C{False}, it is added to the beginning.
++ @param onlyOnce: if C{True}, C{filter} is not added to the list of
++ response filters if it already in the list.
++ """
++ if onlyOnce and filter in self.responseFilters:
+ return
if atEnd:
- self.responseFilters.append(f)
+- self.responseFilters.append(f)
++ self.responseFilters.append(filter)
else:
-@@ -263,8 +270,15 @@
- failedDeferred = self._processingFailed(failure.Failure())
- return
+- self.responseFilters.insert(0, f)
++ self.responseFilters.insert(0, filter)
+
+ def unparseURL(self, scheme=None, host=None, port=None,
+ path=None, params=None, querystring=None, fragment=None):
+@@ -265,6 +282,7 @@
-+ def _registerResource(child):
-+ url = "/" + "/".join(self.prepath)
-+ self._resourcesByURL[child] = url
-+ self._resourcesFromURL[url] = child
-+ return child
-+
d = defer.Deferred()
d.addCallback(self._getChild, self.site.resource, self.postpath)
-+ d.addCallback(_registerResource)
++ d.addCallback(self._rememberResource, "/" + "/".join(self.prepath))
d.addCallback(lambda res, req: res.renderHTTP(req), self)
d.addCallback(self._cbFinishRender)
d.addErrback(self._processingFailed)
-@@ -321,7 +335,7 @@
+@@ -320,8 +338,6 @@
+ url = "/" + "/".join(path)
else:
url = "/"
-
+-
- self._rememberURLForResource(quote(url), res)
-+ #self._rememberURLForResource(quote(url), res)
return res
#else:
# raise ValueError("locateChild must not return StopTraversal with a resource other than self.")
-@@ -342,12 +356,10 @@
+@@ -342,17 +358,16 @@
self.prepath.append(self.postpath.pop(0))
child = self._getChild(None, newres, newpath, updatepaths=updatepaths)
- self._rememberURLForResource(quote(url), child)
-+ #self._rememberURLForResource(quote(url), child)
return child
- _resourcesByURL = weakref.WeakKeyDictionary()
-
- def _rememberURLForResource(self, url, resource):
+- def _rememberURLForResource(self, url, resource):
++ def _rememberResource(self, resource, url):
"""
- Remember the URL of visited resources.
-@@ -387,6 +399,11 @@
+- Remember the URL of visited resources.
++ Remember the URL of a visited resources.
"""
- if url is None: return None
+ self._resourcesByURL[resource] = url
++ self._urlsByResource[url] = resource
++ return resource
-+ try:
-+ return succeed(self._resourcesFromURL[url])
-+ except KeyError:
-+ pass
+ def urlForResource(self, resource):
+ """
+@@ -367,10 +382,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,8 +397,13 @@
+ The contained response will have a status code of
+ L{responsecode.BAD_REQUEST}.
+ """
+- if url is None: return None
++ if url is None:
++ return None
+
++ cached = self._urlsByResource.get(url, None)
++ if cached is not None:
++ return succeed(cached)
+
#
# Parse the URL
#
-@@ -417,7 +434,52 @@
- raise f
+@@ -406,19 +423,62 @@
+ "URL is not on this site (%s://%s/): %s" % (scheme, self.headers.getHeader("host"), url)
+ ))
+
+- segments = path.split("/")
++ segments = unquote(path).split("/")
+ assert segments[0] == "", "URL path didn't begin with '/': %s" % (path,)
+ segments = segments[1:]
+- segments = map(unquote, segments)
+
+ def notFound(f):
+ f.trap(http.HTTPError)
+ if f.response.code != responsecode.NOT_FOUND:
+- raise f
++ return f
return None
- return defer.maybeDeferred(self._getChild, None, self.site.resource, segments, updatepaths=False)
-+ def _registerResource(child):
-+ self._resourcesByURL[child] = path
-+ self._resourcesFromURL[path] = child
-+ return child
-+
+ d = defer.maybeDeferred(self._getChild, None, self.site.resource, segments, updatepaths=False)
-+ d.addCallback(_registerResource)
++ d.addCallback(self._rememberResource, path)
++ d.addErrback(notFound)
+ return d
-+
-+ def locateChildResource(self, res, childpath):
+
++ def locateChildResource(self, parent, child_name):
+ """
-+ Looks up the child resource with the given name given the parent resource.
-+ @param uri: The URL last path segment of the desired resource.
++ 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
@@ -110,30 +153,30 @@
+ The contained response will have a status code of
+ L{responsecode.BAD_REQUEST}.
+ """
-+ if res is None or childpath is None: return None
-+
-+ url = joinURL(self.urlForResource(res), childpath)
-+ try:
-+ return succeed(self._resourcesFromURL[url])
-+ except KeyError:
-+ pass
++ if parent is None or child_name is None:
++ return None
+
-+ segment = unquote(childpath)
++ url = joinURL(self.urlForResource(parent), child_name)
+
++ cached = self._urlsByResource.get(url, None)
++ if cached is not None:
++ return 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.response.code != responsecode.NOT_FOUND:
-+ raise f
++ return f
+ return None
+
-+ def _registerResource(child):
-+ self._resourcesByURL[child] = url
-+ self._resourcesFromURL[url] = child
-+ return child
-+
-+ d = defer.maybeDeferred(self._getChild, None, res, [segment], updatepaths=False)
-+ d.addCallback(_registerResource)
++ 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
Modified: CalendarServer/branches/users/cdaboo/dropbox/support/submit
===================================================================
--- CalendarServer/branches/users/cdaboo/dropbox/support/submit 2006-11-01 00:07:35 UTC (rev 345)
+++ CalendarServer/branches/users/cdaboo/dropbox/support/submit 2006-11-01 18:45:19 UTC (rev 346)
@@ -36,11 +36,11 @@
usage ()
{
- program="$(basename "$0") release";
+ program="$(basename "$0")";
if [ "${1-}" != "-" ]; then echo "$1"; echo; fi;
- echo "Usage: ${program} release version";
+ echo "Usage: ${program} release";
if [ "${1-}" == "-" ]; then return 0; fi;
exit 64;
Modified: CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/authkerb.py
===================================================================
--- CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/authkerb.py 2006-11-01 00:07:35 UTC (rev 345)
+++ CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/authkerb.py 2006-11-01 18:45:19 UTC (rev 346)
@@ -113,11 +113,11 @@
kerberos.checkPassword(creds.username, creds.password, creds.service, creds.default_realm)
except kerberos.BasicAuthError, ex:
logging.err("%s" % (ex[0],), system="BasicKerberosCredentialsChecker")
- raise error.UnauthorizedLogin("Bad credentials for: %s (%s)" % (pcreds.principalURI, ex[0],))
+ raise error.UnauthorizedLogin("Bad credentials for: %s (%s)" % (pcreds.authnURI, ex[0],))
else:
- return succeed(pcreds.principalURI)
+ return succeed((pcreds.authnURI, pcreds.authzURI,))
- raise error.UnauthorizedLogin("Bad credentials for: %s" % (pcreds.principalURI,))
+ raise error.UnauthorizedLogin("Bad credentials for: %s" % (pcreds.authnURI,))
class NegotiateCredentials:
"""
@@ -207,14 +207,14 @@
def requestAvatarId(self, credentials):
# NB If we get here authentication has already succeeded as it is done in NegotiateCredentialsFactory.decode
- # So all we need to do is return the principal URI from the credentials.
+ # So all we need to do is return the principal URIs from the credentials.
- # If there is no calendar principal URI then the calendar user is disabled.
+ # Look for proper credential type.
pcreds = IPrincipalCredentials(credentials)
creds = pcreds.credentials
if isinstance(creds, NegotiateCredentials):
- return succeed(pcreds.principalURI)
+ return succeed((pcreds.authnURI, pcreds.authzURI,))
- raise error.UnauthorizedLogin("Bad credentials for: %s" % (pcreds.principalURI,))
+ raise error.UnauthorizedLogin("Bad credentials for: %s" % (pcreds.authnURI,))
Modified: CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/caldavxml.py
===================================================================
--- CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/caldavxml.py 2006-11-01 00:07:35 UTC (rev 345)
+++ CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/caldavxml.py 2006-11-01 18:45:19 UTC (rev 346)
@@ -1134,13 +1134,28 @@
test = str(self)
if self.caseless:
test = test.lower()
- for value in values:
+
+ def _textCompare(s):
if self.caseless:
- if value.lower().find(test) != -1:
- return not self.negate
+ if s.lower().find(test) != -1:
+ return True, not self.negate
else:
- if value.find(test) != -1:
- return not self.negate
+ if s.find(test) != -1:
+ return True, not self.negate
+ return False, False
+
+ for value in values:
+ # NB Its possible that we have a text list value which appears as a Pythin list,
+ # so we need to check for that an iterate over thr list.
+ if isinstance(value, list):
+ for subvalue in value:
+ matched, result = _textCompare(subvalue)
+ if matched:
+ return result
+ else:
+ matched, result = _textCompare(value)
+ if matched:
+ return result
return self.negate
Modified: CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/customxml.py
===================================================================
--- CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/customxml.py 2006-11-01 00:07:35 UTC (rev 345)
+++ CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/customxml.py 2006-11-01 18:45:19 UTC (rev 346)
@@ -103,7 +103,7 @@
namespace = twisted_dav_namespace
name = "notifications"
-class DropBoxHomeURL (davxml.WebDAVTextElement):
+class DropBoxHomeURL (davxml.WebDAVElement):
"""
A principal property to indicate the location of the drop box home.
(Apple Extension to CalDAV)
@@ -115,7 +115,7 @@
allowed_children = { (davxml.dav_namespace, "href"): (0, 1) }
-class NotificationsURL (davxml.WebDAVTextElement):
+class NotificationsURL (davxml.WebDAVElement):
"""
A principal property to indicate the location of the notification collection.
(Apple Extension to CalDAV)
@@ -127,6 +127,163 @@
allowed_children = { (davxml.dav_namespace, "href"): (0, 1) }
+class Notification(davxml.WebDAVElement):
+ """
+ Root element for XML data in a notification resource.
+ """
+ namespace = twisted_dav_namespace
+ name = "notification"
+
+ allowed_children = {
+ (twisted_dav_namespace, "action" ): (1, 1),
+ (twisted_dav_namespace, "time-stamp" ): (1, 1),
+ (twisted_dav_namespace, "auth-id" ): (1, 1),
+ (twisted_dav_namespace, "old-etag" ): (1, 1),
+ (twisted_dav_namespace, "new-etag" ): (1, 1),
+ (twisted_dav_namespace, "old-uri" ): (1, 1),
+ (twisted_dav_namespace, "new_uri" ): (1, 1),
+ }
+
+class Action (davxml.WebDAVElement):
+ """
+ A property to indicate the action of a notification resource.
+ (Apple Extension to CalDAV)
+ """
+ namespace = twisted_dav_namespace
+ name = "action"
+ hidden = True
+ protected = True
+
+ allowed_children = {
+ (twisted_dav_namespace, "created" ): (0, 1),
+ (twisted_dav_namespace, "modified" ): (0, 1),
+ (twisted_dav_namespace, "deleted" ): (0, 1),
+ (twisted_dav_namespace, "copiedto" ): (0, 1),
+ (twisted_dav_namespace, "copiedfrom" ): (0, 1),
+ (twisted_dav_namespace, "movedout" ): (0, 1),
+ (twisted_dav_namespace, "movedin" ): (0, 1),
+ }
+
+class Created (davxml.WebDAVEmptyElement):
+ """
+ A property value to indicate the created action of a notification resource.
+ (Apple Extension to CalDAV)
+ """
+ namespace = twisted_dav_namespace
+ name = "created"
+
+class Modified (davxml.WebDAVEmptyElement):
+ """
+ A property value to indicate the modified action of a notification resource.
+ (Apple Extension to CalDAV)
+ """
+ namespace = twisted_dav_namespace
+ name = "modified"
+
+class Deleted (davxml.WebDAVEmptyElement):
+ """
+ A property value to indicate the deleted action of a notification resource.
+ (Apple Extension to CalDAV)
+ """
+ namespace = twisted_dav_namespace
+ name = "deleted"
+
+class CopiedTo (davxml.WebDAVEmptyElement):
+ """
+ A property value to indicate the copied to action of a notification resource.
+ (Apple Extension to CalDAV)
+ """
+ namespace = twisted_dav_namespace
+ name = "copiedto"
+
+class CopiedFrom (davxml.WebDAVEmptyElement):
+ """
+ A property value to indicate the copied from action of a notification resource.
+ (Apple Extension to CalDAV)
+ """
+ namespace = twisted_dav_namespace
+ name = "copiedfrom"
+
+class MovedTo (davxml.WebDAVEmptyElement):
+ """
+ A property value to indicate the moved to action of a notification resource.
+ (Apple Extension to CalDAV)
+ """
+ namespace = twisted_dav_namespace
+ name = "movedto"
+
+class MovedFrom (davxml.WebDAVEmptyElement):
+ """
+ A property value to indicate the moved from action of a notification resource.
+ (Apple Extension to CalDAV)
+ """
+ namespace = twisted_dav_namespace
+ name = "movedfrom"
+
+class TimeStamp (davxml.WebDAVTextElement):
+ """
+ A property to indicate the timestamp of a notification resource.
+ (Apple Extension to CalDAV)
+ """
+ namespace = twisted_dav_namespace
+ name = "time-stamp"
+ hidden = True
+ protected = True
+
+class AuthID (davxml.WebDAVTextElement):
+ """
+ A property to indicate the authorization identitifer of a notification resource.
+ (Apple Extension to CalDAV)
+ """
+ namespace = twisted_dav_namespace
+ name = "auth-id"
+ hidden = True
+ protected = True
+
+class OldETag (davxml.WebDAVTextElement):
+ """
+ A property to indicate the old ETag of a notification resource.
+ (Apple Extension to CalDAV)
+ """
+ namespace = twisted_dav_namespace
+ name = "old-etag"
+ hidden = True
+ protected = True
+
+class NewETag (davxml.WebDAVTextElement):
+ """
+ A property to indicate the new ETag of a notification resource.
+ (Apple Extension to CalDAV)
+ """
+ namespace = twisted_dav_namespace
+ name = "new-etag"
+ hidden = True
+ protected = True
+
+class OldURI (davxml.WebDAVElement):
+ """
+ A property to indicate the old URI of a notification resource.
+ (Apple Extension to CalDAV)
+ """
+ namespace = twisted_dav_namespace
+ name = "old-uri"
+ hidden = True
+ protected = True
+
+ allowed_children = { (davxml.dav_namespace, "href"): (0, 1) }
+
+class NewURI (davxml.WebDAVElement):
+ """
+ A property to indicate the new URI of a notification resource.
+ (Apple Extension to CalDAV)
+ """
+ namespace = twisted_dav_namespace
+ name = "new-uri"
+ hidden = True
+ protected = True
+
+ allowed_children = { (davxml.dav_namespace, "href"): (0, 1) }
+
##
# Extensions to davxml.ResourceType
##
Modified: CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/directory.py
===================================================================
--- CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/directory.py 2006-11-01 00:07:35 UTC (rev 345)
+++ CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/directory.py 2006-11-01 18:45:19 UTC (rev 346)
@@ -39,6 +39,7 @@
from twisted.web2 import responsecode
from twisted.web2.dav import davxml
from twisted.web2.dav.auth import IPrincipalCredentials
+from twisted.web2.dav.auth import TwistedPropertyChecker
from twisted.web2.dav.static import DAVFile
from twisted.web2.dav.util import joinURL
from twisted.web2.http import HTTPError
@@ -57,26 +58,24 @@
import os
import unicodedata
-class DirectoryCredentialsChecker:
- implements(checkers.ICredentialsChecker)
+class DirectoryCredentialsChecker (TwistedPropertyChecker):
- credentialInterfaces = (IPrincipalCredentials,)
-
def requestAvatarId(self, credentials):
# If there is no calendar principal URI then the calendar user is disabled.
pcreds = IPrincipalCredentials(credentials)
- if not pcreds.principal.hasDeadProperty(customxml.TwistedCalendarPrincipalURI):
- raise error.UnauthorizedLogin("Bad credentials for: %s" % (pcreds.principalURI,))
+ if not pcreds.authnPrincipal.hasDeadProperty(customxml.TwistedCalendarPrincipalURI):
+ # Try regular password check
+ return TwistedPropertyChecker.requestAvatarId(self, credentials)
creds = pcreds.credentials
if isinstance(creds, UsernamePassword):
user = creds.username
pswd = creds.password
- if opendirectory.authenticateUser(pcreds.principal.directory(), user, pswd):
- return succeed(pcreds.principalURI)
+ if opendirectory.authenticateUser(pcreds.authnPrincipal.directory(), user, pswd):
+ return succeed((pcreds.authnURI, pcreds.authzURI,))
- raise error.UnauthorizedLogin("Bad credentials for: %s" % (pcreds.principalURI,))
+ raise error.UnauthorizedLogin("Bad credentials for: %s" % (pcreds.authnURI,))
class DirectoryPrincipalFile (CalendarPrincipalFile):
"""
Modified: CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/logging.py
===================================================================
--- CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/logging.py 2006-11-01 00:07:35 UTC (rev 345)
+++ CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/logging.py 2006-11-01 18:45:19 UTC (rev 346)
@@ -25,6 +25,8 @@
import time
from twisted.python import log
+from twisted.web2 import iweb
+from twisted.web2.dav import davxml
from twisted.web2.log import BaseCommonAccessLoggingObserver
#
@@ -117,6 +119,41 @@
self.rotate()
self.f.write(message + '\n')
+ def emit(self, eventDict):
+ if eventDict.get('interface') is not iweb.IRequest:
+ return
+
+ request = eventDict['request']
+ response = eventDict['response']
+ loginfo = eventDict['loginfo']
+ firstLine = '%s %s HTTP/%s' %(
+ request.method,
+ request.uri,
+ '.'.join([str(x) for x in request.clientproto]))
+
+ # Try to determine authentication and authorization identifiers
+ uid = "-"
+ if hasattr(request, "authnUser"):
+ if isinstance(request.authnUser.children[0], davxml.HRef):
+ uid = str(request.authnUser.children[0])
+ if hasattr(request, "authzUser") and str(request.authzUser.children[0]) != uid:
+ uid += " as %s" % (str(request.authzUser.children[0]),)
+
+
+ self.logMessage(
+ '%s - %s [%s] "%s" %s %d "%s" "%s"' %(
+ request.remoteAddr.host,
+ uid,
+ self.logDateString(
+ response.headers.getHeader('date', 0)),
+ firstLine,
+ response.code,
+ loginfo.bytesSent,
+ request.headers.getHeader('referer', '-'),
+ request.headers.getHeader('user-agent', '-')
+ )
+ )
+
def start(self):
"""
Start logging. Open the log file and log an 'open' message.
Modified: CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/method/__init__.py
===================================================================
--- CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/method/__init__.py 2006-11-01 00:07:35 UTC (rev 345)
+++ CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/method/__init__.py 2006-11-01 18:45:19 UTC (rev 346)
@@ -35,6 +35,5 @@
"report_calquery",
"report_multiget",
"report_freebusy",
- "schedule",
"schedule_common",
]
Deleted: CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/method/schedule.py
===================================================================
--- CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/method/schedule.py 2006-11-01 00:07:35 UTC (rev 345)
+++ CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/method/schedule.py 2006-11-01 18:45:19 UTC (rev 346)
@@ -1,58 +0,0 @@
-##
-# Copyright (c) 2006 Apple Computer, 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.
-#
-# DRI: Cyrus Daboo, cdaboo at apple.com
-##
-
-"""
-CalDAV SCHEDULE method.
-"""
-
-__all__ = ["http_SCHEDULE"]
-
-from twisted.internet.defer import deferredGenerator, waitForDeferred
-from twisted.web2.dav.util import parentForURL
-
-from twistedcaldav import caldavxml
-from twistedcaldav.method.schedule_common import processScheduleRequest
-
-def http_SCHEDULE(self, request):
-
- """
- The CalDAV SCHEDULE method.
-
- This uses a generator function yielding either L{waitForDeferred} objects or L{Response} objects.
- This allows for code that follows a 'linear' execution pattern rather than having to use nested
- L{Deferred} callbacks. The logic is easier to follow this way plus we don't run into deep nesting
- issues which the other approach would have with large numbers of recipients.
- """
-
- #
- # Check authentication and access controls
- #
- parent = waitForDeferred(request.locateResource(parentForURL(request.uri)))
- yield parent
- parent = parent.getResult()
-
- d = waitForDeferred(parent.authorize(request, (caldavxml.Schedule(),)))
- yield d
- d.getResult()
-
- # Initiate deferred generator
- d = waitForDeferred(processScheduleRequest(self, "SCHEDULE", request))
- yield d
- yield d.getResult()
-
-http_SCHEDULE = deferredGenerator(http_SCHEDULE)
Modified: CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/repository.py
===================================================================
--- CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/repository.py 2006-11-01 00:07:35 UTC (rev 345)
+++ CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/repository.py 2006-11-01 18:45:19 UTC (rev 346)
@@ -119,6 +119,7 @@
ELEMENT_CALENDAR = "calendar"
ELEMENT_QUOTA = "quota"
ELEMENT_AUTORESPOND = "autorespond"
+ELEMENT_CANPROXY = "canproxy"
ATTRIBUTE_REPEAT = "repeat"
def startServer(docroot, repo, doacct, doacl, dossl,
@@ -813,6 +814,8 @@
self.acl.parseXML(child)
elif child._get_localName() == ELEMENT_AUTORESPOND:
self.autorespond = True
+ elif child._get_localName() == ELEMENT_CANPROXY:
+ CalDAVResource.proxyUsers.add(self.uid)
class Authentication:
"""
Modified: CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/resource.py
===================================================================
--- CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/resource.py 2006-11-01 00:07:35 UTC (rev 345)
+++ CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/resource.py 2006-11-01 18:45:19 UTC (rev 346)
@@ -38,6 +38,7 @@
from twisted.internet import reactor
from twisted.internet.defer import Deferred, maybeDeferred, succeed
from twisted.internet.defer import deferredGenerator, waitForDeferred
+from twisted.python import log
from twisted.web2 import responsecode
from twisted.web2.dav import davxml
from twisted.web2.dav.resource import AccessDeniedError, DAVPrincipalResource
@@ -76,6 +77,10 @@
# resources to that size, or C{None} for no limit.
sizeLimit = None
+ # Set containing user ids of all the users who have been given
+ # the right to authorize as someone else.
+ proxyUsers = set()
+
##
# HTTP
##
@@ -226,6 +231,61 @@
return super(CalDAVResource, self).accessControlList(*args, **kwargs)
+ def authorizationPrincipal(self, request, authid, authnPrincipal, authnURI):
+ """
+ Determine the authorization principal for the given request and authentication principal.
+ This implementation looks for an X-Authorize-As header value to use as the authoization principal.
+
+ @param request: the L{IRequest} for the request in progress.
+ @param authid: a string containing the uthentication/authorization identifier
+ for the principal to lookup.
+ @param authnPrincipal: the L{IDAVPrincipal} for the authenticated principal
+ @param authnURI: a C{str} containing the URI of the authenticated principal
+ @return: a deferred result C{tuple} of (L{IDAVPrincipal}, C{str}) containing the authorization principal
+ resource and URI respectively.
+ """
+
+ # Look for X-Authorize-As Header
+ authz = request.headers.getRawHeaders("x-authorize-as")
+ if authz is not None and (len(authz) == 1):
+ # Substitute the authz value for principal look up
+ authz = authz[0]
+
+ # See if authenticated uid is a proxy user
+ if authid in CalDAVResource.proxyUsers:
+ if authz:
+ if authz in CalDAVResource.proxyUsers:
+ log.msg("Cannot proxy as another proxy: user '%s' as user '%s'" % (authid, authz))
+ raise HTTPError(responsecode.UNAUTHORIZED)
+ else:
+ d = waitForDeferred(self.findPrincipalForAuthID(request, authz))
+ yield d
+ result = d.getResult()
+
+ if result is not None:
+ log.msg("Allow proxy: user '%s' as '%s'" % (authid, authz,))
+ authzPrincipal = result[0]
+ authzURI = result[1]
+ yield authzPrincipal, authzURI
+ return
+ else:
+ log.msg("Could not find proxy user id: '%s'" % authid)
+ raise HTTPError(responsecode.UNAUTHORIZED)
+ else:
+ log.msg("Cannot authenticate proxy user '%s' without X-Authorize-As header" % (authid, ))
+ raise HTTPError(responsecode.UNAUTHORIZED)
+ elif authz:
+ log.msg("Cannot proxy: user '%s' as '%s'" % (authid, authz,))
+ raise HTTPError(responsecode.UNAUTHORIZED)
+ else:
+ # No proxy - do default behavior
+ d = waitForDeferred(super(CalDAVResource, self).authorizationPrincipal(request, authid, authnPrincipal, authnURI))
+ yield d
+ yield d.getResult()
+ return
+
+ authorizationPrincipal = deferredGenerator(authorizationPrincipal)
+
##
# CalDAV
##
Modified: CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/static.py
===================================================================
--- CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/static.py 2006-11-01 00:07:35 UTC (rev 345)
+++ CalendarServer/branches/users/cdaboo/dropbox/twistedcaldav/static.py 2006-11-01 18:45:19 UTC (rev 346)
@@ -27,11 +27,12 @@
"CalendarHomeFile",
"CalendarHomeProvisioningFile",
"CalendarPrincipalFile",
- "CalendarUserPrincipalProvisioningResource",
+ "CalendarPrincipalCollectionFile",
]
import os
import errno
+from posixpath import basename
from urlparse import urlsplit
from twisted.internet.defer import deferredGenerator, fail, succeed, waitForDeferred
@@ -869,7 +870,7 @@
DropBox.provision(self, (homeURL, home))
-class CalendarUserPrincipalProvisioningResource (CalendarPrincipalCollectionResource, DAVFile):
+class CalendarPrincipalCollectionFile (CalendarPrincipalCollectionResource, DAVFile):
"""
L{DAVFile} resource which provisions user L{CalendarPrincipalFile} resources
as needed.
@@ -893,34 +894,13 @@
"""
pass
- def render(self, request):
- return StatusResponse(
- responsecode.OK,
- "This collection contains user principal resources",
- title=self.displayName()
- )
-
- def getChild(self, name):
- if name == "": return self
-
- child_fp = self.fp.child(name)
- if child_fp.exists():
- assert child_fp.isfile()
+ def createSimilarFile(self, path):
+ if path == self.fp.path:
+ return self
else:
- assert self.exists()
- assert self.isCollection()
+ # TODO: Fix this - not sure how to get URI for second argument of __init__
+ return CalendarPrincipalFile(path, joinURL(self.principalCollectionURL(), basename(path)))
- # FIXME: Do a real lookup of what's valid here
- if name[0] == ".": return None
- if len(name) > 8: return None
-
- child_fp.open("w").close()
-
- return CalendarPrincipalFile(child_fp.path, joinURL(self.principalCollectionURL(), name))
-
- def createSimilarFile(self, path):
- raise NotImplementedError("Not allowed.")
-
def principalSearchPropertySet(self):
"""
See L{IDAVResource.principalSearchPropertySet}.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20061101/3ddb804a/attachment.html
More information about the calendarserver-changes
mailing list