Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files

Port wiki and sharing to twext.who

  • Loading branch information
m0rgen committed Mar 28, 2014
1 parent 64ebc83 commit fd1bc3f478aa3654a77645a8f89601bf34295b9e
@@ -27,25 +27,28 @@

log = Logger()


@inlineCallbacks
def guidForAuthToken(token, host="localhost", port=80):
def uidForAuthToken(token, host="localhost", port=80):
"""
Send a GET request to the web auth service to retrieve the user record
guid associated with the provided auth token.
uid associated with the provided auth token.
@param token: An auth token, usually passed in via cookie when webcal
makes a request.
@type token: C{str}
@return: deferred returning a guid (C{str}) if successful, or
@return: deferred returning a uid (C{str}) if successful, or
will raise WebAuthError otherwise.
"""
url = "http://%s:%d/auth/verify?auth_token=%s" % (host, port, token,)
jsonResponse = (yield _getPage(url, host, port))
try:
response = json.loads(jsonResponse)
except Exception, e:
log.error("Error parsing JSON response from webauth: %s (%s)" %
(jsonResponse, str(e)))
log.error(
"Error parsing JSON response from webauth: {resp} {error}",
resp=jsonResponse, error=str(e)
)
raise WebAuthError("Could not look up token: %s" % (token,))
if response["succeeded"]:
returnValue(response["generated_uid"])
@@ -57,10 +60,10 @@ def guidForAuthToken(token, host="localhost", port=80):
def accessForUserToWiki(user, wiki, host="localhost", port=4444):
"""
Send a GET request to the wiki collabd service to retrieve the access level
the given user (in GUID form) has to the given wiki (in wiki short-name
the given user (uid) has to the given wiki (in wiki short-name
form).
@param user: The GUID of the user
@param user: The UID of the user
@type user: C{str}
@param wiki: The short name of the wiki
@type wiki: C{str}
@@ -69,8 +72,9 @@ def accessForUserToWiki(user, wiki, host="localhost", port=4444):
status FORBIDDEN will errBack; an unknown wiki will have a status
of NOT_FOUND
"""
url = "http://%s:%s/cal/accessLevelForUserWikiCalendar/%s/%s" % (host, port,
user, wiki)
url = "http://%s:%s/cal/accessLevelForUserWikiCalendar/%s/%s" % (
host, port, user, wiki
)
return _getPage(url, host, port)


@@ -19,29 +19,29 @@
"RootResource",
]

from calendarserver.platform.darwin.wiki import uidForAuthToken
from twext.python.log import Logger
from txweb2 import responsecode
from txweb2.auth.wrapper import UnauthorizedResponse
from txdav.xml import element as davxml
from txweb2.dav.xattrprops import xattrPropertyStore
from txweb2.http import HTTPError, StatusResponse, RedirectResponse

from twext.who.idirectory import RecordType
from twisted.cred.error import LoginFailed, UnauthorizedLogin
from twisted.internet.defer import inlineCallbacks, returnValue, succeed
from twisted.python.reflect import namedClass
from twisted.web.xmlrpc import Proxy
from twisted.web.error import Error as WebError

from twistedcaldav.cache import _CachedResponseResource
from twistedcaldav.cache import MemcacheResponseCache, MemcacheChangeNotifier
from twisted.web.xmlrpc import Proxy
from twistedcaldav.cache import DisabledCache
from twistedcaldav.cache import MemcacheResponseCache, MemcacheChangeNotifier
from twistedcaldav.cache import _CachedResponseResource
from twistedcaldav.config import config
from twistedcaldav.directory.principal import DirectoryPrincipalResource
from twistedcaldav.extensions import DAVFile, CachingPropertyStore
from twistedcaldav.extensions import DirectoryPrincipalPropertySearchMixIn
from twistedcaldav.extensions import ReadOnlyResourceMixIn
from twistedcaldav.resource import CalDAVComplianceMixIn
from twistedcaldav.directory.principal import DirectoryPrincipalResource
from calendarserver.platform.darwin.wiki import guidForAuthToken
from txdav.who.wiki import DirectoryService as WikiDirectoryService
from txdav.xml import element as davxml
from txweb2 import responsecode
from txweb2.auth.wrapper import UnauthorizedResponse
from txweb2.dav.xattrprops import xattrPropertyStore
from txweb2.http import HTTPError, StatusResponse, RedirectResponse

log = Logger()

@@ -234,20 +234,20 @@ def locateChild(self, request, segments):
record = None
try:
if wikiConfig.LionCompatibility:
guid = None
uid = None
proxy = Proxy(wikiConfig["URL"])
username = (yield proxy.callRemote(wikiConfig["UserMethod"], token))
directory = request.site.resource.getDirectory()
record = directory.recordWithShortName("users", username)
record = yield directory.recordWithShortName(RecordType.user, username)
if record is not None:
guid = record.guid
uid = record.uid
else:
guid = (yield guidForAuthToken(token))
if guid == "unauthenticated":
guid = None
uid = (yield uidForAuthToken(token))
if uid == "unauthenticated":
uid = None

except WebError, w:
guid = None
uid = None
# FORBIDDEN status means it's an unknown token
if int(w.status) == responsecode.NOT_FOUND:
log.debug("Unknown wiki token: %s" % (token,))
@@ -257,18 +257,18 @@ def locateChild(self, request, segments):

except Exception, e:
log.error("Failed to look up wiki token (%s)" % (e,))
guid = None
uid = None

if guid is not None:
log.debug("Wiki lookup returned guid: %s" % (guid,))
if uid is not None:
log.debug("Wiki lookup returned uid: %s" % (uid,))
principal = None
directory = request.site.resource.getDirectory()
record = directory.recordWithGUID(guid)
record = yield directory.recordWithUID(uid)
if record is not None:
username = record.shortNames[0]
log.debug("Wiki user record for user %s : %s" % (username, record))
for collection in self.principalCollections():
principal = collection.principalForRecord(record)
principal = yield collection.principalForRecord(record)
if principal is not None:
break

@@ -317,7 +317,7 @@ def locateChild(self, request, segments):
elif (len(segments) > 2 and segments[0] in ("calendars", "principals") and
(
segments[1] == "wikis" or
(segments[1] == "__uids__" and segments[2].startswith("wiki-"))
(segments[1] == "__uids__" and segments[2].startswith(WikiDirectoryService.uidPrefix))
)
):
# This is a wiki-related calendar resource. SACLs are not checked.
@@ -28,7 +28,6 @@

import errno
import os
from time import sleep
from socket import fromfd, AF_UNIX, SOCK_STREAM, socketpair
import psutil

@@ -46,17 +45,13 @@
from twisted.internet import reactor as _reactor
from twisted.internet.reactor import addSystemEventTrigger
from twisted.internet.tcp import Connection
from twisted.python.reflect import namedClass
# from twisted.python.failure import Failure

from twistedcaldav.bind import doBind
from twistedcaldav.cache import CacheStoreNotifierFactory
from twistedcaldav.directory import calendaruserproxy
from twistedcaldav.directory.addressbook import DirectoryAddressBookHomeProvisioningResource
from twistedcaldav.directory.calendar import DirectoryCalendarHomeProvisioningResource
from twistedcaldav.directory.digest import QopDigestCredentialFactory
from twistedcaldav.directory.principal import DirectoryPrincipalProvisioningResource
from twistedcaldav.directory.wiki import WikiDirectoryService
from calendarserver.push.notifier import NotifierFactory
from calendarserver.push.applepush import APNSubscriptionResource
from twistedcaldav.directorybackedaddressbook import DirectoryBackedAddressBookResource
@@ -98,8 +93,6 @@
from urllib import quote
from twisted.python.usage import UsageError

from txdav.dps.client import DirectoryService as DirectoryProxyClientService

from twext.who.checker import UsernamePasswordCredentialChecker
from twext.who.checker import HTTPDigestCredentialChecker
from twisted.cred.error import UnauthorizedLogin
@@ -281,96 +274,6 @@ def storeFromConfig(config, txnFactory, directoryService):



def REMOVEMEdirectoryFromConfig(config):
"""
Create an L{AggregateDirectoryService} from the given configuration.
"""

#
# Setup the Augment Service
#
if config.AugmentService.type:
augmentClass = namedClass(config.AugmentService.type)
log.info("Configuring augment service of type: {augmentClass}",
augmentClass=augmentClass)
try:
augmentService = augmentClass(**config.AugmentService.params)
except IOError:
log.error("Could not start augment service")
raise
else:
augmentService = None

#
# Setup the group membership cacher
#
if config.GroupCaching.Enabled:
groupMembershipCache = GroupMembershipCache(
config.GroupCaching.MemcachedPool,
expireSeconds=config.GroupCaching.ExpireSeconds)
else:
groupMembershipCache = None

#
# Setup the Directory
#
directories = []

directoryClass = namedClass(config.DirectoryService.type)
principalResourceClass = DirectoryPrincipalProvisioningResource

log.info("Configuring directory service of type: {directoryType}",
directoryType=config.DirectoryService.type)

config.DirectoryService.params.augmentService = augmentService
config.DirectoryService.params.groupMembershipCache = groupMembershipCache
baseDirectory = directoryClass(config.DirectoryService.params)

# Wait for the directory to become available
while not baseDirectory.isAvailable():
sleep(5)

directories.append(baseDirectory)

#
# Setup the Locations and Resources Service
#
if config.ResourceService.Enabled:
resourceClass = namedClass(config.ResourceService.type)

log.info("Configuring resource service of type: {resourceClass}",
resourceClass=resourceClass)

config.ResourceService.params.augmentService = augmentService
config.ResourceService.params.groupMembershipCache = groupMembershipCache
resourceDirectory = resourceClass(config.ResourceService.params)
resourceDirectory.realmName = baseDirectory.realmName
directories.append(resourceDirectory)

#
# Add wiki directory service
#
if config.Authentication.Wiki.Enabled:
wikiDirectory = WikiDirectoryService()
wikiDirectory.realmName = baseDirectory.realmName
directories.append(wikiDirectory)

directory = AggregateDirectoryService(directories, groupMembershipCache)

#
# Use system-wide realm on OSX
#
try:
import ServerFoundation
realmName = ServerFoundation.XSAuthenticator.defaultRealm().encode("utf-8")
directory.setRealm(realmName)
except ImportError:
pass
log.info("Setting up principal collection: {cls}", cls=principalResourceClass)
principalResourceClass("/principals/", directory)
return directory


# MOVE2WHO -- should we move this class somewhere else?
class PrincipalCredentialChecker(object):
credentialInterfaces = (IPrincipalCredentials,)
@@ -81,6 +81,7 @@ def __init__(
"locations": "Location",
"resources": "Resource",
"addresses": "Address",
"wikis": "Wiki",
}


@@ -38,7 +38,7 @@
from twistedcaldav.directory.common import uidsResourceName, \
CommonUIDProvisioningResource, CommonHomeTypeProvisioningResource

from twistedcaldav.directory.wiki import getWikiACL
from txdav.who.wiki import getWikiACL
from twistedcaldav.extensions import ReadOnlyResourceMixIn, DAVResource, \
DAVResourceWithChildrenMixin
from twistedcaldav.resource import CalendarHomeResource
@@ -48,7 +48,7 @@
from twistedcaldav.directory.util import (
formatLink, formatLinks, formatPrincipals, formatList
)
from twistedcaldav.directory.wiki import getWikiACL
from txdav.who.wiki import getWikiACL
from twistedcaldav.extensions import (
ReadOnlyResourceMixIn, DAVPrincipalResource, DAVResourceWithChildrenMixin
)
@@ -1308,6 +1308,7 @@ def canonicalCalendarUserAddress(self):
Return a CUA for this principal, preferring in this order:
urn:uuid: form
mailto: form
/principal/__uids__/ form
first in calendarUserAddresses( ) list
"""
return self.record.canonicalCalendarUserAddress()
@@ -250,8 +250,8 @@ def getWikiAccess(userID, wikiID, method=None):



def getWikiACL(resource, request):
return succeed(None)
# def getWikiACL(resource, request):
# return succeed(None)
# @inlineCallbacks
# def getWikiACL(resource, request):
# """
@@ -44,7 +44,7 @@
from twistedcaldav import customxml, caldavxml
from twistedcaldav.config import config
from twistedcaldav.customxml import calendarserver_namespace
from twistedcaldav.directory.wiki import WikiDirectoryService, getWikiAccess
from txdav.who.wiki import RecordType as WikiRecordType, WikiAccessLevel
from twistedcaldav.linkresource import LinkFollowerMixIn


@@ -269,15 +269,13 @@ def _checkAccessControl(self):
if self._newStoreObject.direct():
owner = yield self.principalForUID(self._newStoreObject.ownerHome().uid())
sharee = yield self.principalForUID(self._newStoreObject.viewerHome().uid())
if owner.record.recordType == WikiDirectoryService.recordType_wikis:
if owner.record.recordType == WikiRecordType.macOSXServerWiki:
# Access level comes from what the wiki has granted to the
# sharee
userID = sharee.record.guid
wikiID = owner.record.shortNames[0]
access = (yield getWikiAccess(userID, wikiID))
if access == "read":
access = (yield owner.record.accessForRecord(sharee.record))
if access == WikiAccessLevel.read:
returnValue("read-only")
elif access in ("write", "admin"):
elif access == WikiAccessLevel.write:
returnValue("read-write")
else:
returnValue(None)
@@ -502,7 +500,7 @@ def _defer(resultset):


@inlineCallbacks
def inviteSingleUserToShare(self, userid, cn, ace, summary, request): #@UnusedVariable
def inviteSingleUserToShare(self, userid, cn, ace, summary, request): #@UnusedVariable

# We currently only handle local users
sharee = yield self.principalForCalendarUserAddress(userid)
@@ -1257,7 +1257,13 @@ def _updateHostName(configDict, reloading=False):

# Default DirectoryRealmName from ServerHostName
if not configDict.DirectoryRealmName:
configDict.DirectoryRealmName = configDict.ServerHostName
# Use system-wide realm on OSX
try:
import ServerFoundation
realmName = ServerFoundation.XSAuthenticator.defaultRealm()
configDict.DirectoryRealmName = realmName
except ImportError:
configDict.DirectoryRealmName = configDict.ServerHostName



0 comments on commit fd1bc3f

Please sign in to comment.
You can’t perform that action at this time.