def accessControlList(self, request, *args, **kwargs): """ Override this to give write proxies DAV:write-acl privilege so they can add attachments too. """ acl = (yield super(DropBoxHomeResource, self).accessControlList(request, *args, **kwargs)) if config.EnableProxyPrincipals: owner = (yield self.ownerPrincipal(request)) newaces = tuple(acl.children) newaces += ( # DAV:write-acl access for this principal's calendar-proxy-write users. davxml.ACE( davxml.Principal( davxml.HRef( joinURL(owner.principalURL(), "calendar-proxy-write/"))), davxml.Grant(davxml.Privilege(davxml.WriteACL()), ), davxml.Protected(), TwistedACLInheritable(), ), ) returnValue(davxml.ACL(*newaces)) else: returnValue(acl)
def defaultAccessControlList(self): return succeed( davxml.ACL( davxml.ACE( davxml.Principal(davxml.Authenticated()), davxml.Grant(davxml.Privilege(davxml.Read()), ), davxml.Protected(), TwistedACLInheritable(), ), ))
def writeNewACEs(self, newaces): """ Write a new ACL to the resource's property store. We override this for calendar collections and force all the ACEs to be inheritable so that all calendar object resources within the calendar collection have the same privileges unless explicitly overridden. The same applies to drop box collections as we want all resources (attachments) to have the same privileges as the drop box collection. @param newaces: C{list} of L{ACE} for ACL being set. """ # Add inheritable option to each ACE in the list edited_aces = [] for ace in newaces: if TwistedACLInheritable() not in ace.children: children = list(ace.children) children.append(TwistedACLInheritable()) edited_aces.append(davxml.ACE(*children)) else: edited_aces.append(ace) # Do inherited with possibly modified set of aces return super(DropBoxCollectionResource, self).writeNewACEs(edited_aces)
def defaultAccessControlList(self): if config.AnonymousDirectoryAddressBookAccess: # DAV:Read for all principals (includes anonymous) accessPrincipal = davxml.All() else: # DAV:Read for all authenticated principals (does not include anonymous) accessPrincipal = davxml.Authenticated() return succeed( davxml.ACL( davxml.ACE( davxml.Principal(accessPrincipal), davxml.Grant( davxml.Privilege(davxml.Read()), davxml.Privilege( davxml.ReadCurrentUserPrivilegeSet())), davxml.Protected(), TwistedACLInheritable(), ), ))
def grantInherit(*privileges): return element.ACL(*[ element.ACE(element.Grant(element.Privilege(privilege)), element.Principal(element.All()), TwistedACLInheritable()) for privilege in privileges ])
def getWikiACL(resource, request): """ Ask the wiki server we're paired with what level of access the authnUser has. Returns an ACL. Wiki authentication is a bit tricky because the end-user accessing a group calendar may not actually be enabled for calendaring. Therefore in that situation, the authzUser will have been replaced with the wiki principal in locateChild( ), so that any changes the user makes will have the wiki as the originator. The authnUser will always be the end-user. """ from twistedcaldav.directory.principal import DirectoryPrincipalResource if (not hasattr(resource, "record") or resource.record.recordType != RecordType.macOSXServerWiki): returnValue(None) if hasattr(request, 'wikiACL'): returnValue(request.wikiACL) wikiRecord = resource.record wikiID = wikiRecord.shortNames[0] userRecord = None try: url = request.authnUser.principalURL() principal = (yield request.locateResource(url)) if isinstance(principal, DirectoryPrincipalResource): userRecord = principal.record except: # TODO: better error handling pass try: access = yield wikiRecord.accessForRecord(userRecord) # The ACL we returns has ACEs for the end-user and the wiki principal # in case authzUser is the wiki principal. if access == WikiAccessLevel.read: request.wikiACL = davxml.ACL( davxml.ACE( (request.authnUser.principalElement() if request.authnUser is not None else davxml.Principal( davxml.Unauthenticated())), davxml.Grant( davxml.Privilege(davxml.Read()), davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()), # We allow write-properties so that direct sharees can # change e.g. calendar color properties davxml.Privilege(davxml.WriteProperties()), ), TwistedACLInheritable(), ), davxml.ACE( davxml.Principal( davxml.HRef.fromString( "/principals/wikis/{}/".format(wikiID))), davxml.Grant( davxml.Privilege(davxml.Read()), davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()), ), TwistedACLInheritable(), )) returnValue(request.wikiACL) elif access == WikiAccessLevel.write: request.wikiACL = davxml.ACL( davxml.ACE( (request.authnUser.principalElement() if request.authnUser is not None else davxml.Principal( davxml.Unauthenticated())), davxml.Grant( davxml.Privilege(davxml.Read()), davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()), davxml.Privilege(davxml.Write()), ), TwistedACLInheritable(), ), davxml.ACE( davxml.Principal( davxml.HRef.fromString( "/principals/wikis/{}/".format(wikiID))), davxml.Grant( davxml.Privilege(davxml.Read()), davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()), davxml.Privilege(davxml.Write()), ), TwistedACLInheritable(), )) returnValue(request.wikiACL) else: # "no-access": if userRecord is None: # Return a 401 so they have an opportunity to log in response = (yield UnauthorizedResponse.makeResponse( request.credentialFactories, request.remoteAddr, )) raise HTTPError(response) raise HTTPError( StatusResponse(responsecode.FORBIDDEN, "You are not allowed to access this wiki")) except HTTPError: # pass through the HTTPError we might have raised above raise except Exception as e: log.error("Wiki ACL lookup failed: {error}", error=e) raise HTTPError( StatusResponse(responsecode.SERVICE_UNAVAILABLE, "Wiki ACL lookup failed"))
def shareeAccessControlList(self, request, *args, **kwargs): """ Return WebDAV ACLs appropriate for the current user accessing the shared collection. For an "invite" share we take the privilege granted to the sharee in the invite and map that to WebDAV ACLs. For a "direct" share, if it is a wiki collection we map the wiki privileges into WebDAV ACLs, otherwise we use whatever privileges exist on the underlying shared collection. @param request: the request used to locate the owner resource. @type request: L{txweb2.iweb.IRequest} @param args: The arguments for L{txweb2.dav.idav.IDAVResource.accessControlList} @param kwargs: The keyword arguments for L{txweb2.dav.idav.IDAVResource.accessControlList}, plus keyword-only arguments. @return: the appropriate WebDAV ACL for the sharee @rtype: L{davxml.ACL} """ assert self._isShareeResource, "Only call this for a sharee resource" assert self.isCalendarCollection() or self.isAddressBookCollection( ), "Only call this for a address book or calendar resource" sharee = yield self.principalForUID( self._newStoreObject.viewerHome().uid()) access = yield self._checkAccessControl() if access == "original" and not self._newStoreObject.ownerHome( ).external(): original = (yield request.locateResource(self._share_url)) result = (yield original.accessControlList(request, *args, **kwargs)) returnValue(result) # Direct shares use underlying privileges of shared collection userprivs = [] if access in ( "read-only", "read-write", ): userprivs.append(element.Privilege(element.Read())) userprivs.append(element.Privilege(element.ReadACL())) userprivs.append( element.Privilege(element.ReadCurrentUserPrivilegeSet())) if access in ("read-only", ): userprivs.append(element.Privilege(element.WriteProperties())) if access in ("read-write", ): userprivs.append(element.Privilege(element.Write())) proxyprivs = list(userprivs) try: proxyprivs.remove(element.Privilege(element.ReadACL())) except ValueError: # If wiki says no-access then ReadACL won't be in the list pass aces = ( # Inheritable specific access for the resource's associated principal. element.ACE( element.Principal(element.HRef(sharee.principalURL())), element.Grant(*userprivs), element.Protected(), TwistedACLInheritable(), ), ) if self.isCalendarCollection(): aces += ( # Inheritable CALDAV:read-free-busy access for authenticated users. element.ACE( element.Principal(element.Authenticated()), element.Grant(element.Privilege(caldavxml.ReadFreeBusy())), TwistedACLInheritable(), ), ) # Give read access to config.ReadPrincipals aces += config.ReadACEs # Give all access to config.AdminPrincipals aces += config.AdminACEs if self.isCalendarCollection() and config.EnableProxyPrincipals: aces += ( # DAV:read/DAV:read-current-user-privilege-set access for this principal's calendar-proxy-read users. element.ACE( element.Principal( element.HRef( joinURL(sharee.principalURL(), "calendar-proxy-read/"))), element.Grant( element.Privilege(element.Read()), element.Privilege( element.ReadCurrentUserPrivilegeSet()), element.Privilege(element.WriteProperties()), ), element.Protected(), TwistedACLInheritable(), ), # DAV:read/DAV:read-current-user-privilege-set/DAV:write access for this principal's calendar-proxy-write users. element.ACE( element.Principal( element.HRef( joinURL(sharee.principalURL(), "calendar-proxy-write/"))), element.Grant(*proxyprivs), element.Protected(), TwistedACLInheritable(), ), ) returnValue(element.ACL(*aces))