[CalendarServer-changes] [8955] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Fri Mar 30 15:08:34 PDT 2012


Revision: 8955
          http://trac.macosforge.org/projects/calendarserver/changeset/8955
Author:   wsanchez at apple.com
Date:     2012-03-30 15:08:34 -0700 (Fri, 30 Mar 2012)
Log Message:
-----------
Remove sudoers functionality.

Modified Paths:
--------------
    CalendarServer/trunk/calendarserver/tap/util.py
    CalendarServer/trunk/twext/web2/dav/resource.py
    CalendarServer/trunk/twistedcaldav/directory/test/resources/caldavd.plist
    CalendarServer/trunk/twistedcaldav/extensions.py
    CalendarServer/trunk/twistedcaldav/stdconfig.py

Removed Paths:
-------------
    CalendarServer/trunk/calendarserver/tap/test/test_caldav.py
    CalendarServer/trunk/twistedcaldav/directory/sudo.py
    CalendarServer/trunk/twistedcaldav/directory/test/test_sudo.py

Deleted: CalendarServer/trunk/calendarserver/tap/test/test_caldav.py
===================================================================
--- CalendarServer/trunk/calendarserver/tap/test/test_caldav.py	2012-03-30 21:12:58 UTC (rev 8954)
+++ CalendarServer/trunk/calendarserver/tap/test/test_caldav.py	2012-03-30 22:08:34 UTC (rev 8955)
@@ -1,1230 +0,0 @@
-##
-# Copyright (c) 2007-2010 Apple 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.
-##
-
-import sys
-import os
-import stat
-import grp
-
-from os.path import dirname, abspath
-
-from zope.interface import implements
-
-from twisted.python.threadable import isInIOThread
-from twisted.internet.reactor import callFromThread
-from twisted.python.usage import Options, UsageError
-from twisted.python.reflect import namedAny
-from twisted.python import log
-
-from twisted.internet.interfaces import IProcessTransport, IReactorProcess
-from twisted.internet.protocol import ServerFactory
-from twisted.internet.defer import Deferred
-from twisted.internet.task import Clock
-
-from twisted.application.service import IService, IServiceCollection
-from twisted.application import internet
-
-from twext.web2.dav import auth
-from twext.web2.log import LogWrapperResource
-from twext.python.filepath import CachingFilePath as FilePath
-
-from twext.python.plistlib import writePlist #@UnresolvedImport
-from twext.internet.tcp import MaxAcceptTCPServer, MaxAcceptSSLServer
-
-from twistedcaldav.config import config, ConfigDict
-from twistedcaldav.stdconfig import DEFAULT_CONFIG
-
-from twistedcaldav.directory.aggregate import AggregateDirectoryService
-from twistedcaldav.directory.calendar import DirectoryCalendarHomeProvisioningResource
-from twistedcaldav.directory.directory import UnknownRecordTypeError
-from twistedcaldav.directory.principal import DirectoryPrincipalProvisioningResource
-from twistedcaldav.directory.sudo import SudoDirectoryService
-from twistedcaldav.test.util import TestCase
-
-from calendarserver.tap.caldav import (
-    CalDAVOptions, CalDAVServiceMaker, CalDAVService, GroupOwnedUNIXServer,
-    DelayedStartupProcessMonitor, DelayedStartupLineLogger, TwistdSlaveProcess
-)
-from calendarserver.provision.root import RootResource
-from StringIO import StringIO
-
-
-# Points to top of source tree.
-sourceRoot = dirname(dirname(dirname(dirname(abspath(__file__)))))
-
-
-class NotAProcessTransport(object):
-    """
-    Simple L{IProcessTransport} stub.
-    """
-    implements(IProcessTransport)
-
-    def __init__(self, processProtocol, executable, args, env, path,
-                 uid, gid, usePTY, childFDs):
-        """
-        Hold on to all the attributes passed to spawnProcess.
-        """
-        self.processProtocol = processProtocol
-        self.executable = executable
-        self.args = args
-        self.env = env
-        self.path = path
-        self.uid = uid
-        self.gid = gid
-        self.usePTY = usePTY
-        self.childFDs = childFDs
-
-
-class InMemoryProcessSpawner(Clock):
-    """
-    Stub out L{IReactorProcess} and L{IReactorClock} so that we can examine the
-    interaction of L{DelayedStartupProcessMonitor} and the reactor.
-    """
-    implements(IReactorProcess)
-
-    def __init__(self):
-        """
-        Create some storage to hold on to all the fake processes spawned.
-        """
-        super(InMemoryProcessSpawner, self).__init__()
-        self.processTransports = []
-        self.waiting = []
-
-
-    def waitForOneProcess(self, amount=10.0):
-        """
-        Wait for an L{IProcessTransport} to be created by advancing the clock.
-        If none are created in the specified amount of time, raise an
-        AssertionError.
-        """
-        self.advance(amount)
-        if self.processTransports:
-            return self.processTransports.pop(0)
-        else:
-            raise AssertionError(
-                "There were no process transports available.  Calls: " +
-                repr(self.calls)
-            )
-
-
-    def spawnProcess(self, processProtocol, executable, args=(), env={},
-                     path=None, uid=None, gid=None, usePTY=0,
-                     childFDs=None):
-
-        transport = NotAProcessTransport(
-            processProtocol, executable, args, env, path, uid, gid, usePTY,
-            childFDs
-        )
-        transport.startedAt = self.seconds()
-        self.processTransports.append(transport)
-        if self.waiting:
-            self.waiting.pop(0).callback(transport)
-        return transport
-
-
-
-class TestCalDAVOptions (CalDAVOptions):
-    """
-    A fake implementation of CalDAVOptions that provides
-    empty implementations of checkDirectory and checkFile.
-    """
-    def checkDirectory(self, *args, **kwargs):
-        pass
-
-    def checkFile(self, *args, **kwargs):
-        pass
-
-
-    def loadConfiguration(self):
-        """
-        Simple wrapper to avoid printing during test runs.
-        """
-        oldout = sys.stdout
-        newout = sys.stdout = StringIO()
-        try:
-            return CalDAVOptions.loadConfiguration(self)
-        finally:
-            sys.stdout = oldout
-            log.msg(
-                "load configuration console output: %s" % newout.getvalue()
-            )
-
-
-class CalDAVOptionsTest (TestCase):
-    """
-    Test various parameters of our usage.Options subclass
-    """
-    def setUp(self):
-        """
-        Set up our options object, giving it a parent, and forcing the
-        global config to be loaded from defaults.
-        """
-        TestCase.setUp(self)
-        self.config = TestCalDAVOptions()
-        self.config.parent = Options()
-        self.config.parent["uid"] = 0
-        self.config.parent["gid"] = 0
-        self.config.parent["nodaemon"] = False
-
-    def tearDown(self):
-        config.setDefaults(DEFAULT_CONFIG)
-        config.reload()
-
-    def test_overridesConfig(self):
-        """
-        Test that values on the command line's -o and --option options
-        overide the config file
-        """
-        myConfig = ConfigDict(DEFAULT_CONFIG)
-        myConfigFile = self.mktemp()
-        writePlist(myConfig, myConfigFile)
-
-        argv = [
-            "-f", myConfigFile,
-            "-o", "EnableSACLs",
-            "-o", "HTTPPort=80",
-            "-o", "BindAddresses=127.0.0.1,127.0.0.2,127.0.0.3",
-            "-o", "DocumentRoot=/dev/null",
-            "-o", "UserName=None",
-            "-o", "EnableProxyPrincipals=False",
-        ]
-
-        self.config.parseOptions(argv)
-
-        self.assertEquals(config.EnableSACLs, True)
-        self.assertEquals(config.HTTPPort, 80)
-        self.assertEquals(config.BindAddresses,
-                          ["127.0.0.1", "127.0.0.2", "127.0.0.3"])
-        self.assertEquals(config.DocumentRoot, "/dev/null")
-        self.assertEquals(config.UserName, None)
-        self.assertEquals(config.EnableProxyPrincipals, False)
-
-        argv = ["-o", "Authentication=This Doesn't Matter"]
-
-        self.assertRaises(UsageError, self.config.parseOptions, argv)
-
-    def test_setsParent(self):
-        """
-        Test that certain values are set on the parent (i.e. twistd's
-        Option's object)
-        """
-        myConfig = ConfigDict(DEFAULT_CONFIG)
-        myConfigFile = self.mktemp()
-        writePlist(myConfig, myConfigFile)
-
-        argv = [
-            "-f", myConfigFile,
-            "-o", "PIDFile=/dev/null",
-        ]
-
-        self.config.parseOptions(argv)
-
-        self.assertEquals(self.config.parent["pidfile"], "/dev/null")
-
-    def test_specifyConfigFile(self):
-        """
-        Test that specifying a config file from the command line
-        loads the global config with those values properly.
-        """
-        myConfig = ConfigDict(DEFAULT_CONFIG)
-
-        myConfig.Authentication.Basic.Enabled = False
-        myConfig.HTTPPort = 80
-        myConfig.ServerHostName = "calendar.calenderserver.org"
-
-        myConfigFile = self.mktemp()
-        writePlist(myConfig, myConfigFile)
-
-        args = ["-f", myConfigFile]
-
-        self.config.parseOptions(args)
-
-        self.assertEquals(config.ServerHostName, myConfig["ServerHostName"])
-        self.assertEquals(config.HTTPPort, myConfig.HTTPPort)
-        self.assertEquals(
-            config.Authentication.Basic.Enabled,
-            myConfig.Authentication.Basic.Enabled
-        )
-
-    def test_specifyDictPath(self):
-        """
-        Test that we can specify command line overrides to leafs using
-        a "/" seperated path.  Such as "-o MultiProcess/ProcessCount=1"
-        """
-        myConfig = ConfigDict(DEFAULT_CONFIG)
-        myConfigFile = self.mktemp()
-        writePlist(myConfig, myConfigFile)
-
-        argv = [
-            "-o", "MultiProcess/ProcessCount=102",
-            "-f", myConfigFile,
-        ]
-
-        self.config.parseOptions(argv)
-
-        self.assertEquals(config.MultiProcess["ProcessCount"], 102)
-
-class BaseServiceMakerTests(TestCase):
-    """
-    Utility class for ServiceMaker tests.
-    """
-    configOptions = None
-
-    def setUp(self):
-        TestCase.setUp(self)
-        self.options = TestCalDAVOptions()
-        self.options.parent = Options()
-        self.options.parent["gid"] = None
-        self.options.parent["uid"] = None
-        self.options.parent["nodaemon"] = None
-
-        self.config = ConfigDict(DEFAULT_CONFIG)
-
-        accountsFile = os.path.join(sourceRoot, "twistedcaldav/directory/test/accounts.xml")
-        resourcesFile = os.path.join(sourceRoot, "twistedcaldav/directory/test/resources.xml")
-        augmentsFile = os.path.join(sourceRoot, "twistedcaldav/directory/test/augments.xml")
-        pemFile = os.path.join(sourceRoot, "twistedcaldav/test/data/server.pem")
-
-        self.config["DirectoryService"] = {
-            "params": {"xmlFile": accountsFile},
-            "type": "twistedcaldav.directory.xmlfile.XMLDirectoryService"
-        }
-
-        self.config["ResourceService"] = {
-            "params": {"xmlFile": resourcesFile},
-        }
-
-        self.config["AugmentService"] = {
-            "params": {"xmlFiles": [augmentsFile]},
-            "type": "twistedcaldav.directory.augment.AugmentXMLDB"
-        }
-
-        self.config.UseDatabase    = False
-        self.config.ServerRoot     = self.mktemp()
-        self.config.ConfigRoot     = "config"
-        self.config.ProcessType    = "Single"
-        self.config.SSLPrivateKey  = pemFile
-        self.config.SSLCertificate = pemFile
-        self.config.EnableSSL      = True
-        self.config.Memcached.Pools.Default.ClientEnabled = False
-        self.config.Memcached.Pools.Default.ServerEnabled = False
-        self.config.DirectoryAddressBook.Enabled = False
-
-        self.config.SudoersFile = ""
-
-        if self.configOptions:
-            self.config.update(self.configOptions)
-
-        os.mkdir(self.config.ServerRoot)
-        os.mkdir(os.path.join(self.config.ServerRoot, self.config.DocumentRoot))
-        os.mkdir(os.path.join(self.config.ServerRoot, self.config.DataRoot))
-        os.mkdir(os.path.join(self.config.ServerRoot, self.config.ConfigRoot))
-
-        self.configFile = self.mktemp()
-
-        self.writeConfig()
-
-
-    def tearDown(self):
-        config.setDefaults(DEFAULT_CONFIG)
-        config.reset()
-
-
-    def writeConfig(self):
-        """
-        Flush self.config out to self.configFile
-        """
-        writePlist(self.config, self.configFile)
-
-
-    def makeService(self):
-        """
-        Create a service by calling into CalDAVServiceMaker with
-        self.configFile
-        """
-        self.options.parseOptions(["-f", self.configFile])
-
-        return CalDAVServiceMaker().makeService(self.options)
-
-
-    def getSite(self):
-        """
-        Get the server.Site from the service by finding the HTTPFactory.
-        """
-        service = self.makeService()
-        for listeningService in inServiceHierarchy(
-                service,
-                # FIXME: need a better predicate for 'is this really an HTTP
-                # factory' but this works for now.
-                # NOTE: in a database 'single' configuration, PostgresService
-                # will prevent the HTTP services from actually getting added to
-                # the hierarchy until the hierarchy has started.
-                lambda x: hasattr(x, 'args')
-            ):
-            return listeningService.args[1].protocolArgs['requestFactory']
-        raise RuntimeError("No site found.")
-
-
-
-def inServiceHierarchy(svc, predicate):
-    """
-    Find services in the service collection which satisfy the given predicate.
-    """
-    for subsvc in svc.services:
-        if IServiceCollection.providedBy(subsvc):
-            for value in inServiceHierarchy(subsvc, predicate):
-                yield value
-        if predicate(subsvc):
-            yield subsvc
-
-
-
-def determineAppropriateGroupID():
-    """
-    Determine a secondary group ID which can be used for testing.
-    """
-    return os.getgroups()[1]
-
-
-
-class SocketGroupOwnership(TestCase):
-    """
-    Tests for L{GroupOwnedUNIXServer}.
-    """
-
-    def test_groupOwnedUNIXSocket(self):
-        """
-        When a L{GroupOwnedUNIXServer} is started, it will change the group of
-        its socket.
-        """
-        alternateGroup = determineAppropriateGroupID()
-        socketName = self.mktemp()
-        gous = GroupOwnedUNIXServer(alternateGroup, socketName, ServerFactory(), mode=0660)
-        gous.privilegedStartService()
-        self.addCleanup(gous.stopService)
-        filestat = os.stat(socketName)
-        self.assertTrue(stat.S_ISSOCK(filestat.st_mode))
-        self.assertEquals(filestat.st_gid, alternateGroup)
-        self.assertEquals(filestat.st_uid, os.getuid())
-
-
-
-class CalDAVServiceMakerTests(BaseServiceMakerTests):
-    """
-    Test the service maker's behavior
-    """
-
-    def test_makeServiceDispatcher(self):
-        """
-        Test the default options of the dispatching makeService
-        """
-        validServices = ["Slave", "Combined"]
-
-        self.config["HTTPPort"] = 0
-
-        for service in validServices:
-            self.config["ProcessType"] = service
-            self.writeConfig()
-            self.makeService()
-
-        self.config["ProcessType"] = "Unknown Service"
-        self.writeConfig()
-        self.assertRaises(UsageError, self.makeService)
-
-
-    def test_modesOnUNIXSockets(self):
-        """
-        The logging and stats UNIX sockets that are bound as part of the
-        'Combined' service hierarchy should have a secure mode specified: only
-        the executing user should be able to open and send to them.
-        """
-
-        self.config["HTTPPort"] = 0 # Don't conflict with the test above.
-        alternateGroup = determineAppropriateGroupID()
-        self.config.GroupName = grp.getgrgid(alternateGroup).gr_name
-
-        self.config["ProcessType"] = "Combined"
-        self.writeConfig()
-        svc = self.makeService()
-        for serviceName in ["logging"]:
-            socketService = svc.getServiceNamed(serviceName)
-            self.assertIsInstance(socketService, GroupOwnedUNIXServer)
-            m = socketService.kwargs.get("mode", 0666)
-            self.assertEquals(
-                m, int("660", 8),
-                "Wrong mode on %s: %s" % (serviceName, oct(m))
-            )
-            self.assertEquals(socketService.gid, alternateGroup)
-        for serviceName in ["stats"]:
-            socketService = svc.getServiceNamed(serviceName)
-            self.assertIsInstance(socketService, GroupOwnedUNIXServer)
-            m = socketService.kwargs.get("mode", 0444)
-            self.assertEquals(
-                m, int("440", 8),
-                "Wrong mode on %s: %s" % (serviceName, oct(m))
-            )
-            self.assertEquals(socketService.gid, alternateGroup)
-
-
-    def test_processMonitor(self):
-        """
-        In the master, there should be exactly one
-        L{DelayedStartupProcessMonitor} in the service hierarchy so that it
-        will be started by startup.
-        """
-        self.config["ProcessType"] = "Combined"
-        self.writeConfig()
-        self.assertEquals(
-            1,
-            len(
-                list(inServiceHierarchy(
-                    self.makeService(),
-                    lambda x: isinstance(x, DelayedStartupProcessMonitor)))
-            )
-        )
-
-
-
-
-class SlaveServiceTest(BaseServiceMakerTests):
-    """
-    Test various configurations of the Slave service
-    """
-
-    configOptions = {
-        "HTTPPort": 8008,
-        "SSLPort": 8443,
-    }
-
-    def test_defaultService(self):
-        """
-        Test the value of a Slave service in it's simplest
-        configuration.
-        """
-        service = self.makeService()
-
-        self.failUnless(
-            IService(service),
-            "%s does not provide IService" % (service,)
-        )
-        self.failUnless(
-            service.services,
-            "No services configured"
-        )
-        self.failUnless(
-            isinstance(service, CalDAVService),
-            "%s is not a CalDAVService" % (service,)
-        )
-
-    def test_defaultListeners(self):
-        """
-        Test that the Slave service has sub services with the
-        default TCP and SSL configuration
-        """
-        service = self.makeService()
-
-        expectedSubServices = dict((
-            (MaxAcceptTCPServer, self.config["HTTPPort"]),
-            (MaxAcceptSSLServer, self.config["SSLPort"]),
-        ))
-
-        configuredSubServices = [(s.__class__, getattr(s, 'args', None))
-                                 for s in service.services]
-        checked = 0
-        for serviceClass, serviceArgs in configuredSubServices:
-            if serviceClass in expectedSubServices:
-                checked += 1
-                self.assertEquals(
-                    serviceArgs[0],
-                    dict(expectedSubServices)[serviceClass]
-                )
-        # TCP+SSL services for IPv4, TCP+SSL services for IPv6.
-        self.assertEquals(checked, 4)
-
-
-    def test_SSLKeyConfiguration(self):
-        """
-        Test that the configuration of the SSLServer reflect the config file's
-        SSL Private Key and SSL Certificate
-        """
-        service = self.makeService()
-
-        sslService = None
-        for s in service.services:
-            if isinstance(s, internet.SSLServer):
-                sslService = s
-                break
-
-        self.failIf(sslService is None, "No SSL Service found")
-
-        context = sslService.args[2]
-
-        self.assertEquals(
-            self.config["SSLPrivateKey"],
-            context.privateKeyFileName
-        )
-        self.assertEquals(
-            self.config["SSLCertificate"],
-            context.certificateFileName,
-        )
-
-    def test_noSSL(self):
-        """
-        Test the single service to make sure there is no SSL Service when SSL
-        is disabled
-        """
-        del self.config["SSLPort"]
-        self.writeConfig()
-
-        service = self.makeService()
-
-        self.assertNotIn(
-            internet.SSLServer,
-            [s.__class__ for s in service.services]
-        )
-
-    def test_noHTTP(self):
-        """
-        Test the single service to make sure there is no TCPServer when
-        HTTPPort is not configured
-        """
-        del self.config["HTTPPort"]
-        self.writeConfig()
-
-        service = self.makeService()
-
-        self.assertNotIn(
-            internet.TCPServer,
-            [s.__class__ for s in service.services]
-        )
-
-    def test_singleBindAddresses(self):
-        """
-        Test that the TCPServer and SSLServers are bound to the proper address
-        """
-        self.config.BindAddresses = ["127.0.0.1"]
-        self.writeConfig()
-
-        service = self.makeService()
-
-        for s in service.services:
-            if isinstance(s, (internet.TCPServer, internet.SSLServer)):
-                self.assertEquals(s.kwargs["interface"], "127.0.0.1")
-
-    def test_multipleBindAddresses(self):
-        """
-        Test that the TCPServer and SSLServers are bound to the proper
-        addresses.
-        """
-        self.config.BindAddresses = [
-            "127.0.0.1",
-            "10.0.0.2",
-            "172.53.13.123",
-        ]
-
-        self.writeConfig()
-        service = self.makeService()
-
-        tcpServers = []
-        sslServers = []
-
-        for s in service.services:
-            if isinstance(s, internet.TCPServer):
-                tcpServers.append(s)
-            elif isinstance(s, internet.SSLServer):
-                sslServers.append(s)
-
-        self.assertEquals(len(tcpServers), len(self.config.BindAddresses))
-        self.assertEquals(len(sslServers), len(self.config.BindAddresses))
-
-        for addr in self.config.BindAddresses:
-            for s in tcpServers:
-                if s.kwargs["interface"] == addr:
-                    tcpServers.remove(s)
-
-            for s in sslServers:
-                if s.kwargs["interface"] == addr:
-                    sslServers.remove(s)
-
-        self.assertEquals(len(tcpServers), 0)
-        self.assertEquals(len(sslServers), 0)
-
-    def test_listenBacklog(self):
-        """
-        Test that the backlog arguments is set in TCPServer and SSLServers
-        """
-        self.config.ListenBacklog = 1024
-        self.writeConfig()
-        service = self.makeService()
-
-        for s in service.services:
-            if isinstance(s, (internet.TCPServer, internet.SSLServer)):
-                self.assertEquals(s.kwargs["backlog"], 1024)
-
-
-class ServiceHTTPFactoryTests(BaseServiceMakerTests):
-    """
-    Test the configuration of the initial resource hierarchy of the
-    single service
-    """
-    configOptions = {"HTTPPort": 8008}
-
-    def test_AuthWrapperAllEnabled(self):
-        """
-        Test the configuration of the authentication wrapper
-        when all schemes are enabled.
-        """
-        self.config.Authentication.Digest.Enabled = True
-        self.config.Authentication.Kerberos.Enabled = True
-        self.config.Authentication.Kerberos.ServicePrincipal = "http/hello at bob"
-        self.config.Authentication.Basic.Enabled = True
-
-        self.writeConfig()
-        site = self.getSite()
-
-        self.failUnless(isinstance(
-                site.resource.resource,
-                auth.AuthenticationWrapper))
-
-        authWrapper = site.resource.resource
-
-        expectedSchemes = ["negotiate", "digest", "basic"]
-
-        for scheme in authWrapper.credentialFactories:
-            self.failUnless(scheme in expectedSchemes)
-
-        self.assertEquals(len(expectedSchemes),
-                          len(authWrapper.credentialFactories))
-
-    def test_servicePrincipalNone(self):
-        """
-        Test that the Kerberos principal look is attempted if the principal is empty.
-        """
-        self.config.Authentication.Kerberos.ServicePrincipal = ""
-        self.config.Authentication.Kerberos.Enabled = True
-        self.writeConfig()
-        site = self.getSite()
-
-        authWrapper = site.resource.resource
-
-        self.assertFalse(authWrapper.credentialFactories.has_key("negotiate"))
-
-    def test_servicePrincipal(self):
-        """
-        Test that the kerberos realm is the realm portion of a principal
-        in the form proto/host at realm
-        """
-        self.config.Authentication.Kerberos.ServicePrincipal = "http/hello at bob"
-        self.config.Authentication.Kerberos.Enabled = True
-        self.writeConfig()
-        site = self.getSite()
-
-        authWrapper = site.resource.resource
-        ncf = authWrapper.credentialFactories["negotiate"]
-
-        self.assertEquals(ncf.service, "http at HELLO")
-        self.assertEquals(ncf.realm, "bob")
-
-    def test_AuthWrapperPartialEnabled(self):
-        """
-        Test that the expected credential factories exist when
-        only a partial set of authentication schemes is
-        enabled.
-        """
-
-        self.config.Authentication.Basic.Enabled    = False
-        self.config.Authentication.Kerberos.Enabled = False
-
-        self.writeConfig()
-        site = self.getSite()
-
-        authWrapper = site.resource.resource
-
-        expectedSchemes = ["digest"]
-
-        for scheme in authWrapper.credentialFactories:
-            self.failUnless(scheme in expectedSchemes)
-
-        self.assertEquals(
-            len(expectedSchemes),
-            len(authWrapper.credentialFactories)
-        )
-
-    def test_LogWrapper(self):
-        """
-        Test the configuration of the log wrapper
-        """
-        site = self.getSite()
-
-        self.failUnless(isinstance(
-                site.resource,
-                LogWrapperResource))
-
-    def test_rootResource(self):
-        """
-        Test the root resource
-        """
-        site = self.getSite()
-        root = site.resource.resource.resource
-
-        self.failUnless(isinstance(root, RootResource))
-
-    def test_principalResource(self):
-        """
-        Test the principal resource
-        """
-        site = self.getSite()
-        root = site.resource.resource.resource
-
-        self.failUnless(isinstance(
-            root.getChild("principals"),
-            DirectoryPrincipalProvisioningResource
-        ))
-
-    def test_calendarResource(self):
-        """
-        Test the calendar resource
-        """
-        site = self.getSite()
-        root = site.resource.resource.resource
-
-        self.failUnless(isinstance(
-            root.getChild("calendars"),
-            DirectoryCalendarHomeProvisioningResource
-        ))
-
-
-sudoersFile = """<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-    <key>users</key>
-    <array>
-       	<dict>
-            <key>password</key>
-            <string>superuser</string>
-            <key>username</key>
-            <string>superuser</string>
-        </dict>
-    </array>
-</dict>
-</plist>
-"""
-
-class DirectoryServiceTest(BaseServiceMakerTests):
-    """
-    Tests of the directory service
-    """
-
-    configOptions = {"HTTPPort": 8008}
-
-    def test_sameDirectory(self):
-        """
-        Test that the principal hierarchy has a reference
-        to the same DirectoryService as the calendar hierarchy
-        """
-        site = self.getSite()
-        principals = site.resource.resource.resource.getChild("principals")
-        calendars = site.resource.resource.resource.getChild("calendars")
-
-        self.assertEquals(principals.directory, calendars.directory)
-
-    def test_aggregateDirectory(self):
-        """
-        Assert that the base directory service is actually
-        an AggregateDirectoryService
-        """
-        site = self.getSite()
-        principals = site.resource.resource.resource.getChild("principals")
-        directory = principals.directory
-
-        self.failUnless(isinstance(directory, AggregateDirectoryService))
-
-    def test_sudoDirectoryService(self):
-        """
-        Test that a sudo directory service is available if the
-        SudoersFile is set and exists
-        """
-        self.config.SudoersFile = "sudoers.plist"
-        sudoersFilePath = os.path.join(
-            self.config.ServerRoot,
-            self.config.ConfigRoot,
-            self.config.SudoersFile
-        )
-        self.writeConfig()
-
-        open(sudoersFilePath, "w").write(sudoersFile)
-
-        site = self.getSite()
-        principals = site.resource.resource.resource.getChild("principals")
-        directory = principals.directory
-
-        self.failUnless(sudoersFilePath)
-
-        sudoService = directory.serviceForRecordType(SudoDirectoryService.recordType_sudoers)
-
-        self.assertEquals(
-            sudoService.plistFile.path,
-            os.path.abspath(sudoersFilePath)
-        )
-        self.failUnless(
-            SudoDirectoryService.recordType_sudoers
-            in directory.userRecordTypes
-        )
-
-    def test_sudoDirectoryServiceNoFile(self):
-        """
-        Test that there is no SudoDirectoryService if
-        the SudoersFile does not exist.
-        """
-        self.config.SudoersFile = self.mktemp()
-
-        self.writeConfig()
-        site = self.getSite()
-        principals = site.resource.resource.resource.getChild("principals")
-        directory = principals.directory
-
-        self.failUnless(self.config.SudoersFile)
-
-        self.assertRaises(
-            UnknownRecordTypeError,
-            directory.serviceForRecordType,
-            SudoDirectoryService.recordType_sudoers
-        )
-
-    def test_sudoDirectoryServiceNotConfigured(self):
-        """
-        Test that there is no SudoDirectoryService if
-        the SudoersFile is not configured
-        """
-        site = self.getSite()
-        principals = site.resource.resource.resource.getChild("principals")
-        directory = principals.directory
-
-        self.failIf(self.config.SudoersFile)
-
-        self.assertRaises(
-            UnknownRecordTypeError,
-            directory.serviceForRecordType,
-            SudoDirectoryService.recordType_sudoers
-        )
-
-    def test_configuredDirectoryService(self):
-        """
-        Test that the real directory service is the directory service
-        set in the configuration file.
-        """
-        site = self.getSite()
-        principals = site.resource.resource.resource.getChild("principals")
-        directory = principals.directory
-
-        realDirectory = directory.serviceForRecordType("users")
-
-        configuredDirectory = namedAny(self.config.DirectoryService.type)
-
-        self.failUnless(isinstance(realDirectory, configuredDirectory))
-
-
-
-class DummyProcessObject(object):
-    """
-    Simple stub for Process Object API which just has an executable and some
-    arguments.
-
-    This is a stand in for L{TwistdSlaveProcess}.
-    """
-
-    def __init__(self, scriptname, *args):
-        self.scriptname = scriptname
-        self.args = args
-
-
-    def getCommandLine(self):
-        """
-        Simple command line.
-        """
-        return [self.scriptname] + list(self.args)
-
-
-    def getFileDescriptors(self):
-        """
-        Return a dummy, empty mapping of file descriptors.
-        """
-        return {}
-
-
-    def getName(self):
-        """
-        Get a dummy name.
-        """
-        return 'Dummy'
-
-
-class ScriptProcessObject(DummyProcessObject):
-    """
-    Simple stub for the Process Object API that will run a test script.
-    """
-
-    def getCommandLine(self):
-        """
-        Get the command line to invoke this script.
-        """
-        return [
-            sys.executable,
-            FilePath(__file__).sibling(self.scriptname).path
-        ] + list(self.args)
-
-
-
-
-
-class DelayedStartupProcessMonitorTests(TestCase):
-    """
-    Test cases for L{DelayedStartupProcessMonitor}.
-    """
-
-    def test_lineAfterLongLine(self):
-        """
-        A "long" line of output from a monitored process (longer than
-        L{LineReceiver.MAX_LENGTH}) should be logged in chunks rather than all
-        at once, to avoid resource exhaustion.
-        """
-        dspm = DelayedStartupProcessMonitor()
-        dspm.addProcessObject(ScriptProcessObject(
-                'longlines.py', str(DelayedStartupLineLogger.MAX_LENGTH)),
-                          os.environ)
-        dspm.startService()
-        self.addCleanup(dspm.stopService)
-
-        logged = []
-
-        def tempObserver(event):
-            # Probably won't be a problem, but let's not have any intermittent
-            # test issues that stem from multi-threaded log messages randomly
-            # going off...
-            if not isInIOThread():
-                callFromThread(tempObserver, event)
-                return
-            if event.get('isError'):
-                d.errback()
-            m = event.get('message')[0]
-            if m.startswith('[Dummy] '):
-                logged.append(event)
-                if m == '[Dummy] z':
-                    d.callback("done")
-
-        log.addObserver(tempObserver)
-        self.addCleanup(log.removeObserver, tempObserver)
-        d = Deferred()
-        def assertions(result):
-            self.assertEquals(["[Dummy] x",
-                               "[Dummy] y",
-                               "[Dummy] y", # final segment
-                               "[Dummy] z"],
-                              [''.join(evt['message'])[:len('[Dummy]') + 2]
-                               for evt in logged])
-            self.assertEquals([" (truncated, continued)",
-                               " (truncated, continued)",
-                               "[Dummy] y",
-                               "[Dummy] z"],
-                              [''.join(evt['message'])[-len(" (truncated, continued)"):]
-                               for evt in logged])
-        d.addCallback(assertions)
-        return d
-
-
-    def test_breakLineIntoSegments(self):
-        """
-        Exercise the line-breaking logic with various key lengths
-        """
-        testLogger = DelayedStartupLineLogger()
-        testLogger.MAX_LENGTH = 10
-        for input, output in [
-            ("", []),
-            ("a", ["a"]),
-            ("abcde", ["abcde"]),
-            ("abcdefghij", ["abcdefghij"]),
-            ("abcdefghijk",
-                ["abcdefghij (truncated, continued)",
-                 "k"
-                ]
-            ),
-            ("abcdefghijklmnopqrst",
-                ["abcdefghij (truncated, continued)",
-                 "klmnopqrst"
-                ]
-            ),
-            ("abcdefghijklmnopqrstuv",
-                ["abcdefghij (truncated, continued)",
-                 "klmnopqrst (truncated, continued)",
-                 "uv"]
-            ),
-        ]:
-            self.assertEquals(output, testLogger._breakLineIntoSegments(input))
-
-
-    def test_acceptDescriptorInheritance(self):
-        """
-        If a L{TwistdSlaveProcess} specifies some file descriptors to be
-        inherited, they should be inherited by the subprocess.
-        """
-        imps = InMemoryProcessSpawner()
-        dspm = DelayedStartupProcessMonitor(imps)
-
-        # Most arguments here will be ignored, so these are bogus values.
-        slave = TwistdSlaveProcess(
-            twistd        = "bleh",
-            tapname       = "caldav",
-            configFile    = "/does/not/exist",
-            id            = 10,
-            interfaces    = '127.0.0.1',
-            inheritFDs    = [3, 7],
-            inheritSSLFDs = [19, 25],
-        )
-
-        dspm.addProcessObject(slave, {})
-        dspm.startService()
-        # We can easily stub out spawnProcess, because caldav calls it, but a
-        # bunch of callLater calls are buried in procmon itself, so we need to
-        # use the real clock.
-        oneProcessTransport = imps.waitForOneProcess()
-        self.assertEquals(oneProcessTransport.childFDs,
-                          {0: 'w', 1: 'r', 2: 'r',
-                           3: 3, 7: 7,
-                           19: 19, 25: 25})
-
-
-    def test_changedArgumentEachSpawn(self):
-        """
-        If the result of C{getCommandLine} changes on subsequent calls,
-        subsequent calls should result in different arguments being passed to
-        C{spawnProcess} each time.
-        """
-        imps = InMemoryProcessSpawner()
-        dspm = DelayedStartupProcessMonitor(imps)
-        slave = DummyProcessObject('scriptname', 'first')
-        dspm.addProcessObject(slave, {})
-        dspm.startService()
-        oneProcessTransport = imps.waitForOneProcess()
-        self.assertEquals(oneProcessTransport.args,
-                          ['scriptname', 'first'])
-        slave.args = ['second']
-        oneProcessTransport.processProtocol.processEnded(None)
-        twoProcessTransport = imps.waitForOneProcess()
-        self.assertEquals(twoProcessTransport.args,
-                          ['scriptname', 'second'])
-
-
-    def test_metaDescriptorInheritance(self):
-        """
-        If a L{TwistdSlaveProcess} specifies a meta-file-descriptor to be
-        inherited, it should be inherited by the subprocess, and a
-        configuration argument should be passed that indicates to the
-        subprocess.
-        """
-        imps = InMemoryProcessSpawner()
-        dspm = DelayedStartupProcessMonitor(imps)
-        # Most arguments here will be ignored, so these are bogus values.
-        slave = TwistdSlaveProcess(
-            twistd     = "bleh",
-            tapname    = "caldav",
-            configFile = "/does/not/exist",
-            id         = 10,
-            interfaces = '127.0.0.1',
-            metaSocket = FakeDispatcher().addSocket()
-        )
-
-        dspm.addProcessObject(slave, {})
-        dspm.startService()
-        oneProcessTransport = imps.waitForOneProcess()
-        self.assertIn("MetaFD=4", oneProcessTransport.args)
-        self.assertEquals(
-            oneProcessTransport.args[oneProcessTransport.args.index("MetaFD=4")-1],
-            '-o',
-            "MetaFD argument was not passed as an option"
-        )
-        self.assertEquals(oneProcessTransport.childFDs,
-                          {0: 'w', 1: 'r', 2: 'r',
-                           4: 4})
-
-
-    def test_startServiceDelay(self):
-        """
-        Starting a L{DelayedStartupProcessMonitor} should result in the process
-        objects that have been added to it being started once per
-        delayInterval.
-        """
-        imps = InMemoryProcessSpawner()
-        dspm = DelayedStartupProcessMonitor(imps)
-        dspm.delayInterval = 3.0
-        sampleCounter = range(0, 5)
-        for counter in sampleCounter:
-            slave = TwistdSlaveProcess(
-                twistd     = "bleh",
-                tapname    = "caldav",
-                configFile = "/does/not/exist",
-                id         = counter * 10,
-                interfaces = '127.0.0.1',
-                metaSocket = FakeDispatcher().addSocket()
-            )
-            dspm.addProcessObject(slave, {"SAMPLE_ENV_COUNTER": str(counter)})
-        dspm.startService()
-
-        # Advance the clock a bunch of times, allowing us to time things with a
-        # comprehensible resolution.
-        imps.pump([0] + [dspm.delayInterval / 2.0] * len(sampleCounter) * 3)
-        expectedValues = [dspm.delayInterval * n for n in sampleCounter]
-        self.assertEquals([x.startedAt for x in imps.processTransports],
-                          expectedValues)
-
-
-
-class FakeFD(object):
-
-    def __init__(self, n):
-        self.fd = n
-
-    
-    def fileno(self):
-        return self.fd
-
-
-
-class FakeDispatcher(object):
-    n = 3
-
-    def addSocket(self):
-        self.n += 1
-        return FakeFD(self.n)
-
-
-
-class TwistdSlaveProcessTests(TestCase):
-    """
-    Tests for L{TwistdSlaveProcess}.
-    """
-    def test_pidfile(self):
-        """
-        The result of L{TwistdSlaveProcess.getCommandLine} includes an option
-        setting the name of the pidfile to something including the instance id.
-        """
-        slave = TwistdSlaveProcess("/path/to/twistd", "something", "config", 7, [])
-        commandLine = slave.getCommandLine()
-
-        option = 'PIDFile=something-instance-7.pid'
-        self.assertIn(option, commandLine)
-        self.assertEquals(commandLine[commandLine.index(option) - 1], '-o')
-

Modified: CalendarServer/trunk/calendarserver/tap/util.py
===================================================================
--- CalendarServer/trunk/calendarserver/tap/util.py	2012-03-30 21:12:58 UTC (rev 8954)
+++ CalendarServer/trunk/calendarserver/tap/util.py	2012-03-30 22:08:34 UTC (rev 8955)
@@ -53,7 +53,6 @@
 from twistedcaldav.directory.directory import GroupMembershipCache
 from twistedcaldav.directory.internal import InternalDirectoryService
 from twistedcaldav.directory.principal import DirectoryPrincipalProvisioningResource
-from twistedcaldav.directory.sudo import SudoDirectoryService
 from twistedcaldav.directory.wiki import WikiDirectoryService
 from twistedcaldav.notify import NotifierFactory, getPubSubConfiguration
 from calendarserver.push.applepush import APNSubscriptionResource
@@ -312,25 +311,6 @@
         directories.append(resourceDirectory)
 
     #
-    # Add sudoers directory
-    #
-    sudoDirectory = None
-
-    if config.SudoersFile and os.path.exists(config.SudoersFile):
-        log.info("Configuring SudoDirectoryService with file: %s"
-                      % (config.SudoersFile,))
-
-        sudoDirectory = SudoDirectoryService(config.SudoersFile)
-        sudoDirectory.realmName = baseDirectory.realmName
-
-        CalDAVResource.sudoDirectory = sudoDirectory
-        directories.insert(0, sudoDirectory)
-    else:
-        log.info( "Not using SudoDirectoryService; file doesn't exist: %s"
-            % (config.SudoersFile,)
-        )
-
-    #
     # Add wiki directory service
     #
     if config.Authentication.Wiki.Enabled:
@@ -348,10 +328,6 @@
 
     directory = AggregateDirectoryService(directories, groupMembershipCache)
 
-    if sudoDirectory:
-        directory.userRecordTypes.insert(0,
-            SudoDirectoryService.recordType_sudoers)
-
     #
     # Use system-wide realm on OSX
     #

Modified: CalendarServer/trunk/twext/web2/dav/resource.py
===================================================================
--- CalendarServer/trunk/twext/web2/dav/resource.py	2012-03-30 21:12:58 UTC (rev 8954)
+++ CalendarServer/trunk/twext/web2/dav/resource.py	2012-03-30 22:08:34 UTC (rev 8955)
@@ -948,51 +948,62 @@
             if the authentication scheme is unsupported, or the
             credentials provided by the request are not valid.
         """
-        if not (hasattr(request, 'portal') and
-                hasattr(request, 'credentialFactories') and
-                hasattr(request, 'loginInterfaces')):
+        # 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
+        ):
+            return succeed((request.authnUser, request.authzUser))
+
+        if not (
+            hasattr(request, "portal") and
+            hasattr(request, "credentialFactories") and
+            hasattr(request, "loginInterfaces")
+        ):
             request.authnUser = element.Principal(element.Unauthenticated())
             request.authzUser = element.Principal(element.Unauthenticated())
             return succeed((request.authnUser, request.authzUser))
 
-        authHeader = request.headers.getHeader('authorization')
+        authHeader = request.headers.getHeader("authorization")
 
         if authHeader is not None:
             if authHeader[0] not in request.credentialFactories:
-                log.err("Client authentication scheme %s is not "
-                        "provided by server %s"
-                        % (authHeader[0], request.credentialFactories.keys()))
+                log.err(
+                    "Client authentication scheme %s is not provided by server %s"
+                    % (authHeader[0], request.credentialFactories.keys())
+                )
                 d = UnauthorizedResponse.makeResponse(
                     request.credentialFactories,
                     request.remoteAddr
                 )
-                def _fail(response):
-                    return Failure(HTTPError(response))
-                return d.addCallback(_fail)
+                return d.addCallback(lambda response: Failure(HTTPError(response)))
             else:
                 factory = request.credentialFactories[authHeader[0]]
 
                 def gotCreds(creds):
-                    return self.principalsForAuthID(
-                        request, creds.username
-                        ).addCallback(gotDetails, creds)
+                    d = self.principalsForAuthID(request, creds.username)
+                    d.addCallback(gotDetails, creds)
+                    return d
 
                 # Try to match principals in each principal collection
                 # on the resource
                 def gotDetails(details, creds):
                     if details == (None, None):
-                        log.msg("Could not find the principal resource for user id: %s" % (creds.username,))
-                        raise HTTPError(responsecode.UNAUTHORIZED)
+                        log.msg(
+                            "Could not find the principal resource for user id: %s"
+                            % (creds.username,)
+                        )
+                        return Failure(HTTPError(responsecode.UNAUTHORIZED))
 
                     authnPrincipal = IDAVPrincipalResource(details[0])
                     authzPrincipal = IDAVPrincipalResource(details[1])
-                    return PrincipalCredentials(
-                        authnPrincipal, authzPrincipal, creds
-                    )
+                    return PrincipalCredentials(authnPrincipal, authzPrincipal, creds)
 
                 def login(pcreds):
-                    return request.portal.login(
-                        pcreds, None, *request.loginInterfaces)
+                    return request.portal.login(pcreds, None, *request.loginInterfaces)
+
                 def gotAuth(result):
                     request.authnUser = result[1]
                     request.authzUser = result[2]
@@ -1004,9 +1015,7 @@
                     d = UnauthorizedResponse.makeResponse(
                         request.credentialFactories, request.remoteAddr
                     )
-                    d.addCallback(
-                        lambda response: Failure(HTTPError(response))
-                    )
+                    d.addCallback(lambda response: Failure(HTTPError(response)))
                     return d
 
                 d = factory.decode(authHeader[1], request)

Deleted: CalendarServer/trunk/twistedcaldav/directory/sudo.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/sudo.py	2012-03-30 21:12:58 UTC (rev 8954)
+++ CalendarServer/trunk/twistedcaldav/directory/sudo.py	2012-03-30 22:08:34 UTC (rev 8955)
@@ -1,144 +0,0 @@
-##
-# Copyright (c) 2006-2012 Apple 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.
-##
-
-"""
-Directory service implementation for users who are allowed to authorize
-as other principals.
-"""
-
-__all__ = [
-    "SudoDirectoryService",
-]
-
-from twext.python.filepath import CachingFilePath as FilePath
-from twisted.cred.credentials import IUsernamePassword, IUsernameHashedPassword
-from twisted.cred.error import UnauthorizedLogin
-
-from twext.python.plistlib import readPlist
-
-from twistedcaldav.directory.directory import DirectoryService, DirectoryRecord
-from twistedcaldav.directory.directory import UnknownRecordTypeError
-
-class SudoDirectoryService(DirectoryService):
-    """
-    L{IDirectoryService} implementation for Sudo users.
-    """
-    baseGUID = "1EE00E46-1885-4DBC-A001-590AFA76A8E3"
-
-    realmName = None
-
-    plistFile = None
-
-    recordType_sudoers = "sudoers"
-
-    def __repr__(self):
-        return "<%s %r: %r>" % (self.__class__.__name__, self.realmName,
-                                self.plistFile)
-
-    def __init__(self, plistFile):
-        super(SudoDirectoryService, self).__init__()
-
-        if isinstance(plistFile, (unicode, str)):
-            plistFile = FilePath(plistFile)
-
-        self.plistFile = plistFile
-        self._fileInfo = None
-        self._plist = None
-        self._accounts()
-
-    def _accounts(self):
-        if self._plist is None:
-            self.plistFile.restat()
-            fileInfo = (self.plistFile.getmtime(), self.plistFile.getsize())
-            if fileInfo != self._fileInfo:
-                self._plist = readPlist(self.plistFile.path)
-                self._fileInfo = fileInfo
-
-        return self._plist
-
-    def recordTypes(self):
-        return (SudoDirectoryService.recordType_sudoers,)
-
-    def _recordForEntry(self, entry):
-        return SudoDirectoryRecord(
-            service=self,
-            recordType=SudoDirectoryService.recordType_sudoers,
-            shortName=entry['username'],
-            entry=entry)
-
-
-    def listRecords(self, recordType):
-        if recordType != SudoDirectoryService.recordType_sudoers:
-            raise UnknownRecordTypeError(recordType)
-
-        for entry in self._accounts()['users']:
-            yield self._recordForEntry(entry)
-
-    def recordWithShortName(self, recordType, shortName):
-        if recordType != SudoDirectoryService.recordType_sudoers:
-            raise UnknownRecordTypeError(recordType)
-
-        for entry in self._accounts()['users']:
-            if entry['username'] == shortName:
-                return self._recordForEntry(entry)
-
-    def requestAvatarId(self, credentials):
-        # FIXME: ?
-        # We were checking if principal is enabled; seems unnecessary in current
-        # implementation because you shouldn't have a principal object for a
-        # disabled directory principal.
-
-        if credentials.authnPrincipal is None or not hasattr(credentials.authnPrincipal, "record"):
-            raise UnauthorizedLogin("No such user: %s" % (credentials.credentials.username,))
-        sudouser = credentials.authnPrincipal.record
-
-        if credentials.authnPrincipal.record.verifyCredentials(credentials.credentials):
-            return (
-                credentials.authnPrincipal.principalURL(),
-                credentials.authzPrincipal.principalURL(),
-                credentials.authnPrincipal,
-                credentials.authzPrincipal,
-                )
-        else:
-            raise UnauthorizedLogin(
-                "Incorrect credentials for %s" % (sudouser,))
-
-
-class SudoDirectoryRecord(DirectoryRecord):
-    """
-    L{DirectoryRecord} implementation for Sudo users.
-    """
-
-    def __init__(self, service, recordType, shortName, entry):
-        super(SudoDirectoryRecord, self).__init__(
-            service=service,
-            recordType=recordType,
-            uid="%s:%s" % (recordType, shortName),
-            shortNames=(shortName,),
-            fullName=shortName,
-        )
-
-        self.password = entry['password']
-
-        self.enabled = True     # Explicitly enabled
-
-    def verifyCredentials(self, credentials):
-        if IUsernamePassword.providedBy(credentials):
-            return credentials.checkPassword(self.password)
-        elif IUsernameHashedPassword.providedBy(credentials):
-            return credentials.checkPassword(self.password)
-
-        return super(SudoDirectoryRecord, self).verifyCredentials(credentials)

Modified: CalendarServer/trunk/twistedcaldav/directory/test/resources/caldavd.plist
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/test/resources/caldavd.plist	2012-03-30 21:12:58 UTC (rev 8954)
+++ CalendarServer/trunk/twistedcaldav/directory/test/resources/caldavd.plist	2012-03-30 22:08:34 UTC (rev 8955)
@@ -284,10 +284,6 @@
       <!-- <string>/principals/__uids__/983C8238-FB6B-4D92-9242-89C0A39E5F81/</string> -->
     </array>
 
-    <!-- Principals that can pose as other principals -->
-    <key>SudoersFile</key>
-    <string>conf/sudoers.plist</string>
-
     <!-- Create "proxy access" principals -->
     <key>EnableProxyPrincipals</key>
     <true/>

Deleted: CalendarServer/trunk/twistedcaldav/directory/test/test_sudo.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/test/test_sudo.py	2012-03-30 21:12:58 UTC (rev 8954)
+++ CalendarServer/trunk/twistedcaldav/directory/test/test_sudo.py	2012-03-30 22:08:34 UTC (rev 8955)
@@ -1,75 +0,0 @@
-##
-# Copyright (c) 2005-2009 Apple 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.
-##
-import os
-
-from twext.python.filepath import CachingFilePath as FilePath
-
-import twistedcaldav.directory.test.util
-from twistedcaldav.directory.sudo import SudoDirectoryService
-
-plistFile = FilePath(os.path.join(os.path.dirname(__file__), "sudoers.plist"))
-plistFile2 = FilePath(os.path.join(os.path.dirname(__file__), "sudoers2.plist"))
-
-class SudoTestCase(
-    twistedcaldav.directory.test.util.BasicTestCase,
-    twistedcaldav.directory.test.util.DigestTestCase
-):
-    """
-    Test the Sudo Directory Service
-    """
-
-    recordTypes = set(('sudoers',))
-    recordType = 'sudoers'
-
-    sudoers = {
-        'alice': {'password': 'alice',},
-    }
-
-    locations = {}
-
-    def plistFile(self):
-        if not hasattr(self, "_plistFile"):
-            self._plistFile = FilePath(self.mktemp())
-            plistFile.copyTo(self._plistFile)
-        return self._plistFile
-
-    def service(self):
-        service = SudoDirectoryService(self.plistFile())
-        service.realmName = "test realm"
-        return service
-
-    def test_listRecords(self):
-        for record in self.service().listRecords(self.recordType):
-            self.failUnless(record.shortNames[0] in self.sudoers)
-            self.assertEqual(self.sudoers[record.shortNames[0]]['password'],
-                             record.password)
-
-    def test_recordWithShortName(self):
-        service = self.service()
-
-        record = service.recordWithShortName(self.recordType, 'alice')
-        self.assertEquals(record.password, 'alice')
-
-        record = service.recordWithShortName(self.recordType, 'bob')
-        self.failIf(record)
-
-    def test_calendaringDisabled(self):
-        service = self.service()
-
-        record = service.recordWithShortName(self.recordType, 'alice')
-
-        self.failIf(record.enabledForCalendaring,
-                    "sudoers should have enabledForCalendaring=False")

Modified: CalendarServer/trunk/twistedcaldav/extensions.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/extensions.py	2012-03-30 21:12:58 UTC (rev 8954)
+++ CalendarServer/trunk/twistedcaldav/extensions.py	2012-03-30 22:08:34 UTC (rev 8955)
@@ -65,7 +65,6 @@
 from twistedcaldav import customxml
 from twistedcaldav.customxml import calendarserver_namespace
 
-from twistedcaldav.directory.sudo import SudoDirectoryService
 from twistedcaldav.directory.directory import DirectoryService
 from twistedcaldav.method.report import http_REPORT
 
@@ -77,208 +76,6 @@
 log = Logger()
 
 
-class SudoersMixin (object):
-    """
-    Mixin class to let DAVResource, and DAVFile subclasses know about
-    sudoer principals and how to find their AuthID.
-    """
-
-    @inlineCallbacks
-    def authenticate(self, request):
-        # 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
-        ):
-            returnValue((request.authnUser, request.authzUser))
-
-        # Copy of SuperDAVResource.authenticate except we pass the
-        # creds on as well as we will need to take different actions
-        # based on what the auth method was
-        if not (
-            hasattr(request, "portal") and 
-            hasattr(request, "credentialFactories") and
-            hasattr(request, "loginInterfaces")
-        ):
-            request.authnUser = element.Principal(element.Unauthenticated())
-            request.authzUser = element.Principal(element.Unauthenticated())
-            returnValue((request.authnUser, request.authzUser,))
-
-        authHeader = request.headers.getHeader("authorization")
-
-        if authHeader is not None:
-            if authHeader[0] not in request.credentialFactories:
-                log.error("Client authentication scheme %s is not provided by server %s"
-                               % (authHeader[0], request.credentialFactories.keys()))
-
-                response = (yield UnauthorizedResponse.makeResponse(
-                    request.credentialFactories,
-                    request.remoteAddr
-                ))
-                raise HTTPError(response)
-            else:
-                factory = request.credentialFactories[authHeader[0]]
-
-                try:
-                    creds = (yield factory.decode(authHeader[1], request))
-                except (UnauthorizedLogin, LoginFailed,):
-                    raise HTTPError((yield UnauthorizedResponse.makeResponse(
-                                request.credentialFactories, request.remoteAddr)))
-
-                # Try to match principals in each principal collection on the resource
-                authnPrincipal, authzPrincipal = (yield self.principalsForAuthID(request, creds))
-                if (authnPrincipal, authzPrincipal) == (None, None):
-                    log.info("Could not find the principal resource for user id: %s" % (creds.username,))
-                    raise HTTPError(responsecode.UNAUTHORIZED)
-                    
-                authnPrincipal = IDAVPrincipalResource(authnPrincipal)
-                authzPrincipal = IDAVPrincipalResource(authzPrincipal)
-
-                pcreds = PrincipalCredentials(authnPrincipal, authzPrincipal, creds)
-
-                try:
-                    result = (yield request.portal.login(pcreds, None, *request.loginInterfaces))
-                except UnauthorizedLogin:
-                    raise HTTPError((yield UnauthorizedResponse.makeResponse(
-                                request.credentialFactories, request.remoteAddr)))
-                request.authnUser = result[1]
-                request.authzUser = result[2]
-                returnValue((request.authnUser, request.authzUser,))
-        else:
-            if (
-                hasattr(request, "checkedWiki") and
-                hasattr(request, "authnUser") and
-                hasattr(request, "authzUser")
-            ):
-                # This request has already been authenticated via the wiki
-                returnValue((request.authnUser, request.authzUser))
-
-            request.authnUser = element.Principal(element.Unauthenticated())
-            request.authzUser = element.Principal(element.Unauthenticated())
-            returnValue((request.authnUser, request.authzUser,))
-
-    def principalsForAuthID(self, request, creds):
-        """
-        Return authentication and authorization prinicipal identifiers
-        for the authentication identifer passed in. In this
-        implementation authn and authz principals are the same.
-
-        @param request: the L{IRequest} for the request in progress.
-        @param creds: L{Credentials} or the principal to lookup.
-        @return: a deferred tuple of two tuples. Each tuple is
-            C{(principal, principalURI)} where: C{principal} is the
-            L{Principal} that is found; {principalURI} is the C{str}
-            URI of the principal.  The first tuple corresponds to
-            authentication identifiers, the second to authorization
-            identifiers.  It will errback with an
-            HTTPError(responsecode.FORBIDDEN) if the principal isn't
-            found.
-        """
-        authnPrincipal = self.findPrincipalForAuthID(creds)
-
-        if authnPrincipal is None:
-            return succeed((None, None))
-
-        d = self.authorizationPrincipal(request, creds.username, authnPrincipal)
-        d.addCallback(lambda authzPrincipal: (authnPrincipal, authzPrincipal))
-        return d
-
-    def findPrincipalForAuthID(self, creds):
-        """
-        Return an authentication and authorization principal
-        identifiers for the authentication identifier passed in.
-        Check for sudo users before regular users.
-        """
-        if type(creds) is str:
-            return super(SudoersMixin, self).findPrincipalForAuthID(creds)
-
-        for collection in self.principalCollections():
-            principal = collection.principalForShortName(
-                SudoDirectoryService.recordType_sudoers, 
-                creds.username)
-            if principal is not None:
-                return principal
-
-        for collection in self.principalCollections():
-            principal = collection.principalForAuthID(creds)
-            if principal is not None:
-                return principal
-        return None
-
-    @inlineCallbacks
-    def authorizationPrincipal(self, request, authID, authnPrincipal):
-        """
-        Determine the authorization principal for the given request
-        and authentication principal.  This implementation looks for
-        an X-Authorize-As header value to use as the authorization
-        principal.
-        
-        @param request: the L{IRequest} for the request in progress.
-        @param authID: a string containing the
-            authentication/authorization identifier for the principal
-            to lookup.
-        @param authnPrincipal: the L{IDAVPrincipal} for the
-            authenticated principal
-        @return: a deferred result C{tuple} of (L{IDAVPrincipal},
-            C{str}) containing the authorization principal resource
-            and URI respectively.
-        """
-        # Look for X-Authorize-As Header
-        authz = request.headers.getRawHeaders("x-authorize-as")
-
-        if authz is not None and (len(authz) == 1):
-            # Substitute the authz value for principal look up
-            authz = authz[0]
-
-        def getPrincipalForType(type, name):
-            for collection in self.principalCollections():
-                principal = collection.principalForShortName(type, name)
-                if principal:
-                    return principal
-
-        def isSudoUser(authzID):
-            if getPrincipalForType(SudoDirectoryService.recordType_sudoers, authzID):
-                return True
-            return False
-
-        if (
-            hasattr(authnPrincipal, "record") and
-            authnPrincipal.record.recordType == SudoDirectoryService.recordType_sudoers
-        ):
-            if authz:
-                if isSudoUser(authz):
-                    log.info("Cannot proxy as another proxy: user %r as user %r"
-                             % (authID, authz))
-                    raise HTTPError(responsecode.FORBIDDEN)
-                else:
-                    authzPrincipal = getPrincipalForType(DirectoryService.recordType_users, authz)
-
-                    if not authzPrincipal:
-                        authzPrincipal = self.findPrincipalForAuthID(authz)
-
-                    if authzPrincipal is not None:
-                        log.info("Allow proxy: user %r as %r"
-                                 % (authID, authz,))
-                        returnValue(authzPrincipal)
-                    else:
-                        log.info("Could not find authorization user id: %r"
-                                 % (authz,))
-                        raise HTTPError(responsecode.FORBIDDEN)
-            else:
-                log.info("Cannot authenticate proxy user %r without X-Authorize-As header"
-                         % (authID,))
-                raise HTTPError(responsecode.BAD_REQUEST)
-        elif authz:
-            log.info("Cannot proxy: user %r as %r" % (authID, authz,))
-            raise HTTPError(responsecode.FORBIDDEN)
-        else:
-            # No proxy - do default behavior
-            result = (yield super(SudoersMixin, self).authorizationPrincipal(request, authID, authnPrincipal))
-            returnValue(result)
-
-
 class DirectoryPrincipalPropertySearchMixIn(object):
 
     @inlineCallbacks
@@ -673,7 +470,7 @@
     return wrapper
 
 class DAVResource (DirectoryPrincipalPropertySearchMixIn,
-                   SudoersMixin, SuperDAVResource, LoggingMixIn,
+                   SuperDAVResource, LoggingMixIn,
                    DirectoryRenderingMixIn, StaticRenderMixin):
     """
     Extended L{twext.web2.dav.resource.DAVResource} implementation.
@@ -888,8 +685,7 @@
 
 
 
-class DAVFile (SudoersMixin, SuperDAVFile, LoggingMixIn,
-               DirectoryRenderingMixIn):
+class DAVFile (SuperDAVFile, LoggingMixIn, DirectoryRenderingMixIn):
     """
     Extended L{twext.web2.dav.static.DAVFile} implementation.
     """

Modified: CalendarServer/trunk/twistedcaldav/stdconfig.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/stdconfig.py	2012-03-30 21:12:58 UTC (rev 8954)
+++ CalendarServer/trunk/twistedcaldav/stdconfig.py	2012-03-30 22:08:34 UTC (rev 8955)
@@ -384,7 +384,6 @@
     #
     "AdminPrincipals": [],                       # Principals with "DAV:all" access (relative URLs)
     "ReadPrincipals": [],                        # Principals with "DAV:read" access (relative URLs)
-    "SudoersFile": "sudoers.plist",              # Principals that can pose as other principals
     "EnableProxyPrincipals": True,               # Create "proxy access" principals
 
     #
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120330/291e6870/attachment-0001.html>


More information about the calendarserver-changes mailing list