[CalendarServer-changes] [13548] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Wed May 28 11:29:34 PDT 2014


Revision: 13548
          http://trac.calendarserver.org//changeset/13548
Author:   cdaboo at apple.com
Date:     2014-05-28 11:29:34 -0700 (Wed, 28 May 2014)
Log Message:
-----------
Make sure access log displays user names rather than principal URLs.

Modified Paths:
--------------
    CalendarServer/trunk/calendarserver/accesslog.py
    CalendarServer/trunk/calendarserver/provision/root.py
    CalendarServer/trunk/calendarserver/provision/test/test_root.py
    CalendarServer/trunk/calendarserver/push/applepush.py
    CalendarServer/trunk/calendarserver/tap/util.py
    CalendarServer/trunk/calendarserver/webcal/resource.py
    CalendarServer/trunk/twistedcaldav/authkerb.py
    CalendarServer/trunk/twistedcaldav/cache.py
    CalendarServer/trunk/twistedcaldav/directory/util.py
    CalendarServer/trunk/twistedcaldav/test/test_addressbookmultiget.py
    CalendarServer/trunk/twistedcaldav/test/test_addressbookquery.py
    CalendarServer/trunk/twistedcaldav/test/test_cache.py
    CalendarServer/trunk/twistedcaldav/test/test_calendarquery.py
    CalendarServer/trunk/twistedcaldav/test/test_collectioncontents.py
    CalendarServer/trunk/twistedcaldav/test/test_mkcalendar.py
    CalendarServer/trunk/twistedcaldav/test/test_multiget.py
    CalendarServer/trunk/twistedcaldav/test/test_props.py
    CalendarServer/trunk/twistedcaldav/test/test_resource.py
    CalendarServer/trunk/twistedcaldav/test/test_sharing.py
    CalendarServer/trunk/twistedcaldav/test/test_wrapping.py
    CalendarServer/trunk/twistedcaldav/test/util.py
    CalendarServer/trunk/twistedcaldav/upgrade.py
    CalendarServer/trunk/txdav/who/wiki.py
    CalendarServer/trunk/txweb2/dav/auth.py
    CalendarServer/trunk/txweb2/dav/idav.py
    CalendarServer/trunk/txweb2/dav/resource.py
    CalendarServer/trunk/txweb2/dav/test/test_resource.py

Modified: CalendarServer/trunk/calendarserver/accesslog.py
===================================================================
--- CalendarServer/trunk/calendarserver/accesslog.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/calendarserver/accesslog.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -40,6 +40,7 @@
     getAdjustedClientName
 
 from twext.python.log import Logger
+from twext.who.idirectory import RecordType
 from txweb2 import iweb
 from txweb2.log import BaseCommonAccessLoggingObserver
 from txweb2.log import LogWrapperResource
@@ -49,8 +50,6 @@
 
 from twistedcaldav.config import config
 
-from txdav.xml import element as davxml
-
 log = Logger()
 
 class DirectoryLogWrapperResource(LogWrapperResource):
@@ -83,39 +82,21 @@
 
             # Try to determine authentication and authorization identifiers
             uid = "-"
-            if hasattr(request, "authnUser"):
-                if isinstance(request.authnUser.children[0], davxml.HRef):
-                    uidn = str(request.authnUser.children[0])
-                    uidz = None
-                    if hasattr(request, "authzUser") and str(request.authzUser.children[0]) != uidn:
-                        uidz = str(request.authzUser.children[0])
+            if getattr(request, "authnUser", None) is not None:
+                def convertPrincipaltoShortName(principal):
+                    if principal.record.recordType == RecordType.user:
+                        return principal.record.shortNames[0]
+                    else:
+                        return "({rtype}){name}".format(rtype=principal.record.recordType, name=principal.record.shortNames[0],)
 
-                    # def convertUIDtoShortName(uid):
-                    #     uid = uid.rstrip("/")
-                    #     uid = uid[uid.rfind("/") + 1:]
-                    #     record = request.site.resource.getDirectory().recordWithUID(uid)
-                    #     if record:
-                    #         if record.recordType == DirectoryService.recordType_users:
-                    #             return record.shortNames[0]
-                    #         else:
-                    #             return "(%s)%s" % (record.recordType, record.shortNames[0],)
-                    #     else:
-                    #         return uid
+                uidn = convertPrincipaltoShortName(request.authnUser)
+                uidz = convertPrincipaltoShortName(request.authzUser)
 
-                    # MOVE2WHO
-                    # Better to stick the records directly on the request at
-                    # an earlier point, since we can't do anything deferred
-                    # in here.
+                if uidn != uidz:
+                    uid = '"{authn} as {authz}"'.format(authn=uidn, authz=uidz,)
+                else:
+                    uid = uidn
 
-                    # uidn = convertUIDtoShortName(uidn)
-                    # if uidz:
-                    #     uidz = convertUIDtoShortName(uidz)
-
-                    if uidn and uidz:
-                        uid = '"%s as %s"' % (uidn, uidz,)
-                    else:
-                        uid = uidn
-
             #
             # For some methods which basically allow you to tunnel a
             # custom request (eg. REPORT, POST), the method name

Modified: CalendarServer/trunk/calendarserver/provision/root.py
===================================================================
--- CalendarServer/trunk/calendarserver/provision/root.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/calendarserver/provision/root.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -35,7 +35,6 @@
 from twistedcaldav.resource import CalDAVComplianceMixIn
 from txdav.who.wiki import DirectoryService as WikiDirectoryService
 from txdav.who.wiki import uidForAuthToken
-from txdav.xml import element as davxml
 from txweb2 import responsecode
 from txweb2.auth.wrapper import UnauthorizedResponse
 from txweb2.dav.xattrprops import xattrPropertyStore
@@ -146,7 +145,7 @@
         # be a SACL group assigned to this service.  Let's see if
         # unauthenticated users are allowed by calling CheckSACL
         # with an empty string.
-        if authzUser == davxml.Principal(davxml.Unauthenticated()):
+        if authzUser is None:
             for saclService in saclServices:
                 if RootResource.CheckSACL("", saclService) == 0:
                     # No group actually exists for this SACL, so allow
@@ -166,22 +165,8 @@
         request.authzUser = authzUser
 
         # Figure out the "username" from the davxml.Principal object
-        request.checkingSACL = True
+        username = authzUser.record.shortNames[0]
 
-        for collection in self.principalCollections():
-            principal = yield collection._principalForURI(
-                authzUser.children[0].children[0].data
-            )
-            if principal is None:
-                response = (yield UnauthorizedResponse.makeResponse(
-                    request.credentialFactories,
-                    request.remoteAddr
-                ))
-                raise HTTPError(response)
-
-        delattr(request, "checkingSACL")
-        username = principal.record.shortNames[0]
-
         access = False
         for saclService in saclServices:
             if RootResource.CheckSACL(username, saclService) == 0:
@@ -278,21 +263,7 @@
                         log.debug(
                             "Wiki lookup returned uid: {uid}", uid=uid
                         )
-                        principal = None
-                        directory = request.site.resource.getDirectory()
-                        record = yield directory.recordWithUID(uid)
-                        if record is not None:
-                            username = record.shortNames[0]
-                            log.debug(
-                                "Wiki user record for user {user}: {record}",
-                                user=username, record=record
-                            )
-                            for collection in self.principalCollections():
-                                principal = (
-                                    yield collection.principalForRecord(record)
-                                )
-                                if principal is not None:
-                                    break
+                        principal = yield self.principalForUID(request, uid)
 
                         if principal:
                             log.debug(
@@ -300,14 +271,7 @@
                                 "being assigned to authnUser and authzUser",
                                 record=record
                             )
-                            request.authzUser = request.authnUser = (
-                                davxml.Principal(
-                                    davxml.HRef.fromString(
-                                        "/principals/__uids__/{}/"
-                                        .format(record.uid)
-                                    )
-                                )
-                            )
+                            request.authzUser = request.authnUser = principal
 
         if not hasattr(request, "authzUser") and config.WebCalendarAuthPath:
             topLevel = request.path.strip("/").split("/")[0]
@@ -366,26 +330,21 @@
             # The authzuser value is set to that of the wiki principal if
             # not already set.
             if not hasattr(request, "authzUser"):
-                wikiName = None
+                wikiUid = None
                 if segments[1] == "wikis":
-                    wikiName = segments[2]
+                    wikiUid = "{}{}".format(WikiDirectoryService.uidPrefix, segments[2])
                 else:
-                    wikiName = segments[2][5:]
-                if wikiName:
+                    wikiUid = segments[2]
+                if wikiUid:
                     log.debug(
                         "Wiki principal {name} being assigned to authzUser",
-                        name=wikiName
+                        name=wikiUid
                     )
-                    request.authzUser = davxml.Principal(
-                        davxml.HRef.fromString(
-                            "/principals/wikis/{}/".format(wikiName)
-                        )
-                    )
+                    request.authzUser = yield self.principalForUID(request, wikiUid)
 
         elif (
             self.useSacls and
-            not hasattr(request, "checkedSACL") and
-            not hasattr(request, "checkingSACL")
+            not hasattr(request, "checkedSACL")
         ):
             yield self.checkSacl(request)
 
@@ -442,6 +401,25 @@
         returnValue(child)
 
 
+    @inlineCallbacks
+    def principalForUID(self, request, uid):
+        principal = None
+        directory = request.site.resource.getDirectory()
+        record = yield directory.recordWithUID(uid)
+        if record is not None:
+            username = record.shortNames[0]
+            log.debug(
+                "Wiki user record for user {user}: {record}",
+                user=username, record=record
+            )
+            for collection in self.principalCollections():
+                principal = yield collection.principalForRecord(record)
+                if principal is not None:
+                    break
+
+        returnValue(principal)
+
+
     def http_COPY(self, request):
         return responsecode.FORBIDDEN
 

Modified: CalendarServer/trunk/calendarserver/provision/test/test_root.py
===================================================================
--- CalendarServer/trunk/calendarserver/provision/test/test_root.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/calendarserver/provision/test/test_root.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -17,7 +17,6 @@
 
 from twisted.internet.defer import inlineCallbacks, maybeDeferred, returnValue
 
-from twext.who.idirectory import RecordType
 from txweb2 import http_headers
 from txweb2 import responsecode
 from txdav.xml import element as davxml
@@ -126,15 +125,12 @@
         """
         self.actualRoot.useSacls = True
 
-        record = yield self.directory.recordWithShortName(
-            RecordType.user,
-            u"dreid"
-        )
+        principal = yield self.actualRoot.findPrincipalForAuthID("dreid")
         request = SimpleStoreRequest(
             self,
             "GET",
             "/principals/",
-            authRecord=record
+            authPrincipal=principal
         )
 
         resrc, segments = (yield maybeDeferred(
@@ -150,11 +146,10 @@
         self.assertEquals(segments, [])
 
         self.assertEquals(
-            request.authzUser,
+            request.authzUser.principalElement(),
             davxml.Principal(
                 davxml.HRef(
-                    "/principals/__uids__/"
-                    "5FF60DAD-0BDE-4508-8C77-15F0CA5C8DD1/"
+                    "/principals/__uids__/5FF60DAD-0BDE-4508-8C77-15F0CA5C8DD1/"
                 )
             )
         )
@@ -170,16 +165,13 @@
         """
         self.actualRoot.useSacls = True
 
-        record = yield self.directory.recordWithShortName(
-            RecordType.user,
-            u"wsanchez"
-        )
+        principal = yield self.actualRoot.findPrincipalForAuthID("wsanchez")
 
         request = SimpleStoreRequest(
             self,
             "GET",
             "/principals/",
-            authRecord=record
+            authPrincipal=principal
         )
 
         try:
@@ -338,10 +330,7 @@
 </D:prop>
 </D:propfind>
 """
-        record = yield self.directory.recordWithShortName(
-            RecordType.user,
-            u"dreid"
-        )
+        principal = yield self.actualRoot.findPrincipalForAuthID("dreid")
 
         request = SimpleStoreRequest(
             self,
@@ -350,7 +339,7 @@
             headers=http_headers.Headers({
                     'Depth': '1',
             }),
-            authRecord=record,
+            authPrincipal=principal,
             content=body
         )
         response = yield self.send(request)
@@ -366,7 +355,7 @@
             headers=http_headers.Headers({
                     'Depth': '1',
             }),
-            authRecord=record,
+            authPrincipal=principal,
             content=body
         )
         response = yield self.send(request)

Modified: CalendarServer/trunk/calendarserver/push/applepush.py
===================================================================
--- CalendarServer/trunk/calendarserver/push/applepush.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/calendarserver/push/applepush.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -872,20 +872,6 @@
     http_GET = http_POST
 
     @inlineCallbacks
-    def principalFromRequest(self, request):
-        """
-        Given an authenticated request, return the principal based on
-        request.authnUser
-        """
-        principal = None
-        for collection in self.principalCollections():
-            data = request.authnUser.children[0].children[0].data
-            principal = yield collection._principalForURI(data)
-            if principal is not None:
-                returnValue(principal)
-
-
-    @inlineCallbacks
     def processSubscription(self, request):
         """
         Given an authenticated request, use the token and key arguments
@@ -913,8 +899,7 @@
             msg = "Invalid request: bad 'token' %s" % (token,)
 
         else:
-            principal = yield self.principalFromRequest(request)
-            uid = principal.record.uid
+            uid = request.authnUser.record.uid
             try:
                 yield self.addSubscription(token, key, uid, userAgent, host)
                 code = responsecode.OK

Modified: CalendarServer/trunk/calendarserver/tap/util.py
===================================================================
--- CalendarServer/trunk/calendarserver/tap/util.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/calendarserver/tap/util.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -310,8 +310,6 @@
             # If we get here with Kerberos, then authentication has already succeeded
             returnValue(
                 (
-                    credentials.authnPrincipal.principalURL(),
-                    credentials.authzPrincipal.principalURL(),
                     credentials.authnPrincipal,
                     credentials.authzPrincipal,
                 )
@@ -320,8 +318,6 @@
             if (yield credentials.authnPrincipal.record.verifyCredentials(credentials.credentials)):
                 returnValue(
                     (
-                        credentials.authnPrincipal.principalURL(),
-                        credentials.authzPrincipal.principalURL(),
                         credentials.authnPrincipal,
                         credentials.authzPrincipal,
                     )

Modified: CalendarServer/trunk/calendarserver/webcal/resource.py
===================================================================
--- CalendarServer/trunk/calendarserver/webcal/resource.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/calendarserver/webcal/resource.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -154,9 +154,7 @@
         # Don't need to authenticate here because the ACL will have already
         # required it.
         #
-        authenticatedPrincipalURL = str(
-            request.authnUser.childOfType(davxml.HRef)
-        )
+        authenticatedPrincipalURL = request.authnUser.principalURL()
 
         def queryValue(arg):
             query = parse_qs(urlparse(request.uri).query, True)

Modified: CalendarServer/trunk/twistedcaldav/authkerb.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/authkerb.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/twistedcaldav/authkerb.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -191,8 +191,6 @@
                 raise error.UnauthorizedLogin("Bad credentials for: %s (%s: %s)" % (pcreds.authnURI, ex[0], ex[1],))
             else:
                 return succeed((
-                    pcreds.authnPrincipal.principalURL(),
-                    pcreds.authzPrincipal.principalURL(),
                     pcreds.authnPrincipal,
                     pcreds.authzPrincipal,
                 ))
@@ -332,8 +330,6 @@
         creds = pcreds.credentials
         if isinstance(creds, NegotiateCredentials):
             return succeed((
-                pcreds.authnPrincipal.principalURL(),
-                pcreds.authzPrincipal.principalURL(),
                 pcreds.authnPrincipal,
                 pcreds.authzPrincipal,
             ))

Modified: CalendarServer/trunk/twistedcaldav/cache.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/cache.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/twistedcaldav/cache.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -142,7 +142,7 @@
     log = Logger()
 
     def _principalURI(self, principal):
-        return str(principal.children[0])
+        return principal.principalURL() if principal is not None else "unauthenticated"
 
 
     def _uriNotFound(self, f, uri):

Modified: CalendarServer/trunk/twistedcaldav/directory/util.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/util.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/twistedcaldav/directory/util.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -32,7 +32,6 @@
 from txweb2.dav.resource import DAVResource
 from txweb2.http import StatusResponse
 from twisted.internet.defer import inlineCallbacks, returnValue
-from txdav.xml import element as davxml
 from uuid import UUID, uuid5
 from twisted.python.failure import Failure
 from twisted.web.template import tags
@@ -139,10 +138,10 @@
         try:
             _ignore_authnUser, authzUser = yield self.authenticate(request)
         except Exception:
-            authzUser = davxml.Principal(davxml.Unauthenticated())
+            authzUser = None
 
         # Turn 404 into 401
-        if authzUser == davxml.Principal(davxml.Unauthenticated()):
+        if authzUser is None:
             response = (yield UnauthorizedResponse.makeResponse(
                 request.credentialFactories,
                 request.remoteAddr

Modified: CalendarServer/trunk/twistedcaldav/test/test_addressbookmultiget.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_addressbookmultiget.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/twistedcaldav/test/test_addressbookmultiget.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -31,7 +31,6 @@
 from twisted.internet.defer import inlineCallbacks, returnValue
 
 from txdav.xml import element as davxml
-from twext.who.idirectory import RecordType
 
 
 
@@ -46,7 +45,7 @@
     @inlineCallbacks
     def setUp(self):
         yield StoreTestCase.setUp(self)
-        self.authRecord = yield self.directory.recordWithShortName(RecordType.user, u"wsanchez")
+        self.authPrincipal = yield self.actualRoot.findPrincipalForAuthID("wsanchez")
 
 
     def test_multiget_some_vcards(self):
@@ -217,7 +216,7 @@
 </D:set>
 </D:mkcol>
 """
-            response = yield self.send(SimpleStoreRequest(self, "MKCOL", addressbook_uri, content=mkcol, authRecord=self.authRecord))
+            response = yield self.send(SimpleStoreRequest(self, "MKCOL", addressbook_uri, content=mkcol, authPrincipal=self.authPrincipal))
 
             response = IResponse(response)
 
@@ -231,7 +230,7 @@
                         "PUT",
                         joinURL(addressbook_uri, filename + ".vcf"),
                         headers=Headers({"content-type": MimeType.fromString("text/vcard")}),
-                        authRecord=self.authRecord
+                        authPrincipal=self.authPrincipal
                     )
                     request.stream = MemoryStream(icaldata)
                     yield self.send(request)
@@ -245,12 +244,12 @@
                         "PUT",
                         joinURL(addressbook_uri, child.basename()),
                         headers=Headers({"content-type": MimeType.fromString("text/vcard")}),
-                        authRecord=self.authRecord
+                        authPrincipal=self.authPrincipal
                     )
                     request.stream = MemoryStream(child.getContent())
                     yield self.send(request)
 
-        request = SimpleStoreRequest(self, "REPORT", addressbook_uri, authRecord=self.authRecord)
+        request = SimpleStoreRequest(self, "REPORT", addressbook_uri, authPrincipal=self.authPrincipal)
         request.stream = MemoryStream(query.toxml())
         response = yield self.send(request)
 

Modified: CalendarServer/trunk/twistedcaldav/test/test_addressbookquery.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_addressbookquery.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/twistedcaldav/test/test_addressbookquery.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -27,7 +27,6 @@
 from twistedcaldav.test.util import StoreTestCase, SimpleStoreRequest
 from twisted.internet.defer import inlineCallbacks, returnValue
 from twisted.python.filepath import FilePath
-from twext.who.idirectory import RecordType
 
 
 
@@ -196,16 +195,16 @@
         if response.code != responsecode.CREATED:
             self.fail("MKCOL failed: %s" % (response.code,))
         '''
-        authRecord = yield self.directory.recordWithShortName(RecordType.user, u"wsanchez")
+        principal = yield self.actualRoot.findPrincipalForAuthID("wsanchez")
         # Add vCards to addressbook
         for child in FilePath(self.vcards_dir).children():
             if os.path.splitext(child.basename())[1] != ".vcf":
                 continue
-            request = SimpleStoreRequest(self, "PUT", joinURL(addressbook_uri, child.basename()), authRecord=authRecord)
+            request = SimpleStoreRequest(self, "PUT", joinURL(addressbook_uri, child.basename()), authPrincipal=principal)
             request.stream = MemoryStream(child.getContent())
             yield self.send(request)
 
-        request = SimpleStoreRequest(self, "REPORT", addressbook_uri, authRecord=authRecord)
+        request = SimpleStoreRequest(self, "REPORT", addressbook_uri, authPrincipal=principal)
         request.stream = MemoryStream(query.toxml())
         response = yield self.send(request)
 

Modified: CalendarServer/trunk/twistedcaldav/test/test_cache.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_cache.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/twistedcaldav/test/test_cache.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -24,14 +24,13 @@
 from txweb2.stream import MemoryStream
 from txweb2.http_headers import Headers
 
-from txdav.xml import element as davxml
-
 from twistedcaldav.cache import MemcacheResponseCache, CacheStoreNotifier
 from twistedcaldav.cache import MemcacheChangeNotifier
 from twistedcaldav.cache import PropfindCacheMixin
 
 from twistedcaldav.test.util import InMemoryMemcacheProtocol
 from twistedcaldav.test.util import TestCase
+from txdav.xml import element
 
 
 def _newCacheToken(self):
@@ -90,13 +89,27 @@
 
 
 
+class StubPrincipal(object):
+    def __init__(self, user):
+        self.user = user
+
+
+    def principalURL(self):
+        return self.user
+
+
+    def principalElement(self):
+        return element.Principal(element.HRef.fromString(self.user))
+
+
+
 class StubRequest(object):
     resources = {}
 
     def __init__(self, method, uri, authnUser, depth='1', body=None):
         self.method = method
         self.uri = uri
-        self.authnUser = davxml.Principal(davxml.HRef.fromString(authnUser))
+        self.authnUser = StubPrincipal(authnUser)
         self.headers = Headers({'depth': depth})
 
         if body is None:

Modified: CalendarServer/trunk/twistedcaldav/test/test_calendarquery.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_calendarquery.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/twistedcaldav/test/test_calendarquery.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -345,8 +345,8 @@
     @inlineCallbacks
     def calendar_query(self, query, got_xml):
 
-        authRecord = yield self.directory.recordWithShortName(RecordType.user, u"wsanchez")
-        request = SimpleStoreRequest(self, "REPORT", "/calendars/users/wsanchez/calendar/", authRecord=authRecord)
+        principal = yield self.actualRoot.findPrincipalForAuthID("wsanchez")
+        request = SimpleStoreRequest(self, "REPORT", "/calendars/users/wsanchez/calendar/", authPrincipal=principal)
         request.stream = MemoryStream(query.toxml())
         response = yield self.send(request)
 

Modified: CalendarServer/trunk/twistedcaldav/test/test_collectioncontents.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_collectioncontents.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/twistedcaldav/test/test_collectioncontents.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -15,7 +15,6 @@
 ##
 
 from twext.python.filepath import CachingFilePath as FilePath
-from twext.who.idirectory import RecordType
 from twisted.internet.defer import inlineCallbacks
 from twistedcaldav.ical import Component
 from twistedcaldav.memcachelock import MemcacheLock
@@ -68,15 +67,15 @@
         """
         calendar_uri = "/calendars/users/wsanchez/collection_in_calendar/"
 
-        authRecord = yield self.directory.recordWithShortName(RecordType.user, u"wsanchez")
-        request = SimpleStoreRequest(self, "MKCALENDAR", calendar_uri, authRecord=authRecord)
+        principal = yield self.actualRoot.findPrincipalForAuthID("wsanchez")
+        request = SimpleStoreRequest(self, "MKCALENDAR", calendar_uri, authPrincipal=principal)
         response = yield self.send(request)
         response = IResponse(response)
         if response.code != responsecode.CREATED:
             self.fail("MKCALENDAR failed: %s" % (response.code,))
             nested_uri = joinURL(calendar_uri, "nested")
 
-            request = SimpleStoreRequest(self, "MKCOL", nested_uri, authRecord=authRecord)
+            request = SimpleStoreRequest(self, "MKCOL", nested_uri, authPrincipal=principal)
             response = yield self.send(request)
             response = IResponse(response)
 
@@ -168,8 +167,8 @@
         """
         calendar_uri = "/calendars/users/wsanchez/testing_calendar/"
 
-        authRecord = yield self.directory.recordWithShortName(RecordType.user, u"wsanchez")
-        request = SimpleStoreRequest(self, "MKCALENDAR", calendar_uri, authRecord=authRecord)
+        principal = yield self.actualRoot.findPrincipalForAuthID("wsanchez")
+        request = SimpleStoreRequest(self, "MKCALENDAR", calendar_uri, authPrincipal=principal)
         response = yield self.send(request)
         response = IResponse(response)
         if response.code != responsecode.CREATED:
@@ -178,7 +177,7 @@
         c = 0
         for stream, response_code in work:
             dst_uri = joinURL(calendar_uri, "dst%d.ics" % (c,))
-            request = SimpleStoreRequest(self, "PUT", dst_uri, authRecord=authRecord)
+            request = SimpleStoreRequest(self, "PUT", dst_uri, authPrincipal=principal)
             request.headers.setHeader("if-none-match", "*")
             request.headers.setHeader("content-type", MimeType("text", "calendar"))
             request.stream = stream
@@ -197,8 +196,8 @@
         Make (regular) collection in calendar
         """
         calendar_uri = "/calendars/users/wsanchez/dot_file_in_calendar/"
-        authRecord = yield self.directory.recordWithShortName(RecordType.user, u"wsanchez")
-        request = SimpleStoreRequest(self, "MKCALENDAR", calendar_uri, authRecord=authRecord)
+        principal = yield self.actualRoot.findPrincipalForAuthID("wsanchez")
+        request = SimpleStoreRequest(self, "MKCALENDAR", calendar_uri, authPrincipal=principal)
         response = yield self.send(request)
         response = IResponse(response)
         if response.code != responsecode.CREATED:
@@ -215,7 +214,7 @@
 
         event_uri = "/".join([calendar_uri, ".event.ics"])
 
-        request = SimpleStoreRequest(self, "PUT", event_uri, authRecord=authRecord)
+        request = SimpleStoreRequest(self, "PUT", event_uri, authPrincipal=principal)
         request.headers.setHeader("content-type", MimeType("text", "calendar"))
         request.stream = MemoryStream(calendar)
         response = yield self.send(request)

Modified: CalendarServer/trunk/twistedcaldav/test/test_mkcalendar.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_mkcalendar.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/twistedcaldav/test/test_mkcalendar.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -27,10 +27,8 @@
 from twistedcaldav import caldavxml
 from twistedcaldav.test.util import StoreTestCase, SimpleStoreRequest
 
-from twext.who.idirectory import RecordType
 
 
-
 class MKCALENDAR (StoreTestCase):
     """
     MKCALENDAR request
@@ -42,7 +40,7 @@
     @inlineCallbacks
     def setUp(self):
         yield StoreTestCase.setUp(self)
-        self.authRecord = yield self.directory.recordWithShortName(RecordType.user, u"user01")
+        self.authPrincipal = yield self.actualRoot.findPrincipalForAuthID("user01")
 
 
     def test_make_calendar(self):
@@ -55,7 +53,7 @@
         if os.path.exists(path):
             rmdir(path)
 
-        request = SimpleStoreRequest(self, "MKCALENDAR", uri, authRecord=self.authRecord)
+        request = SimpleStoreRequest(self, "MKCALENDAR", uri, authPrincipal=self.authPrincipal)
 
         @inlineCallbacks
         def do_test(response):
@@ -156,7 +154,7 @@
             )
         )
 
-        request = SimpleStoreRequest(self, "MKCALENDAR", uri, authRecord=self.authRecord)
+        request = SimpleStoreRequest(self, "MKCALENDAR", uri, authPrincipal=self.authPrincipal)
         request.stream = MemoryStream(mk.toxml())
         return self.send(request, do_test)
 
@@ -175,7 +173,7 @@
 
             # FIXME: Check for DAV:resource-must-be-null element
 
-        request = SimpleStoreRequest(self, "MKCALENDAR", uri, authRecord=self.authRecord)
+        request = SimpleStoreRequest(self, "MKCALENDAR", uri, authPrincipal=self.authPrincipal)
         return self.send(request, do_test)
 
 
@@ -200,8 +198,8 @@
 
             nested_uri = os.path.join(first_uri, "nested")
 
-            request = SimpleStoreRequest(self, "MKCALENDAR", nested_uri, authRecord=self.authRecord)
+            request = SimpleStoreRequest(self, "MKCALENDAR", nested_uri, authPrincipal=self.authPrincipal)
             yield self.send(request, do_test)
 
-        request = SimpleStoreRequest(self, "MKCALENDAR", first_uri, authRecord=self.authRecord)
+        request = SimpleStoreRequest(self, "MKCALENDAR", first_uri, authPrincipal=self.authPrincipal)
         return self.send(request, next)

Modified: CalendarServer/trunk/twistedcaldav/test/test_multiget.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_multiget.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/twistedcaldav/test/test_multiget.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -14,7 +14,6 @@
 ##
 
 from twext.python.filepath import CachingFilePath as FilePath
-from twext.who.idirectory import RecordType
 from txweb2 import responsecode
 from txweb2.dav.util import davXMLFromStream, joinURL
 from txweb2.http_headers import Headers, MimeType
@@ -42,7 +41,7 @@
     @inlineCallbacks
     def setUp(self):
         yield StoreTestCase.setUp(self)
-        self.authRecord = yield self.directory.recordWithShortName(RecordType.user, u"wsanchez")
+        self.authPrincipal = yield self.actualRoot.findPrincipalForAuthID("wsanchez")
 
 
     def test_multiget_some_events(self):
@@ -269,7 +268,7 @@
     def calendar_query(self, calendar_uri, query, got_xml, data, no_init):
 
         if not no_init:
-            response = yield self.send(SimpleStoreRequest(self, "MKCALENDAR", calendar_uri, authRecord=self.authRecord))
+            response = yield self.send(SimpleStoreRequest(self, "MKCALENDAR", calendar_uri, authPrincipal=self.authPrincipal))
             response = IResponse(response)
             if response.code != responsecode.CREATED:
                 self.fail("MKCALENDAR failed: %s" % (response.code,))
@@ -281,7 +280,7 @@
                         "PUT",
                         joinURL(calendar_uri, filename + ".ics"),
                         headers=Headers({"content-type": MimeType.fromString("text/calendar")}),
-                        authRecord=self.authRecord
+                        authPrincipal=self.authPrincipal
                     )
                     request.stream = MemoryStream(icaldata)
                     yield self.send(request)
@@ -295,12 +294,12 @@
                         "PUT",
                         joinURL(calendar_uri, child.basename()),
                         headers=Headers({"content-type": MimeType.fromString("text/calendar")}),
-                        authRecord=self.authRecord
+                        authPrincipal=self.authPrincipal
                     )
                     request.stream = MemoryStream(child.getContent())
                     yield self.send(request)
 
-        request = SimpleStoreRequest(self, "REPORT", calendar_uri, authRecord=self.authRecord)
+        request = SimpleStoreRequest(self, "REPORT", calendar_uri, authPrincipal=self.authPrincipal)
         request.stream = MemoryStream(query.toxml())
         response = yield self.send(request)
 

Modified: CalendarServer/trunk/twistedcaldav/test/test_props.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_props.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/twistedcaldav/test/test_props.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -26,10 +26,8 @@
 
 from txdav.xml import element as davxml
 
-from twext.who.idirectory import RecordType
 
 
-
 class Properties(StoreTestCase):
     """
     CalDAV properties
@@ -38,7 +36,7 @@
     @inlineCallbacks
     def setUp(self):
         yield StoreTestCase.setUp(self)
-        self.authRecord = yield self.directory.recordWithShortName(RecordType.user, u"user01")
+        self.authPrincipal = yield self.actualRoot.findPrincipalForAuthID("user01")
 
 
     def test_live_props(self):
@@ -149,12 +147,12 @@
                 "PROPFIND",
                 calendar_uri,
                 headers=http_headers.Headers({"Depth": "0"}),
-                authRecord=self.authRecord,
+                authPrincipal=self.authPrincipal,
             )
             request.stream = MemoryStream(query.toxml())
             return self.send(request, propfind_cb)
 
-        request = SimpleStoreRequest(self, "MKCALENDAR", calendar_uri, authRecord=self.authRecord)
+        request = SimpleStoreRequest(self, "MKCALENDAR", calendar_uri, authPrincipal=self.authPrincipal)
         return self.send(request, mkcalendar_cb)
 
 
@@ -221,10 +219,10 @@
                 "PROPFIND",
                 calendar_uri,
                 headers=http_headers.Headers({"Depth": "0"}),
-                authRecord=self.authRecord,
+                authPrincipal=self.authPrincipal,
             )
             request.stream = MemoryStream(query.toxml())
             return self.send(request, propfind_cb)
 
-        request = SimpleStoreRequest(self, "MKCALENDAR", calendar_uri, authRecord=self.authRecord)
+        request = SimpleStoreRequest(self, "MKCALENDAR", calendar_uri, authPrincipal=self.authPrincipal)
         return self.send(request, mkcalendar_cb)

Modified: CalendarServer/trunk/twistedcaldav/test/test_resource.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_resource.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/twistedcaldav/test/test_resource.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -14,7 +14,6 @@
 # limitations under the License.
 ##
 
-from twext.who.idirectory import RecordType
 from twisted.internet.defer import inlineCallbacks
 from twistedcaldav import carddavxml
 from twistedcaldav.config import config
@@ -27,9 +26,10 @@
     InMemoryPropertyStore, StoreTestCase, SimpleStoreRequest
 )
 from twistedcaldav.test.util import TestCase
-from txdav.xml.element import HRef, Principal, Unauthenticated
+from txdav.xml.element import HRef
 from txweb2.http import HTTPError
 from txweb2.test.test_server import SimpleRequest
+from txdav.xml import element
 
 
 
@@ -61,6 +61,16 @@
 
 
 
+class StubPrincipal(object):
+    def __init__(self, user):
+        self.user = user
+
+
+    def principalElement(self):
+        return element.Principal(element.HRef.fromString(self.user))
+
+
+
 class CalDAVResourceTests(TestCase):
     def setUp(self):
         TestCase.setUp(self)
@@ -115,7 +125,7 @@
         """
         site = None
         request = SimpleRequest(site, "GET", "/not/a/real/url/")
-        request.authzUser = request.authnUser = Principal(Unauthenticated())
+        request.authzUser = request.authnUser = None
         rsrc = CalDAVResource()
         rsrc.owner = lambda igreq: HRef("/somebody/")
         self.assertEquals((yield rsrc.isOwner(request)), False)
@@ -129,8 +139,7 @@
         """
         site = None
         request = SimpleRequest(site, "GET", "/not/a/real/url/")
-        theOwner = Principal(HRef("/yes-i-am-the-owner/"))
-        request.authzUser = request.authnUser = theOwner
+        request.authzUser = request.authnUser = StubPrincipal("/yes-i-am-the-owner/")
         rsrc = CalDAVResource()
         rsrc.owner = lambda igreq: HRef("/no-i-am-not-the-owner/")
         self.assertEquals((yield rsrc.isOwner(request)), False)
@@ -144,8 +153,7 @@
         """
         site = None
         request = SimpleRequest(site, "GET", "/not/a/real/url/")
-        theOwner = Principal(HRef("/yes-i-am-the-owner/"))
-        request.authzUser = request.authnUser = theOwner
+        request.authzUser = request.authnUser = StubPrincipal("/yes-i-am-the-owner/")
         rsrc = CalDAVResource()
         rsrc.owner = lambda igreq: HRef("/yes-i-am-the-owner/")
         self.assertEquals((yield rsrc.isOwner(request)), True)
@@ -162,7 +170,7 @@
         self.patch(config, "AdminPrincipals", [theAdmin])
         site = None
         request = SimpleRequest(site, "GET", "/not/a/real/url/")
-        request.authzUser = request.authnUser = Principal(HRef(theAdmin))
+        request.authzUser = request.authnUser = StubPrincipal(theAdmin)
         rsrc = CalDAVResource()
         rsrc.owner = lambda igreq: HRef("/some-other-user/")
         self.assertEquals((yield rsrc.isOwner(request)), True)
@@ -179,7 +187,7 @@
         self.patch(config, "ReadPrincipals", [theAdmin])
         site = None
         request = SimpleRequest(site, "GET", "/not/a/real/url/")
-        request.authzUser = request.authnUser = Principal(HRef(theAdmin))
+        request.authzUser = request.authnUser = StubPrincipal(theAdmin)
         rsrc = CalDAVResource()
         rsrc.owner = lambda igreq: HRef("/some-other-user/")
         self.assertEquals((yield rsrc.isOwner(request)), True)
@@ -192,7 +200,7 @@
     @inlineCallbacks
     def setUp(self):
         yield StoreTestCase.setUp(self)
-        self.authRecord = yield self.directory.recordWithShortName(RecordType.user, u"wsanchez")
+        self.authPrincipal = yield self.actualRoot.findPrincipalForAuthID("wsanchez")
 
 
     @inlineCallbacks
@@ -201,7 +209,7 @@
         Get adbk
         """
 
-        request = SimpleStoreRequest(self, "GET", "/addressbooks/users/wsanchez/", authRecord=self.authRecord)
+        request = SimpleStoreRequest(self, "GET", "/addressbooks/users/wsanchez/", authPrincipal=self.authPrincipal)
         home = yield request.locateResource("/addressbooks/users/wsanchez")
 
         # default property initially not present

Modified: CalendarServer/trunk/twistedcaldav/test/test_sharing.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_sharing.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/twistedcaldav/test/test_sharing.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -84,8 +84,8 @@
 
     @inlineCallbacks
     def _doPOST(self, body, resultcode=responsecode.OK):
-        authRecord = yield self.directory.recordWithUID(u"user01")
-        request = SimpleStoreRequest(self, "POST", "/calendars/__uids__/user01/calendar/", content=body, authRecord=authRecord)
+        authPrincipal = yield self.actualRoot.findPrincipalForAuthID("user01")
+        request = SimpleStoreRequest(self, "POST", "/calendars/__uids__/user01/calendar/", content=body, authPrincipal=authPrincipal)
         request.headers.setHeader("content-type", MimeType("text", "xml"))
         response = yield self.send(request)
         response = IResponse(response)
@@ -110,8 +110,8 @@
 
     @inlineCallbacks
     def _doPOSTSharerAccept(self, body, resultcode=responsecode.OK, sharer="user02"):
-        authRecord = yield self.directory.recordWithUID(unicode(sharer))
-        request = SimpleStoreRequest(self, "POST", "/calendars/__uids__/{}/".format(sharer), content=body, authRecord=authRecord)
+        authPrincipal = yield self.actualRoot.findPrincipalForAuthID(sharer)
+        request = SimpleStoreRequest(self, "POST", "/calendars/__uids__/{}/".format(sharer), content=body, authPrincipal=authPrincipal)
         request.headers.setHeader("content-type", MimeType("text", "xml"))
         response = yield self.send(request)
         response = IResponse(response)
@@ -712,8 +712,8 @@
 
         @inlineCallbacks
         def listChildrenViaPropfind():
-            authRecord = yield self.directory.recordWithUID(u"user01")
-            request = SimpleStoreRequest(self, "PROPFIND", "/calendars/__uids__/user01/", authRecord=authRecord)
+            authPrincipal = yield self.actualRoot.findPrincipalForAuthID("user01")
+            request = SimpleStoreRequest(self, "PROPFIND", "/calendars/__uids__/user01/", authPrincipal=authPrincipal)
             request.headers.setHeader("depth", "1")
             response = yield self.send(request)
             response = IResponse(response)

Modified: CalendarServer/trunk/twistedcaldav/test/test_wrapping.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_wrapping.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/twistedcaldav/test/test_wrapping.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -175,11 +175,8 @@
             "http://localhost:8008/" + path
         )
         if user is not None:
-            record = yield self.directory.recordWithShortName(RecordType.user, user)
-            uid = record.uid
-            req.authnUser = req.authzUser = (
-                davxml.Principal(davxml.HRef('/principals/__uids__/' + uid + '/'))
-            )
+            principal = yield self.actualRoot.findPrincipalForAuthID(user)
+            req.authnUser = req.authzUser = principal
         returnValue(aResource)
 
 
@@ -585,13 +582,13 @@
         yield NamedLock.acquire(txn, "ImplicitUIDLock:%s" % (hashlib.md5("uid1").hexdigest(),))
 
         # PUT fails
-        authRecord = yield self.directory.recordWithShortName(RecordType.user, u"wsanchez")
+        principal = yield self.actualRoot.findPrincipalForAuthID("wsanchez")
         request = SimpleStoreRequest(
             self,
             "PUT",
             "/calendars/users/wsanchez/calendar/1.ics",
             headers=Headers({"content-type": MimeType.fromString("text/calendar")}),
-            authRecord=authRecord
+            authPrincipal=principal
         )
         request.stream = MemoryStream("""BEGIN:VCALENDAR
 CALSCALE:GREGORIAN
@@ -617,13 +614,13 @@
         """
 
         # PUT works
-        authRecord = yield self.directory.recordWithShortName(RecordType.user, u"wsanchez")
+        principal = yield self.actualRoot.findPrincipalForAuthID("wsanchez")
         request = SimpleStoreRequest(
             self,
             "PUT",
             "/calendars/users/wsanchez/calendar/1.ics",
             headers=Headers({"content-type": MimeType.fromString("text/calendar")}),
-            authRecord=authRecord
+            authPrincipal=principal
         )
         request.stream = MemoryStream("""BEGIN:VCALENDAR
 CALSCALE:GREGORIAN
@@ -647,12 +644,11 @@
         txn = self.transactionUnderTest()
         yield NamedLock.acquire(txn, "ImplicitUIDLock:%s" % (hashlib.md5("uid1").hexdigest(),))
 
-        authRecord = yield self.directory.recordWithShortName(RecordType.user, u"wsanchez")
         request = SimpleStoreRequest(
             self,
             "DELETE",
             "/calendars/users/wsanchez/calendar/1.ics",
-            authRecord=authRecord
+            authPrincipal=principal
         )
         response = yield self.send(request)
         self.assertEqual(response.code, responsecode.SERVICE_UNAVAILABLE)

Modified: CalendarServer/trunk/twistedcaldav/test/util.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/util.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/twistedcaldav/test/util.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -37,7 +37,6 @@
 from twistedcaldav.stdconfig import config
 from txdav.common.datastore.file import CommonDataStore
 from txdav.common.datastore.test.util import deriveQuota, CommonCommonTests
-from txdav.xml import element as element
 from txweb2.dav.test.util import SimpleRequest
 import txweb2.dav.test.util
 from txweb2.http import HTTPError, StatusResponse
@@ -79,15 +78,15 @@
     """
     A SimpleRequest that automatically grabs the proper transaction for a test.
     """
-    def __init__(self, test, method, uri, headers=None, content=None, authRecord=None):
+    def __init__(self, test, method, uri, headers=None, content=None, authPrincipal=None):
         super(SimpleStoreRequest, self).__init__(test.site, method, uri, headers, content)
         self._test = test
         self._newStoreTransaction = test.transactionUnderTest(txn=transactionFromRequest(self, test.storeUnderTest()))
         self.credentialFactories = {}
 
         # Fake credentials if auth needed
-        if authRecord is not None:
-            self.authzUser = self.authnUser = element.Principal(element.HRef("/principals/__uids__/%s/" % (authRecord.uid,)))
+        if authPrincipal is not None:
+            self.authzUser = self.authnUser = authPrincipal
 
 
     @inlineCallbacks

Modified: CalendarServer/trunk/twistedcaldav/upgrade.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/upgrade.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/twistedcaldav/upgrade.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -1119,9 +1119,7 @@
                     request = FakeRequest(root, "PUT", None)
                     request.noAttendeeRefresh = True  # tell scheduling to skip refresh
                     request.checkedSACL = True
-                    request.authnUser = request.authzUser = element.Principal(
-                        element.HRef.fromString("/principals/__uids__/%s/" % (uuid,))
-                    )
+                    request.authnUser = request.authzUser = principal
 
                     # The request may end up with an associated transaction and we must make sure that is
                     # either committed or aborted, so use try/finally to handle that case.

Modified: CalendarServer/trunk/txdav/who/wiki.py
===================================================================
--- CalendarServer/trunk/txdav/who/wiki.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/txdav/who/wiki.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -261,7 +261,7 @@
     userRecord = None
 
     try:
-        url = str(request.authnUser.children[0])
+        url = request.authnUser.principalURL()
         principal = (yield request.locateResource(url))
         if isinstance(principal, DirectoryPrincipalResource):
             userRecord = principal.record
@@ -277,7 +277,7 @@
         if access == WikiAccessLevel.read:
             request.wikiACL = davxml.ACL(
                 davxml.ACE(
-                    request.authnUser,
+                    request.authnUser.principalElement(),
                     davxml.Grant(
                         davxml.Privilege(davxml.Read()),
                         davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()),
@@ -306,7 +306,7 @@
         elif access == WikiAccessLevel.write:
             request.wikiACL = davxml.ACL(
                 davxml.ACE(
-                    request.authnUser,
+                    request.authnUser.principalElement(),
                     davxml.Grant(
                         davxml.Privilege(davxml.Read()),
                         davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()),

Modified: CalendarServer/trunk/txweb2/dav/auth.py
===================================================================
--- CalendarServer/trunk/txweb2/dav/auth.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/txweb2/dav/auth.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -7,10 +7,10 @@
 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 # copies of the Software, and to permit persons to whom the Software is
 # furnished to do so, subject to the following conditions:
-# 
+#
 # The above copyright notice and this permission notice shall be included in all
 # copies or substantial portions of the Software.
-# 
+#
 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -33,7 +33,7 @@
 from twisted.cred import checkers, error, portal
 from txweb2.resource import WrapperResource
 from txdav.xml.element import twisted_private_namespace, registerElement
-from txdav.xml.element import WebDAVTextElement, Principal, HRef
+from txdav.xml.element import WebDAVTextElement
 
 
 class AuthenticationWrapper(WrapperResource):
@@ -67,6 +67,7 @@
         # FIXME: some unit tests access self.credentialFactories, so assigning here
         self.credentialFactories = self.wireEncryptedCredentialFactories
 
+
     def hook(self, req):
         req.portal = self.portal
         req.loginInterfaces = self.loginInterfaces
@@ -83,23 +84,29 @@
         )
 
 
+
 class IPrincipal(Interface):
     pass
 
+
+
 class DavRealm(object):
     implements(portal.IRealm)
 
     def requestAvatar(self, avatarId, mind, *interfaces):
         if IPrincipal in interfaces:
-            return IPrincipal, Principal(HRef(avatarId[0])), Principal(HRef(avatarId[1]))
-        
+            # Return the associated principal resources
+            return IPrincipal, avatarId[0], avatarId[1]
+
         raise NotImplementedError("Only IPrincipal interface is supported")
 
 
+
 class IPrincipalCredentials(Interface):
     pass
 
 
+
 class PrincipalCredentials(object):
     implements(IPrincipalCredentials)
 
@@ -110,19 +117,19 @@
         (.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{ICredentials} for the authentication credentials.
         """
         self.authnPrincipal = authnPrincipal
         self.authzPrincipal = authzPrincipal
         self.credentials = credentials
 
+
     def checkPassword(self, password):
         return self.credentials.checkPassword(password)
 
 
+
 class TwistedPropertyChecker(object):
     implements(checkers.ICredentialsChecker)
 
@@ -135,19 +142,20 @@
         else:
             raise error.UnauthorizedLogin("Bad credentials for: %s" % (principalURIs[0],))
 
+
     def requestAvatarId(self, credentials):
         pcreds = IPrincipalCredentials(credentials)
         pswd = str(pcreds.authnPrincipal.readDeadProperty(TwistedPasswordProperty))
 
         d = defer.maybeDeferred(credentials.checkPassword, pswd)
         d.addCallback(self._cbPasswordMatch, (
-            pcreds.authnPrincipal.principalURL(),
-            pcreds.authzPrincipal.principalURL(),
             pcreds.authnPrincipal,
             pcreds.authzPrincipal,
         ))
         return d
 
+
+
 ##
 # Utilities
 ##

Modified: CalendarServer/trunk/txweb2/dav/idav.py
===================================================================
--- CalendarServer/trunk/txweb2/dav/idav.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/txweb2/dav/idav.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -7,10 +7,10 @@
 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 # copies of the Software, and to permit persons to whom the Software is
 # furnished to do so, subject to the following conditions:
-# 
+#
 # The above copyright notice and this permission notice shall be included in all
 # copies or substantial portions of the Software.
-# 
+#
 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -26,7 +26,7 @@
 web2.dav interfaces.
 """
 
-__all__ = [ "IDAVResource", "IDAVPrincipalResource", "IDAVPrincipalCollectionResource", ]
+__all__ = ["IDAVResource", "IDAVPrincipalResource", "IDAVPrincipalCollectionResource", ]
 
 from txweb2.iweb import IResource
 
@@ -44,13 +44,13 @@
     def findChildren(depth, request, callback, privileges, inherited_aces):
         """
         Returns an iterable of child resources for the given depth.
-        Because resources do not know their request URIs, chidren are returned
+        Because resources do not know their request URIs, children are returned
         as tuples C{(resource, uri)}, where C{resource} is the child resource
         and C{uri} is a URL path relative to this resource.
         @param depth: the search depth (one of C{"0"}, C{"1"}, or C{"infinity"})
         @param request: The current L{IRequest} responsible for this call.
         @param callback: C{callable} that will be called for each child found
-        @param privileges: the list of L{Privilege}s to test for.  This should 
+        @param privileges: the list of L{Privilege}s to test for.  This should
             default to None.
         @param inherited_aces: a list of L{Privilege}s for aces being inherited from
             the parent collection used to bypass inheritance lookup.
@@ -135,7 +135,7 @@
 
     def principalCollections():
         """
-        @return: an interable of L{IDAVPrincipalCollectionResource}s which
+        @return: an iterable of L{IDAVPrincipalCollectionResource}s which
             contain principals used in ACLs for this resource.
         """
 
@@ -176,8 +176,8 @@
     def privilegesForPrincipal(principal, request):
         """
         Evaluate the set of privileges that apply to the specified principal.
-        This involves examing all ace's and granting/denying as appropriate for
-        the specified principal's membership of the ace's prinicpal.
+        This involves examining all ace's and granting/denying as appropriate for
+        the specified principal's membership of the ace's principal.
         @param request: the request being processed.
         @return: a list of L{Privilege}s that are allowed on this resource for
             the specified principal.
@@ -186,32 +186,31 @@
     ##
     # Quota
     ##
-    
+
     def quota(request):
         """
         Get current available & used quota values for this resource's quota root
         collection.
 
-        @return: a C{tuple} containing two C{int}'s the first is 
+        @return: a C{tuple} containing two C{int}'s the first is
             quota-available-bytes, the second is quota-used-bytes, or
             C{None} if quota is not defined on the resource.
         """
-    
+
     def hasQuota(request):
         """
-        Check whether this resource is undre quota control by checking each parent to see if
+        Check whether this resource is under quota control by checking each parent to see if
         it has a quota root.
-        
+
         @return: C{True} if under quota control, C{False} if not.
         """
-        
+
     def hasQuotaRoot(request):
         """
         Determine whether the resource has a quota root.
 
         @return: a C{True} if this resource has quota root, C{False} otherwise.
         """
-    
 
     def quotaRoot(request):
         """
@@ -220,7 +219,7 @@
         @return: a C{int} containing the maximum allowed bytes if this collection
             is quota-controlled, or C{None} if not quota controlled.
         """
-    
+
     def setQuotaRoot(request, maxsize):
         """
         Set the quota root (max. allowed bytes) value for this collection.
@@ -228,7 +227,7 @@
         @param maxsize: a C{int} containing the maximum allowed bytes for the contents
             of this collection.
         """
-    
+
     def quotaSize(request):
         """
         Get the size of this resource (if its a collection get total for all children as well).
@@ -236,7 +235,7 @@
 
         @return: a L{Deferred} with a C{int} result containing the size of the resource.
         """
-        
+
     def currentQuotaUse(request):
         """
         Get the cached quota use value, or if not present (or invalid) determine
@@ -245,7 +244,7 @@
         @return: an L{Deferred} with a C{int} result containing the current used byte count if
             this collection is quota-controlled, or C{None} if not quota controlled.
         """
-        
+
     def updateQuotaUse(request, adjust):
         """
         Adjust current quota use on this all all parent collections that also
@@ -257,6 +256,8 @@
             is quota-controlled, or C{None} if not quota controlled.
         """
 
+
+
 class IDAVPrincipalResource (IDAVResource):
     """
     WebDAV principal resource.  (RFC 3744, section 2)
@@ -270,7 +271,6 @@
         @return: a iterable of URIs.
         """
 
-
     def principalURL():
         """
         Provides the URL which must be used to identify this principal in ACL
@@ -278,6 +278,12 @@
         @return: a URL.
         """
 
+    def principalElement():
+        """
+        Provides the XML element which must be used to identify this principal in ACL
+        requests.  (RFC 3744, section 4.2)
+        @return: L{element.Principal}.
+        """
 
     def groupMembers():
         """
@@ -286,7 +292,6 @@
         @return: a deferred returning an iterable of principal URLs.
         """
 
-
     def expandedGroupMembers():
         """
         Provides the principal URLs of principals that are members of this
@@ -296,7 +301,6 @@
         @return: a L{Deferred} that fires with an iterable of principal URLs.
         """
 
-
     def groupMemberships():
         """
         Provides the URLs of the group principals in which the principal is
@@ -318,7 +322,6 @@
         @return: a URL.
         """
 
-
     def principalForUser(user):
         """
         Retrieve the principal for a given username.
@@ -331,4 +334,3 @@
 
         @rtype: L{IDAVPrincipalResource}
         """
-

Modified: CalendarServer/trunk/txweb2/dav/resource.py
===================================================================
--- CalendarServer/trunk/txweb2/dav/resource.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/txweb2/dav/resource.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -133,7 +133,7 @@
     can only be accessed via the dead property store.
     """
     # Note: The DAV:owner and DAV:group live properties are only
-    # meaningful if you are using ACL semantics (ie. Unix-like) which
+    # meaningful if you are using ACL semantics (i.e. Unix-like) which
     # use them.  This (generic) class does not.
 
     def liveProperties(self):
@@ -957,7 +957,7 @@
             def translateError(response):
                 return Failure(HTTPError(response))
 
-            if request.authnUser == element.Principal(element.Unauthenticated()):
+            if request.authnUser == None:
                 return UnauthorizedResponse.makeResponse(
                     request.credentialFactories,
                     request.remoteAddr).addCallback(translateError)
@@ -973,9 +973,9 @@
     def authenticate(self, request):
         """
         Authenticate the given request against the portal, setting
-        both C{request.authzUser} (a C{str}, the username for the
-        purposes of authorization) and C{request.authnUser} (a C{str},
-        the username for the purposes of authentication) when it has
+        both C{request.authzUser} (a L{DAVPrincipalResource}, the user for the
+        purposes of authorization) and C{request.authnUser} (a L{DAVPrincipalResource},
+        the user for the purposes of authentication) when it has
         been authenticated.
 
         In order to authenticate, the request must have been
@@ -984,7 +984,7 @@
         necessary authentication metadata.
 
         If the request was not thusly prepared, both C{authzUser} and
-        C{authnUser} will be L{element.Unauthenticated}.
+        C{authnUser} will be None.
 
         @param request: the request which may contain authentication
             information and a reference to a portal to authenticate
@@ -1000,10 +1000,8 @@
 
         # Bypass normal authentication if its already been done (by SACL check)
         if (
-            hasattr(request, "authnUser") and
-            hasattr(request, "authzUser") and
-            request.authnUser is not None and
-            request.authzUser is not None
+            getattr(request, "authnUser", None) is not None and
+            getattr(request, "authzUser", None) is not None
         ):
             return succeed((request.authnUser, request.authzUser))
 
@@ -1012,8 +1010,8 @@
             hasattr(request, "credentialFactories") and
             hasattr(request, "loginInterfaces")
         ):
-            request.authnUser = element.Principal(element.Unauthenticated())
-            request.authzUser = element.Principal(element.Unauthenticated())
+            request.authnUser = None
+            request.authzUser = None
             return succeed((request.authnUser, request.authzUser))
 
         authHeader = request.headers.getHeader("authorization")
@@ -1082,8 +1080,8 @@
                 # This request has already been authenticated via the wiki
                 return succeed((request.authnUser, request.authzUser))
 
-            request.authnUser = element.Principal(element.Unauthenticated())
-            request.authzUser = element.Principal(element.Unauthenticated())
+            request.authnUser = None
+            request.authzUser = None
             return succeed((request.authnUser, request.authzUser))
 
 
@@ -1097,8 +1095,8 @@
         @return: the current authorized principal, as derived from the
             given request.
         """
-        if hasattr(request, "authzUser"):
-            return request.authzUser
+        if getattr(request, "authzUser", None) is not None:
+            return request.authzUser.principalElement()
         else:
             return unauthenticatedPrincipal
 
@@ -2489,6 +2487,17 @@
         unimplemented(self)
 
 
+    def principalElement(self):
+        """
+        See L{IDAVPrincipalResource.principalURL}.
+
+        This implementation raises L{NotImplementedError}.  Subclasses
+        must override this method to provide the principal URL for
+        this resource.
+        """
+        return element.Principal(element.HRef.fromString(self.principalURL()))
+
+
     def groupMembers(self):
         """
         This implementation returns a Deferred which fires with C{()},

Modified: CalendarServer/trunk/txweb2/dav/test/test_resource.py
===================================================================
--- CalendarServer/trunk/txweb2/dav/test/test_resource.py	2014-05-28 18:12:03 UTC (rev 13547)
+++ CalendarServer/trunk/txweb2/dav/test/test_resource.py	2014-05-28 18:29:34 UTC (rev 13548)
@@ -7,10 +7,10 @@
 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 # copies of the Software, and to permit persons to whom the Software is
 # furnished to do so, subject to the following conditions:
-# 
+#
 # The above copyright notice and this permission notice shall be included in all
 # copies or substantial portions of the Software.
-# 
+#
 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -41,6 +41,8 @@
         txweb2.dav.test.util.TestCase.setUp(self)
         TestResource._cachedPropertyStores = {}
 
+
+
 class GenericDAVResource(TestCase):
     def setUp(self):
         TestCase.setUp(self)
@@ -49,7 +51,7 @@
             "file1": TestResource("/file1"),
             "file2": AuthAllResource("/file2"),
             "dir1": TestResource("/dir1/", {
-                "subdir1": TestResource("/dir1/subdir1/",{})
+                "subdir1": TestResource("/dir1/subdir1/", {})
             }),
             "dir2": AuthAllResource("/dir2/", {
                 "file1": TestResource("/dir2/file1"),
@@ -63,6 +65,7 @@
 
         self.site = Site(rootresource)
 
+
     def test_findChildren(self):
         """
         This test asserts that we have:
@@ -134,7 +137,7 @@
         resource to verify that we can not find them giving our unauthenticated
         privileges.
         """
-        
+
         expected_children = [
             "/file1",
             "/dir1/",
@@ -193,12 +196,14 @@
                 resource.findChildren("infinity", request, raiseOnChild),
                 Exception
             )
-        
+
         request = SimpleRequest(self.site, "GET", "/")
         d = request.locateResource("/").addCallback(findChildren)
 
         return d
 
+
+
 class AccessTests(TestCase):
     def setUp(self):
         TestCase.setUp(self)
@@ -244,6 +249,7 @@
             loginInterfaces,
         ))
 
+
     def checkSecurity(self, request):
         """
         Locate the resource named by the given request's URI, then authorize it
@@ -253,10 +259,12 @@
         d.addCallback(lambda r: r.authorize(request, (davxml.Read(),)))
         return d
 
+
     def assertErrorResponse(self, error, expectedcode, otherExpectations=lambda err: None):
         self.assertEquals(error.response.code, expectedcode)
         otherExpectations(error)
 
+
     def test_checkPrivileges(self):
         """
         DAVResource.checkPrivileges()
@@ -296,8 +304,7 @@
 
         # Has auth; should allow
         request = SimpleRequest(site, "GET", "/")
-        request.authnUser = davxml.Principal(davxml.HRef("/users/d00d"))
-        request.authzUser = davxml.Principal(davxml.HRef("/users/d00d"))
+        request.authzUser = request.authnUser = self.rootresource.principalForUser("gooduser")
         d = request.locateResource("/")
         d.addCallback(_checkPrivileges)
         d.addCallback(expectOK)
@@ -318,6 +325,7 @@
             ("basic", "gooduser:goodpass".encode("base64")))
         return self.checkSecurity(request)
 
+
     def test_badUsernameOrPassword(self):
         request = SimpleRequest(self.site, "GET", "/protected")
         request.headers.setHeader(
@@ -343,6 +351,7 @@
         return d
 
 
+
 ##
 # Utilities
 ##
@@ -370,6 +379,7 @@
         self.children = children
         self.uri = uri
 
+
     def deadProperties(self):
         """
         Retrieve deadProperties from a special place in memory
@@ -382,20 +392,18 @@
             self._dead_properties = dp
         return self._dead_properties
 
+
     def isCollection(self):
         return self.children is not None
 
+
     def listChildren(self):
         return self.children.keys()
 
+
     def supportedPrivileges(self, request):
         return succeed(davPrivilegeSet)
 
-    def currentPrincipal(self, request):
-        if hasattr(request, "authzUser"):
-            return request.authzUser
-        else:
-            return davxml.Principal(davxml.Unauthenticated())
 
     def locateChild(self, request, segments):
         child = segments[0]
@@ -406,9 +414,11 @@
         else:
             raise HTTPError(404)
 
+
     def setAccessControlList(self, acl):
         self.acl = acl
 
+
     def accessControlList(self, request, **kwargs):
         return succeed(self.acl)
 
@@ -497,7 +507,8 @@
         )
     )
 
-    
+
+
 class TestDAVPrincipalResource(DAVPrincipalResource, TestResource):
     """
     Get deadProperties from TestResource
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20140528/320654be/attachment-0001.html>


More information about the calendarserver-changes mailing list