[CalendarServer-changes] [754]
CalendarServer/branches/caldavd-twistd-plugin-2
source_changes at macosforge.org
source_changes at macosforge.org
Thu Dec 7 16:16:03 PST 2006
Revision: 754
http://trac.macosforge.org/projects/calendarserver/changeset/754
Author: dreid at apple.com
Date: 2006-12-07 16:16:02 -0800 (Thu, 07 Dec 2006)
Log Message:
-----------
get rid of repsoitory.py and caldavd.py replace bin/caldavd with a very small shell script
Modified Paths:
--------------
CalendarServer/branches/caldavd-twistd-plugin-2/bin/caldavd
CalendarServer/branches/caldavd-twistd-plugin-2/twistedcaldav/config.py
CalendarServer/branches/caldavd-twistd-plugin-2/twistedcaldav/tap.py
Removed Paths:
-------------
CalendarServer/branches/caldavd-twistd-plugin-2/twistedcaldav/caldavd.py
CalendarServer/branches/caldavd-twistd-plugin-2/twistedcaldav/repository.py
Modified: CalendarServer/branches/caldavd-twistd-plugin-2/bin/caldavd
===================================================================
--- CalendarServer/branches/caldavd-twistd-plugin-2/bin/caldavd 2006-12-08 00:03:35 UTC (rev 753)
+++ CalendarServer/branches/caldavd-twistd-plugin-2/bin/caldavd 2006-12-08 00:16:02 UTC (rev 754)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/bin/sh
##
# Copyright (c) 2005-2006 Apple Computer, Inc. All rights reserved.
@@ -15,16 +15,56 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-# DRI: Cyrus Daboo, cdaboo at apple.com
+# DRI: David Reid, dreid at apple.com
##
+daemonize="";
+username="";
+groupname="";
+configfile="";
+twistdpath="$(type -p twistd)";
-if __name__ == "__main__":
- from twistedcaldav.caldavd import caldavd
+python="$(type -p python2.5)";
- import sys
+if [ "$?" != "0" ]; then
+ python="$(type -p python2.4)";
+fi;
- try:
- caldavd().run()
- except Exception, e:
- sys.exit(str(e))
+usage ()
+{
+ program="$(basename "$0")";
+
+ if [ "${1--}" != "-" ]; then echo "${1}"; echo; fi;
+
+ echo "Usage: ${program} [-hX] [-u username] [-g groupname] [-T twistd] [-f caldavd.plist]";
+ echo "Options:";
+ echo " -h Print this help and exit";
+ echo " -X Do not daemonize";
+ echo " -u Username to run as";
+ echo " -g Group to run as";
+ echo " -f Configuration file to read";
+ echo " -T Path to twistd binary";
+
+ if [ "${1-}" == "-" ]; then return 0; fi;
+ exit 64;
+}
+
+while getopts 'hXu:g:f:T:' option; do
+ case "${option}" in
+ '?') usage; ;;
+ 'h') usage -; exit 0; ;;
+ 'X') daemonize='-n'; ;;
+ 'f') configfile="-f ${OPTARG}"; ;;
+ 'T') twistdpath="${OPTARG}"; ;;
+ 'u') username="-u ${OPTARG}"; ;;
+ 'g') grouname="-g ${OPTARG}"; ;;
+ esac;
+done;
+
+shift $((${OPTIND} - 1));
+
+if [ $# != 0 ]; then usage "Unrecognized arguments:" "$@"; fi;
+
+exec "${python}" "${twistdpath}" \
+ "${daemonize}" ${username} ${groupname} caldav ${configfile};
+
Deleted: CalendarServer/branches/caldavd-twistd-plugin-2/twistedcaldav/caldavd.py
===================================================================
--- CalendarServer/branches/caldavd-twistd-plugin-2/twistedcaldav/caldavd.py 2006-12-08 00:03:35 UTC (rev 753)
+++ CalendarServer/branches/caldavd-twistd-plugin-2/twistedcaldav/caldavd.py 2006-12-08 00:16:02 UTC (rev 754)
@@ -1,409 +0,0 @@
-#!/usr/bin/env python
-
-##
-# Copyright (c) 2005-2006 Apple Computer, Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# DRI: Cyrus Daboo, cdaboo at apple.com
-##
-
-import sys
-import os
-import getopt
-import signal
-from tempfile import mkstemp
-
-try:
- #
- # plistlib is only included in Mac OS distributions of Python.
- # This may change in Python 2.6, see:
- # https://sourceforge.net/tracker/?func=detail&atid=105470&aid=1555501&group_id=5470
- #
- from plistlib import readPlist
-except ImportError:
- from twistedcaldav.py.plistlib import readPlist
-
-sys.path.insert(0, "/usr/share/caldavd/lib/python")
-
-"""
-Parse the command line and read in a configuration file and then launch the server.
-"""
-
-DEFAULTS = {
- 'DirectoryService': {'params': {'node': '/Search'},
- 'type': 'OpenDirectoryService'},
- 'DocumentRoot': '/Library/CalendarServer/Documents',
- 'DropBoxEnabled': True,
- 'DropBoxInheritedACLs': True,
- 'ErrorLogFile': '/var/log/caldavd/error.log',
- 'ManholePort': 0,
- 'MaximumAttachmentSizeBytes': 1048576,
- 'NotificationsEnabled': False,
- 'PIDFile': '/var/run/caldavd.pid',
- 'Port': 8008,
- 'Repository': '/etc/caldavd/repository.xml',
- 'RunStandalone': True,
- 'SSLCertificate': '/etc/certificates/Default.crt',
- 'SSLEnable': False,
- 'SSLOnly': False,
- 'SSLPort': 8443,
- 'SSLPrivateKey': '/etc/certificates/Default.key',
- 'ServerLogFile': '/var/log/caldavd/server.log',
- 'ServerStatsFile': '/Library/CalendarServer/Documents/stats.plist',
- 'UserQuotaBytes': 104857600,
- 'Verbose': False,
- 'twistdLocation': '/usr/share/caldavd/bin/twistd',
- 'SACLEnable': True,
- }
-
-# FIXME: This doesn't actually work because the webserver runs in a different
-# python process from the commandline util caldavd that actually parses the
-# plists the twistd plugin will fix this.
-CONFIG = DEFAULTS.copy()
-
-
-class caldavd(object):
- """
- Runs the caldav server.
- """
-
- def __init__(self):
- # Option defaults
- self.plistfile = "/etc/caldavd/caldavd.plist"
-
- self.config = CONFIG
-
- self.action = None
-
- def printit(self):
- """
- Print out details about the current configuration.
- """
-
- print "Current Configuration"
- print ""
- print "Configuration File: %s" % (self.plistfile,)
- print ""
- print "Run as daemon: %s" % (self.config['RunStandalone'],)
- print "Document Root: %s" % (self.config['DocumentRoot'],)
- print "Repository Configuration: %s" % (self.config['Repository'],)
- print "Non-ssl Port: %s" % (self.config['Port'],)
- print "Use SSL: %s" % (self.config['SSLEnable'],)
- print "SSL Port: %s" % (self.config['SSLPort'],)
- print "Only Use SSL: %s" % (self.config['SSLOnly'],)
- print "SSL Private Key File: %s" % (self.config['SSLPrivateKey'],)
- print "SSL Certificate File: %s" % (self.config['SSLCertificate'],)
- print "Directory Service: %s" % (self.config['DirectoryService']["type"],)
- print "Directory Service Parameters: %r" % (self.config['DirectoryService']["params"],)
- print "Drop Box Enabled: %s" % (self.config['DropBoxEnabled'],)
- print "Drop Box ACLs are Inherited %s" % (self.config['DropBoxInheritedACLs'],)
- print "Notifications Enabled: %s" % (self.config['NotificationsEnabled'],)
- print "Server Log File: %s" % (self.config['ServerLogFile'],)
- print "Error Log File: %s" % (self.config['ErrorLogFile'],)
- print "PID File: %s" % (self.config['PIDFile'],)
- print "twistd Location: %s" % (self.config['twistdLocation'],)
- print "Maximum Calendar Resource Size: %d bytes" % (self.config['MaximumAttachmentSizeBytes'],)
- print "Global per-user quota limit: %d bytes" % (self.config['UserQuotaBytes'],)
-
- def run(self):
- """
- Run the caldavd server using the provided options and configuration.
-
- @raise: C:{ValueError} if options or configuration are wrong.
- """
-
- # Parse command line options and config file
- self.commandLine()
- if self.action is None:
- return
-
- # Dispatch action
- {"start": self.start,
- "stop": self.stop,
- "restart": self.restart,
- "debug": self.debug, }[self.action]()
-
- def start(self):
- """
- Start the caldavd server.
- """
-
- print "Starting CalDAV Server",
- try:
- fd, tac = mkstemp(prefix="caldav")
- os.write(fd, self.generateTAC())
- os.close(fd)
- except Exception, e:
- print " [Failed]"
- print "Unable to create temporary file for server configuration."
- print e
- sys.exit(1)
-
- # Create arguments for twistd
- args = [os.path.basename(sys.executable)]
- args.append(self.config['twistdLocation'])
- if not self.config['RunStandalone']:
- args.append("-n")
- args.append("--logfile=%s" % (self.config['ErrorLogFile'],))
- args.append("--pidfile=%s" % (self.config['PIDFile'],))
- args.append("-y")
- args.append(tac)
-
- # Create environment for twistd
- environment = dict(os.environ)
- environment["PYTHONPATH"] = ":".join(sys.path)
-
- # spawn the twistd python process
- try:
- os.spawnve(os.P_WAIT, sys.executable, args, environment)
- except OSError, why:
- print " [Failed]"
- print "Error: %s" % (why[1],)
-
- # Get rid of temp file
- try:
- os.unlink(tac)
- except:
- pass
- print " [Done]"
-
- def stop(self):
- """
- Stop the caldavd server.
- """
-
- if os.path.exists(self.config['PIDFile']):
- try:
- pid = int(open(self.config['PIDFile']).read())
- except ValueError:
- sys.exit("Pidfile %s contains non-numeric value" % self.config['PIDFile'])
- try:
- print "Stopping CalDAV Server",
- os.kill(pid, signal.SIGTERM)
- print " [Done]"
- except OSError, why:
- print " [Failed]"
- print "Error: %s" % (why[1],)
- else:
- print "CalDAV server is not running"
-
- def restart(self):
- """
- Restart the caldavd server.
- """
- self.stop()
- self.start()
-
- def debug(self):
- """
- Debug the caldavd server. This is the same as starting it except we do not
- spawn a seperate process - we run twistd directly so a debugger stays 'attached'.
- """
-
- print "Starting CalDAV Server",
- try:
- fd, tac = mkstemp(prefix="caldav")
- os.write(fd, self.generateTAC())
- os.close(fd)
- except Exception, e:
- print " [Failed]"
- print "Unable to create temporary file for server configuration."
- print e
- sys.exit(1)
-
- # Create arguments for twistd
- args = []
- args.append(self.config['twistdLocation'])
- if not self.config['RunStandalone']:
- args.append("-n")
- args.append("--logfile=%s" % (self.config['ErrorLogFile'],))
- args.append("--pidfile=%s" % (self.config['PIDFile'],))
- args.append("-y")
- args.append(tac)
-
- # Create environment for twistd
- environment = dict(os.environ)
- environment["PYTHONPATH"] = ":".join(sys.path)
-
- # run the twistd python process directly
- try:
- sys.argv = args
- os.environ = environment
- from twisted.scripts.twistd import run
- run()
- except OSError, why:
- print " [Failed]"
- print "Error: %s" % (why[1],)
-
- # Get rid of temp file
- try:
- os.unlink(tac)
- except:
- pass
- print " [Done]"
-
- def commandLine(self):
- """
- Parse the command line options into the config object.
-
- @return: the C{str} for the requested action, or C{None} when
- immediate exit is called for.
- @raise: C{ValueError} when a problem occurs with the options.
- """
- options, args = getopt.getopt(sys.argv[1:], "hvf:XT:p")
-
- # Process the plist file first, then the options, so that command line
- # options get to override plist options
- pls = [p for p in options if p[0] == "-f"]
- if len(pls) == 1:
- self.plistfile = pls[0][1]
- if not os.path.exists(self.plistfile):
- print "Configuration file does not exist: %s" % (self.plistfile,)
- raise ValueError
- self.parsePlist()
-
- # Parse all the options
- do_print = False
- for option, value in options:
- if option == "-h":
- self.usage()
- return
- elif option == "-v":
- self.config['Verbose'] = True
- elif option == "-f":
- # We should have handled this already
- pass
- elif option == "-X":
- self.config['RunStandalone'] = False
- elif option == "-T":
- self.config['twistdLocation'] = value
- elif option == "-p":
- do_print = True
- else:
- print "Unrecognized option: %s" % (option,)
- self.usage()
- raise ValueError
-
- # Print out config if requested
- if do_print:
- self.printit()
- return
-
- # Process arguments
- if len(args) == 0:
- print "No arguments given. One of start, stop, restart or debug must be present."
- self.usage()
- raise ValueError
- elif len(args) > 1:
- print "Too many arguments given. Only one of start, stop, restart or debug must be present."
- self.usage()
- raise ValueError
- elif args[0] not in ("start", "stop", "restart", "debug",):
- print "Wrong arguments given: %s" % (args[0],)
- self.usage()
- raise ValueError
-
- # Verify that configuration is valid
- if not self.validate():
- raise ValueError
-
- self.action = args[0]
-
- def parsePlist(self):
- print "Reading configuration file %s." % (self.plistfile,)
-
- root = readPlist(self.plistfile)
-
- for k,v in root.items():
- if k in self.config:
- self.config[k] = v
- else:
- print "Unknown option: %s" % (k,)
-
- CONFIG = self.config
-
- def validate(self):
-
- result = True
-
- if not os.path.exists(self.config['DocumentRoot']):
- print "Document Root does not exist: %s" % (self.config['DocumentRoot'],)
- result = False
-
- if not os.path.exists(self.config['Repository']):
- print "Repository File does not exist: %s" % (self.config['Repository'],)
- result = False
-
- if self.config['SSLEnable'] and not os.path.exists(self.config['SSLPrivateKey']):
- print "SSL Private Key File does not exist: %s" % (self.config['SSLPrivateKey'],)
- result = False
-
- if self.config['SSLEnable'] and not os.path.exists(self.config['SSLCertificate']):
- print "SSL Certificate File does not exist: %s" % (self.config['SSLCertificate'],)
- result = False
-
- if not self.config['SSLEnable'] and self.config['SSLOnly']:
- self.config['SSLEnable'] = True
-
- if not self.config['RunStandalone']:
- self.config['ErrorLogFile'] = "-"
-
- if not os.path.exists(self.config['twistdLocation']):
- print "twistd does not exist: %s" % (self.config['twistdLocation'],)
- result = False
-
- return result
-
- def usage(self):
- default = caldavd()
- print """Usage: caldavd [options] start|stop|restart|debug
-Options:
- -h Print this help and exit
- -v Be verbose
- -f config Specify path to configuration file [""" + default.plistfile + """]
- -X Do not daemonize
- -T twistd Specify path to twistd [""" + default.twistd + """]
- -p Print current configuration and exit
-"""
-
- def generateTAC(self):
- return """
-from twistedcaldav.repository import startServer
-
-application, site = startServer(
- %(DocumentRoot)r,
- %(Repository)r,
- %(SSLEnable)s,
- %(SSLPrivateKey)r,
- %(SSLCertificate)r,
- %(SSLOnly)s,
- %(Port)d,
- %(SSLPort)d,
- %(MaximumAttachmentSizeBytes)d,
- %(UserQuotaBytes)d,
- %(ServerLogFile)r,
- %(DirectoryService)r,
- %(DropBoxEnabled)r,
- %(DropBoxInheritedACLs)r,
- %(NotificationsEnabled)r,
- %(ManholePort)d,
-)
-""" % self.config
-
-
-if __name__ == "__main__":
- try:
- caldavd().run()
- except Exception, e:
- sys.exit(str(e))
Modified: CalendarServer/branches/caldavd-twistd-plugin-2/twistedcaldav/config.py
===================================================================
--- CalendarServer/branches/caldavd-twistd-plugin-2/twistedcaldav/config.py 2006-12-08 00:03:35 UTC (rev 753)
+++ CalendarServer/branches/caldavd-twistd-plugin-2/twistedcaldav/config.py 2006-12-08 00:16:02 UTC (rev 754)
@@ -51,7 +51,7 @@
'UserQuotaBytes': 104857600,
'Verbose': False,
'twistdLocation': '/usr/share/caldavd/bin/twistd',
- 'SACLEnable': True,
+ 'SACLEnable': False,
'AuthSchemes': ['Basic'],
'AdminPrincipals': ['/principal/users/admin']
}
Deleted: CalendarServer/branches/caldavd-twistd-plugin-2/twistedcaldav/repository.py
===================================================================
--- CalendarServer/branches/caldavd-twistd-plugin-2/twistedcaldav/repository.py 2006-12-08 00:03:35 UTC (rev 753)
+++ CalendarServer/branches/caldavd-twistd-plugin-2/twistedcaldav/repository.py 2006-12-08 00:16:02 UTC (rev 754)
@@ -1,700 +0,0 @@
-##
-# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# DRI: Cyrus Daboo, cdaboo at apple.com
-##
-
-"""
-Initial setup of CalDAV repository resource hierarchy, together with optional
-auto-provisioning of user calendar home collections and principals, with appropriate
-properties, access control etc setup.
-"""
-
-__all__ = ["RepositoryBuilder"]
-
-import os
-
-from xml.dom.minidom import Element
-from xml.dom.minidom import Text
-import xml.dom.minidom
-
-from twisted.application.internet import SSLServer, TCPServer
-from twisted.application.service import Application, IServiceCollection, MultiService
-from twisted.cred.portal import Portal
-from twisted.internet.ssl import DefaultOpenSSLContextFactory
-from twisted.python import log
-from twisted.python.reflect import namedObject
-from twisted.web2.auth import basic, digest
-from twisted.web2.channel.http import HTTPFactory
-from twisted.web2.dav import auth, davxml
-from twisted.web2.dav.element.base import PCDATAElement
-from twisted.web2.dav.element.parser import lookupElement
-from twisted.web2.dav.resource import TwistedACLInheritable
-from twisted.web2.dav.util import joinURL
-from twisted.web2.dav.idav import IDAVPrincipalCollectionResource
-from twisted.web2.log import LogWrapperResource
-from twisted.web2.server import Site
-
-from twistedcaldav.dropbox import DropBox
-from twistedcaldav import authkerb
-from twistedcaldav.logging import RotatingFileAccessLoggingObserver
-from twistedcaldav.resource import CalDAVResource
-from twistedcaldav.static import CalendarHomeFile
-
-ELEMENT_REPOSITORY = "repository"
-
-ELEMENT_DOCROOT = "docroot"
-ELEMENT_COLLECTION = "collection"
-ELEMENT_PYTYPE = "pytype"
-ELEMENT_PARAMS = "params"
-ELEMENT_PARAM = "param"
-ELEMENT_KEY = "key"
-ELEMENT_VALUE = "value"
-ELEMENT_PROPERTIES = "properties"
-ELEMENT_PROP = "prop"
-ELEMENT_MEMBERS = "members"
-
-ELEMENT_ACL = "acl"
-ELEMENT_ACE = "ace"
-ELEMENT_PRINCIPAL = "principal"
-ELEMENT_HREF = "href"
-ELEMENT_ALL = "all"
-ELEMENT_AUTHENTICATED = "authenticated"
-ELEMENT_UNAUTHENTICATED = "unauthenticated"
-ELEMENT_GRANT = "grant"
-ELEMENT_DENY = "deny"
-ELEMENT_PRIVILEGE = "privilege"
-ELEMENT_PROTECTED = "protected"
-ELEMENT_INHERITABLE = "inheritable"
-
-ELEMENT_READ = "read"
-
-ATTRIBUTE_VALUE_YES = "yes"
-ATTRIBUTE_VALUE_NO = "no"
-
-ATTRIBUTE_NAME = "name"
-ATTRIBUTE_TAG = "tag"
-ATTRIBUTE_ACCOUNT = "account"
-ATTRIBUTE_INITIALIZE = "initialize"
-
-ATTRVALUE_NONE = "none"
-ATTRVALUE_PRINCIPALS = "principals"
-ATTRVALUE_CALENDARS = "calendars"
-
-ELEMENT_AUTHENTICATION = "authentication"
-ELEMENT_BASIC = "basic"
-ELEMENT_DIGEST = "digest"
-ELEMENT_KERBEROS = "kerberos"
-ELEMENT_REALM = "realm"
-ELEMENT_SERVICE = "service"
-
-ATTRIBUTE_ENABLE = "enable"
-ATTRIBUTE_ONLYSSL = "onlyssl"
-
-ATTRIBUTE_VALUE_DIRECTORY = "directory"
-ATTRIBUTE_VALUE_KERBEROS = "kerberos"
-
-def startServer(docroot, repo, dossl,
- keyfile, certfile, onlyssl, port, sslport, maxsize,
- quota, serverlogfile,
- directoryservice,
- dropbox, dropboxACLs,
- notifications,
- manhole):
- """
- Start the server using XML-based configuration details and supplied .plist based options.
- """
-
- # Make sure SSL options make sense
- if not dossl and onlyssl:
- dossl = True
-
- # Check the file paths for validity
- if os.path.exists(docroot):
- print "Document root is: %s" % (docroot,)
- else:
- raise IOError("No such docroot: %s" % (docroot,))
-
- if os.path.exists(repo):
- print "Repository configuration is: %s" % (repo,)
- else:
- raise IOError("No such repo: %s" % (repo,))
-
- if dossl:
- if os.path.exists(keyfile):
- print "Using SSL private key file: %s" % (keyfile,)
- else:
- raise IOError("SSL Private Key file does not exist: %s" % (keyfile,))
-
- if os.path.exists(certfile):
- print "Using SSL certificate file: %s" % (certfile,)
- else:
- raise IOError("SSL Certificate file does not exist: %s" % (certfile,))
-
- # We need a special service for the access log
- class Web2Service(MultiService):
- def __init__(self, logObserver):
- self.logObserver = logObserver
- MultiService.__init__(self)
-
- def startService(self):
- MultiService.startService(self)
- self.logObserver.start()
-
- def stopService(self):
- MultiService.stopService(self)
- self.logObserver.stop()
-
- # Turn on drop box support before building the repository
- DropBox.enable(dropbox, dropboxACLs, notifications)
-
- dirname = directoryservice["type"]
- dirparams = directoryservice["params"]
- try:
- resource_class = namedObject(dirname)
- except:
- log.err("Unable to locate Python class %r" % (dirname,))
- raise
- try:
- directory = resource_class(**dirparams)
- except Exception:
- log.err("Unable to instantiate Python class %r with arguments %r" % (resource_class, dirparams))
- raise
-
- # Build the server
- builder = RepositoryBuilder(docroot,
- maxsize=maxsize,
- quota=quota)
- builder.buildFromFile(repo, directory)
- rootresource = builder.docRoot.collection.resource
-
- application = Application("CalDAVServer")
- parent = IServiceCollection(application)
- web2 = Web2Service(RotatingFileAccessLoggingObserver(serverlogfile))
- web2.setServiceParent(parent)
- parent = web2
-
- # Configure appropriate authentication
- authenticator = builder.authentication.getEnabledAuthenticator()
-
- portal = Portal(auth.DavRealm())
- if authenticator.credentials == ATTRIBUTE_VALUE_DIRECTORY:
- portal.registerChecker(directory)
- print "Using directory-based password checker."
- elif authenticator.credentials == ATTRIBUTE_VALUE_KERBEROS:
- if authenticator.type == "basic":
- portal.registerChecker(authkerb.BasicKerberosCredentialsChecker())
- elif authenticator.type == "kerberos":
- portal.registerChecker(authkerb.NegotiateCredentialsChecker())
- print "Using Kerberos-based password checker."
-
- if authenticator.type == "basic":
- if authenticator.credentials == ATTRIBUTE_VALUE_KERBEROS:
- credentialFactories = (authkerb.BasicKerberosCredentialFactory(authenticator.service, authenticator.realm),)
- else:
- credentialFactories = (basic.BasicCredentialFactory(authenticator.realm),)
- print "Using HTTP BASIC authentication."
- elif authenticator.type == "digest":
- credentialFactories = (digest.DigestCredentialFactory("md5", authenticator.realm),)
- print "Using HTTP DIGEST authentication."
- elif authenticator.type == "kerberos":
- credentialFactories = (authkerb.NegotiateCredentialFactory(authenticator.service),)
- print "Using HTTP NEGOTIATE authentication."
-
- loginInterfaces = (auth.IPrincipal,)
-
- # Build the site and server instances
- site = Site(LogWrapperResource(auth.AuthenticationWrapper(rootresource,
- portal,
- credentialFactories,
- loginInterfaces)))
-
- factory = HTTPFactory(site)
-
- if not onlyssl:
- print "Starting http server"
- TCPServer(port, factory).setServiceParent(parent)
-
- if dossl:
- print "Starting https server"
- sslContext = DefaultOpenSSLContextFactory(keyfile, certfile)
- SSLServer(sslport, factory, sslContext).setServiceParent(parent)
-
- if manhole:
- print "Starting manhole on port %d" % (manhole,)
- from twisted.manhole.telnet import ShellFactory
- from twisted.internet import reactor
- manhole_factory = ShellFactory()
- reactor.listenTCP(manhole, manhole_factory)
- manhole_factory.username = "admin"
- manhole_factory.password = ""
- manhole_factory.namespace["site"] = site
- manhole_factory.namespace["portal"] = portal
-
- return application, site
-
-class RepositoryBuilder (object):
- """
- Builds a repository hierarchy at a supplied document root file system path.
- """
-
- def __init__(self, docroot, maxsize=None, quota=None):
- """
- @param docroot: file system path to use as the root.
- @param maxsize: maximum size in bytes for any calendar object resource, C{int} to set size,
- if <= 0, then no limit will be set.
- @param quota: maximum quota size in bytes for a user's calendar home, C{int} to set size,
- if <= 0, then no limit will be set.
- """
- self.docRoot = DocRoot(docroot)
- self.authentication = Authentication()
- self.maxsize = maxsize
- self.quota = quota
-
- if self.maxsize <= 0:
- self.maxsized = None
- if self.quota <= 0:
- self.quota = None
-
- def buildFromFile(self, filename, directory):
- """
- Parse the required information from an XML file.
- @param file: the path of the XML file to parse.
- """
- # Read in XML
- fd = open(filename, "r")
- doc = xml.dom.minidom.parse( fd )
- fd.close()
-
- # Verify that top-level element is correct
- repository_node = doc._get_documentElement()
- if repository_node._get_localName() != ELEMENT_REPOSITORY:
- self.log("Ignoring file %r because it is not a repository builder file" % (filename,))
- return
- self.parseXML(repository_node)
-
- self.docRoot.build(directory)
-
- # Handle global quota value
- CalendarHomeFile.quotaLimit = self.quota
- CalDAVResource.sizeLimit = self.maxsize
-
- def parseXML(self, node):
- """
- Parse the XML root node from the repository configuration document.
- @param node: the L{Node} to parse.
- """
- for child in node._get_childNodes():
- if child._get_localName() == ELEMENT_DOCROOT:
- self.docRoot.parseXML(child)
- elif child._get_localName() == ELEMENT_AUTHENTICATION:
- self.authentication.parseXML(child)
-
-class DocRoot (object):
- """
- Represents the hierarchy of resource collections that form the CalDAV repository.
- """
- def __init__(self, docroot):
- """
- @param docroot: the file system path for the root of the hierarchy.
- """
- self.collection = None
- self.path = docroot
- self.principalCollections = []
- self.accountCollection = None
- self.initCollections = []
- self.calendarHome = None
-
- def parseXML(self, node):
- """
- Parse the XML collection nodes from the repository configuration document.
- @param node: the L{Node} to parse.
- """
- for child in node._get_childNodes():
- if child._get_localName() == ELEMENT_COLLECTION:
- self.collection = Collection()
- self.collection.parseXML(child, self)
- break
-
- def build(self, directory):
- """
- Build the entire repository starting at the root resource.
- """
- self.collection.build(self, self.path, "/", directory)
-
- # Cheat
- self.collection.resource._principalCollections = self.principalCollections
-
-class Collection (object):
- """
- Contains information about a collection in the repository.
- """
- def __init__(self):
- self.name = None
- self.pytype = None
- self.params = {}
- self.properties = []
- self.acl = None
- self.members = []
- self.resource = None
- self.uri = None
-
- def parseXML(self, node, builder):
- """
- Parse the XML collection node from the repository configuration document.
- @param node: the L{Node} to parse.
- @param builder: the L{RepositoryBuilder} in use.
- """
- if node.hasAttribute(ATTRIBUTE_NAME):
- self.name = node.getAttribute(ATTRIBUTE_NAME).encode("utf-8")
- if node.hasAttribute(ATTRIBUTE_TAG):
- tag = node.getAttribute(ATTRIBUTE_TAG)
- if tag == ATTRVALUE_PRINCIPALS:
- builder.principalCollections.append(self)
- elif tag == ATTRVALUE_CALENDARS:
- builder.calendarHome = self
- if node.hasAttribute(ATTRIBUTE_ACCOUNT) and node.getAttribute(ATTRIBUTE_ACCOUNT) == ATTRIBUTE_VALUE_YES:
- builder.accountCollection = self
- if node.hasAttribute(ATTRIBUTE_INITIALIZE) and node.getAttribute(ATTRIBUTE_INITIALIZE) == ATTRIBUTE_VALUE_YES:
- builder.initCollections.append(self)
-
- for child in node._get_childNodes():
- if child._get_localName() == ELEMENT_PYTYPE:
- if child.firstChild is not None:
- self.pytype = child.firstChild.data.encode("utf-8")
- elif child._get_localName() == ELEMENT_PARAMS:
- self.parseParamsXML(child)
- elif child._get_localName() == ELEMENT_PROPERTIES:
- self.parsePropertiesXML(child)
- elif child._get_localName() == ELEMENT_MEMBERS:
- for member in child._get_childNodes():
- if member._get_localName() == ELEMENT_COLLECTION:
- collection = Collection()
- collection.parseXML(member, builder)
- self.members.append(collection)
-
- def parseParamsXML(self, node):
- """
- Parse the XML node for parameters for the collection.
- @param node: the L{Node} to parse.
- """
- for child in node._get_childNodes():
- if child._get_localName() == ELEMENT_PARAM:
- self.parseParamXML(child)
-
- def parseParamXML(self, node):
- """
- Parse the XML node for a parameter for the collection.
- @param node: the L{Node} to parse.
- """
- key = None
- value = None
- for child in node._get_childNodes():
- if child._get_localName() == ELEMENT_KEY:
- if child.firstChild is not None:
- key = child.firstChild.data.encode("utf-8")
- elif child._get_localName() == ELEMENT_VALUE:
- if child.firstChild is not None:
- value = child.firstChild.data.encode("utf-8")
-
- if (key is not None) and (value is not None):
- self.params[key] = value
-
- def parsePropertiesXML(self, node):
- """
- Parse the XML node for properties in the collection.
- @param node: the L{Node} to parse.
- """
- for child in node._get_childNodes():
- if child._get_localName() == ELEMENT_ACL:
- self.acl = ACL()
- self.acl.parseXML(child)
- elif child._get_localName() == ELEMENT_PROP:
- self.properties.append(Prop())
- self.properties[-1].parseXML(child)
-
- def build(self, docroot, mypath, urlroot, directory):
- """
- Create this collection, initialising any properties and then create any child
- collections.
- @param docroot: the file system path to create the collection in.
- @param urlroot: the URI path root to create the collection resource in.
- """
- myurl = urlroot
- if self.name is not None:
- mypath = os.path.join(mypath, self.name)
- myurl = joinURL(urlroot, self.name + "/")
-
- if not os.path.exists(mypath):
- os.mkdir(mypath)
-
- try:
- resource_class = namedObject(self.pytype)
- except:
- log.err("Unable to locate Python class %r" % (self.pytype,))
- raise
- kwargs = {}
- argnames = resource_class.__init__.func_code.co_varnames
- for name, value in (
- ("path" , mypath ),
- ("url" , myurl ),
- ("directory", directory),
- ):
- if name in argnames:
- kwargs[name] = value
- if self.params:
- kwargs["params"] = self.params
- try:
- self.resource = resource_class(**kwargs)
- except Exception:
- log.err("Unable to instantiate Python class %r with arguments %r" % (resource_class, kwargs))
- raise
-
- self.uri = myurl
-
- # Set properties now
- for prop in self.properties:
- self.resource.writeDeadProperty(prop.prop)
-
- # Set ACL now
- if self.acl is not None:
- self.resource.setAccessControlList(self.acl.acl)
-
- for member in self.members:
- child = member.build(docroot, mypath, myurl, directory)
- # Only putChild if one does not already exists
- if self.resource.putChildren.get(member.name, None) is None:
- self.resource.putChild(member.name, child)
-
- if IDAVPrincipalCollectionResource.providedBy(child):
- docroot.principalCollections.append(child)
-
- return self.resource
-
-class Prop (object):
- """
- Parses a property from XML.
- """
- def __init__(self):
- self.prop = None
-
- def parseXML(self, node):
- """
- Parse the XML node for a property.
- @param node: the L{Node} to parse.
- """
-
- self.prop = self.toWebDAVElement(node.firstChild)
-
- def toWebDAVElement(self, node):
- """
- Convert XML dom element to WebDAVElement.
- """
- ns = node.namespaceURI
- name = node._get_localName()
- children = []
- for child in node._get_childNodes():
- if isinstance(child, Element):
- children.append(self.toWebDAVElement(child))
- elif isinstance(child, Text):
- children.append(PCDATAElement(child.data))
-
- propClazz = lookupElement((ns, name,))
-
- return propClazz(*children)
-
-class ACL (object):
- """
- Parses a DAV:ACL from XML.
- """
- def __init__(self):
- self.acl = None
-
- def parseXML(self, node):
- """
- Parse the XML node for an ACL.
- @param node: the L{Node} to parse.
- """
- aces = []
- for child in node._get_childNodes():
- if child._get_localName() == ELEMENT_ACE:
- aces.append(self.parseACEXML(child))
- self.acl = davxml.ACL(*aces)
-
- def parseACEXML(self, node):
- """
- Parse the XML node for an ACE.
- @param node: the L{Node} to parse.
- """
- principal = None
- grant = None
- deny = None
- protected = None
- inheritable = False
- for child in node._get_childNodes():
- if child._get_localName() == ELEMENT_PRINCIPAL:
- principal = self.parsePrincipalXML(child)
- elif child._get_localName() == ELEMENT_GRANT:
- grant = self.parseGrantDenyXML(child)
- elif child._get_localName() == ELEMENT_DENY:
- deny = self.parseGrantDenyXML(child)
- elif child._get_localName() == ELEMENT_PROTECTED:
- protected = davxml.Protected()
- elif child._get_localName() == ELEMENT_INHERITABLE:
- inheritable = True
- items = []
- if principal is not None:
- items.append(principal)
- if grant is not None:
- items.append(grant)
- if deny is not None:
- items.append(deny)
- if protected is not None:
- items.append(protected)
- if inheritable:
- items.append(TwistedACLInheritable())
- return davxml.ACE(*items)
-
- def parsePrincipalXML(self, node):
- """
- Parse the XML node for a Principal.
- @param node: the L{Node} to parse.
- """
- item = None
- for child in node._get_childNodes():
- if child._get_localName() == ELEMENT_HREF:
- if child.firstChild is not None:
- item = davxml.HRef.fromString(child.firstChild.data)
- else:
- item = davxml.HRef.fromString("")
- elif child._get_localName() == ELEMENT_ALL:
- item = davxml.All()
- elif child._get_localName() == ELEMENT_AUTHENTICATED:
- item = davxml.Authenticated()
- elif child._get_localName() == ELEMENT_UNAUTHENTICATED:
- item = davxml.Unauthenticated()
- return davxml.Principal(item)
-
- def parseGrantDenyXML(self, node):
- """
- Parse the XML node for Grant/Deny items.
- @param node: the L{Node} to parse.
- """
- items = []
- for child in node._get_childNodes():
- if child._get_localName() == ELEMENT_PRIVILEGE:
- for privilege in child._get_childNodes():
- if privilege._get_localName() == ELEMENT_ALL:
- items.append(davxml.All())
- elif privilege._get_localName() == ELEMENT_READ:
- items.append(davxml.Read())
- if node._get_localName() == ELEMENT_GRANT:
- return davxml.Grant(davxml.Privilege(*items))
- else:
- return davxml.Deny(davxml.Privilege(*items))
-
- def parseInheritedXML(self, node):
- """
- Parse the XML node for inherited items.
- @param node: the L{Node} to parse.
- """
- item = None
- for child in node._get_childNodes():
- if child._get_localName() == ELEMENT_HREF:
- if child.firstChild is not None:
- item = davxml.HRef.fromString(child.firstChild.data)
- else:
- item = davxml.HRef.fromString("")
- return davxml.Inherited(item)
-
-class Authentication:
- """
- Parses authentication information for XML file.
- """
-
- class AuthType:
- """
- Base class for authentication method behaviors.
- """
-
- def __init__(self, type):
- self.type = type
- self.enabled = False
- self.onlyssl = False
- if type == "kerberos":
- self.credentials = ATTRIBUTE_VALUE_KERBEROS
- else:
- self.credentials = ATTRIBUTE_VALUE_DIRECTORY
- self.realm = ""
- self.service = ""
-
- def parseXML(self, node):
- if node.hasAttribute(ATTRIBUTE_ENABLE):
- self.enabled = node.getAttribute(ATTRIBUTE_ENABLE) == ATTRIBUTE_VALUE_YES
- if node.hasAttribute(ATTRIBUTE_ONLYSSL):
- self.onlyssl = node.getAttribute(ATTRIBUTE_ONLYSSL) == ATTRIBUTE_VALUE_YES
- for child in node._get_childNodes():
- if child._get_localName() == ELEMENT_REALM:
- if child.firstChild is not None:
- self.realm = child.firstChild.data.encode("utf-8")
- elif child._get_localName() == ELEMENT_SERVICE:
- if child.firstChild is not None:
- self.service = child.firstChild.data.encode("utf-8")
-
- def __init__(self):
- self.basic = Authentication.AuthType("basic")
- self.digest = Authentication.AuthType("digest")
- self.kerberos = Authentication.AuthType("kerberos")
-
- def getEnabledAuthenticator(self):
- if self.basic.enabled:
- return self.basic
- elif self.digest.enabled:
- return self.digest
- elif self.kerberos.enabled:
- return self.kerberos
- else:
- return None
-
- def parseXML(self, node):
- for child in node._get_childNodes():
- if child._get_localName() == ELEMENT_BASIC:
- self.basic.parseXML(child)
- elif child._get_localName() == ELEMENT_DIGEST:
- self.digest.parseXML(child)
- elif child._get_localName() == ELEMENT_KERBEROS:
- self.kerberos.parseXML(child)
-
- # Sanity checks
- ctr = 0
- if self.basic.enabled:
- ctr += 1
- if self.digest.enabled:
- ctr += 1
- if self.kerberos.enabled:
- ctr += 1
- if ctr == 0:
- log.msg("One authentication method must be enabled.")
- raise ValueError, "One authentication method must be enabled."
- elif ctr > 1:
- log.msg("Only one authentication method allowed.")
- raise ValueError, "Only one authentication method allowed."
-
- # FIXME: currently we have no way to turn off an auth mechanism based on whether SSL is in use or not,
- # so the onlyssl attribute is meaning less for now.
-# if self.basic.enabled and not self.basic.onlyssl:
-# log.msg("IMPORTANT: plain text passwords are allowed without an encrypted/secure connection.")
- if self.basic.enabled:
- log.msg("IMPORTANT: plain text passwords are allowed without an encrypted/secure connection.")
Modified: CalendarServer/branches/caldavd-twistd-plugin-2/twistedcaldav/tap.py
===================================================================
--- CalendarServer/branches/caldavd-twistd-plugin-2/twistedcaldav/tap.py 2006-12-08 00:03:35 UTC (rev 753)
+++ CalendarServer/branches/caldavd-twistd-plugin-2/twistedcaldav/tap.py 2006-12-08 00:16:02 UTC (rev 754)
@@ -32,6 +32,7 @@
from twisted.web2.dav import auth
from twisted.web2.dav import davxml
from twisted.web2.auth import basic
+from twisted.web2.auth import digest
from twisted.web2.channel import http
from twisted.web2.tap import Web2Service
@@ -59,7 +60,6 @@
config.parseConfig(self['config'])
-
class CaldavServiceMaker(object):
implements(IPlugin, service.IServiceMaker)
@@ -101,7 +101,7 @@
directory,
'/calendars/')
- root = rootResource(config.DocumentRoot,
+ root = self.rootResource(config.DocumentRoot,
principalCollections=(principalCollection,)
)
@@ -133,10 +133,11 @@
portal.registerChecker(directory)
+ realm = directory.realmName or ""
+
# TODO: figure out the list of supported schemes from the directory
- schemes = {'basic': basic.BasicCredentialFactory(directory.realmName
- or ""),
- #'digest': digest.DigestCredentialFactory
+ schemes = {'basic': basic.BasicCredentialFactory(realm),
+ 'digest': digest.DigestCredentialFactory("md5", realm),
}
for scheme in config.AuthSchemes:
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20061207/51042cd3/attachment.html
More information about the calendarserver-changes
mailing list