[CalendarServer-changes] [914] CalendarServer/branches/users/dreid/sudoers-2

source_changes at macosforge.org source_changes at macosforge.org
Thu Jan 4 08:39:23 PST 2007


Revision: 914
          http://trac.macosforge.org/projects/calendarserver/changeset/914
Author:   dreid at apple.com
Date:     2007-01-04 08:39:22 -0800 (Thu, 04 Jan 2007)

Log Message:
-----------
Merge forward to pick up fixes for launchd.plist and caldavd etc

Modified Paths:
--------------
    CalendarServer/branches/users/dreid/sudoers-2/conf/accounts.xml
    CalendarServer/branches/users/dreid/sudoers-2/conf/caldavd-test.plist
    CalendarServer/branches/users/dreid/sudoers-2/conf/caldavd.plist
    CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/config.py
    CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/directory/aggregate.py
    CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/directory/principal.py
    CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/directory/xmlaccountsparser.py
    CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/extensions.py
    CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/resource.py
    CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/tap.py

Added Paths:
-----------
    CalendarServer/branches/users/dreid/sudoers-2/conf/sudoers.plist
    CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/directory/sudo.py
    CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/directory/test/sudoers.plist
    CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/directory/test/test_sudo.py

Modified: CalendarServer/branches/users/dreid/sudoers-2/conf/accounts.xml
===================================================================
--- CalendarServer/branches/users/dreid/sudoers-2/conf/accounts.xml	2007-01-04 16:38:32 UTC (rev 913)
+++ CalendarServer/branches/users/dreid/sudoers-2/conf/accounts.xml	2007-01-04 16:39:22 UTC (rev 914)
@@ -25,12 +25,6 @@
     <name>Super User</name>
   </user>
   <user>
-    <uid>proxy</uid>
-    <password>proxy</password>
-    <name>User who can authorize as someone else</name>
-    <canproxy/> <!-- FIXME: Is the directory the right place to configure this bit? -->
-  </user>
-  <user>
     <uid>test</uid>
     <password>test</password>
     <name>Test User</name>

Modified: CalendarServer/branches/users/dreid/sudoers-2/conf/caldavd-test.plist
===================================================================
--- CalendarServer/branches/users/dreid/sudoers-2/conf/caldavd-test.plist	2007-01-04 16:38:32 UTC (rev 913)
+++ CalendarServer/branches/users/dreid/sudoers-2/conf/caldavd-test.plist	2007-01-04 16:39:22 UTC (rev 914)
@@ -183,5 +183,8 @@
   <array>
     <string>/principals/user/admin</string>
   </array>
+
+  <key>SudoersFile</key>
+  <string>conf/sudoers.plist</string>
 </dict>
 </plist>

Modified: CalendarServer/branches/users/dreid/sudoers-2/conf/caldavd.plist
===================================================================
--- CalendarServer/branches/users/dreid/sudoers-2/conf/caldavd.plist	2007-01-04 16:38:32 UTC (rev 913)
+++ CalendarServer/branches/users/dreid/sudoers-2/conf/caldavd.plist	2007-01-04 16:39:22 UTC (rev 914)
@@ -129,5 +129,8 @@
   <array>
     <string>/principals/user/admin</string>
   </array>
+
+  <key>SudoersFile</key>
+  <string>/etc/caldavd/sudoers.plist</string>
 </dict>
 </plist>

Copied: CalendarServer/branches/users/dreid/sudoers-2/conf/sudoers.plist (from rev 909, CalendarServer/branches/users/dreid/sudoers/conf/sudoers.plist)
===================================================================
--- CalendarServer/branches/users/dreid/sudoers-2/conf/sudoers.plist	                        (rev 0)
+++ CalendarServer/branches/users/dreid/sudoers-2/conf/sudoers.plist	2007-01-04 16:39:22 UTC (rev 914)
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+<key>users</key>
+<array>
+<!-- Sudo user definitions -->
+<!--
+  <dict>
+    <key>authorize-as</key>
+    <dict>
+      <key>allow</key>
+      <true/>
+      <key>principals</key>
+      <array>
+	<string>all</string>
+        <string>/principals/user/wsanchez</string>
+      </array>
+    </dict>
+    <key>authorize-from</key>
+    <array>
+      <string>127.0.0.1</string>
+    </array>
+
+    <key>username</key>
+    <string></string>
+
+    <key>password</key>
+    <string></string>
+  </dict>
+-->
+  <dict>
+    <key>username</key>
+    <string>superuser</string>
+    <key>password</key>
+    <string>superuser</string>
+  </dict>
+</array>
+</dict>
+</plist>

Modified: CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/config.py
===================================================================
--- CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/config.py	2007-01-04 16:38:32 UTC (rev 913)
+++ CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/config.py	2007-01-04 16:39:22 UTC (rev 914)
@@ -60,7 +60,8 @@
             'ServicePrincipal': '',
             },
         },
-    'AdminPrincipals': ['/principals/user/admin']
+    'AdminPrincipals': ['/principals/user/admin'],
+    'SudoersFile': '/etc/caldavd/sudoers.plist',
 }
 
 

Modified: CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/directory/aggregate.py
===================================================================
--- CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/directory/aggregate.py	2007-01-04 16:38:32 UTC (rev 913)
+++ CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/directory/aggregate.py	2007-01-04 16:39:22 UTC (rev 914)
@@ -103,6 +103,21 @@
         else:
             return None
 
+    userRecordTypes = ['user', 'sudoer']
+
+    def requestAvatarId(self, credentials):
+        for type in self.userRecordTypes:
+            user = self.recordWithShortName(
+                type,
+                credentials.credentials.username)
+
+            if user:
+                return self.serviceForRecordType(
+                    type).requestAvatarId(credentials)
+        
+        raise UnauthorizedLogin("No such user: %s" % (
+                credentials.credentials.username,))
+
 class DuplicateRecordTypeError(DirectoryError):
     """
     Duplicate record type.

Modified: CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/directory/principal.py	2007-01-04 16:38:32 UTC (rev 913)
+++ CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/directory/principal.py	2007-01-04 16:39:22 UTC (rev 914)
@@ -87,14 +87,17 @@
         for recordType in self.directory.recordTypes():
             self.putChild(recordType, DirectoryPrincipalTypeResource(self.fp.child(recordType).path, self, recordType))
 
+    def principalForShortName(self, type, name):
+        typeResource = self.getChild(type)
+        if typeResource is None:
+            return None
+        return typeResource.getChild(name)
+
     def principalForUser(self, user):
-        return self.getChild("user").getChild(user)
+        return self.principalForShortName('user', user)
 
     def principalForRecord(self, record):
-        typeResource = self.getChild(record.recordType)
-        if typeResource is None:
-            return None
-        return typeResource.getChild(record.shortName)
+        return self.principalForShortName(record.recordType, record.shortName)
 
     def _principalForURI(self, uri):
         if uri.startswith(self._url):

Copied: CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/directory/sudo.py (from rev 909, CalendarServer/branches/users/dreid/sudoers/twistedcaldav/directory/sudo.py)
===================================================================
--- CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/directory/sudo.py	                        (rev 0)
+++ CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/directory/sudo.py	2007-01-04 16:39:22 UTC (rev 914)
@@ -0,0 +1,141 @@
+##
+# 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: David reid, dreid at apple.com
+##
+
+"""
+Directory service implementation for users who are allowed to authorize
+as other principals.
+"""
+
+__all__ = [
+    "SudoDirectoryService",
+]
+
+from twisted.python.filepath import FilePath
+
+from twisted.cred.credentials import (IUsernamePassword, 
+                                      IUsernameHashedPassword)
+
+from twisted.cred.error import UnauthorizedLogin
+
+from twistedcaldav.py.plistlib import readPlist
+from twistedcaldav.directory.directory import (DirectoryService, 
+                                               DirectoryRecord,
+                                               UnknownRecordTypeError)
+
+class SudoDirectoryService(DirectoryService):
+    """
+    L{IDirectoryService} implementation for Sudo users.
+    """
+    baseGUID = "1EE00E46-1885-4DBC-A001-590AFA76A8E3"
+
+    realmName = None
+
+    plistFile = None
+
+    recordType = "sudoer"
+
+    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._accounts()
+
+    def _accounts(self):
+        fileInfo = (self.plistFile.getmtime(), self.plistFile.getsize())
+        if fileInfo != self._fileInfo:
+            self._plist = readPlist(self.plistFile.path)
+
+        return self._plist
+
+    def recordTypes(self):
+        return (self.recordType,)
+
+    def _recordForEntry(self, entry):
+        return SudoDirectoryRecord(
+            service=self,
+            recordType=self.recordType,
+            shortName=entry['username'],
+            entry=entry)
+
+
+    def listRecords(self, recordType):
+        if recordType != self.recordType:
+            raise UnknownRecordTypeError(recordType)
+
+        for entry in self._accounts()['users']:
+            yield self._recordForEntry(entry)
+
+    def recordWithShortName(self, recordType, shortName):
+        if recordType != self.recordType:
+            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.
+        sudouser = self.recordWithShortName("sudoer", 
+                                            credentials.credentials.username)
+        if sudouser is None:
+            raise UnauthorizedLogin("No such user: %s" % (sudouser,))
+        
+        if sudouser.verifyCredentials(credentials.credentials):
+            return (
+                credentials.authnPrincipal.principalURL(),
+                credentials.authzPrincipal.principalURL(),
+                )
+        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,
+            guid=None,
+            shortName=shortName,
+            fullName=shortName,
+            calendarUserAddresses=set())
+
+        self.password = entry['password']
+
+    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)

Copied: CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/directory/test/sudoers.plist (from rev 909, CalendarServer/branches/users/dreid/sudoers/twistedcaldav/directory/test/sudoers.plist)
===================================================================
--- CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/directory/test/sudoers.plist	                        (rev 0)
+++ CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/directory/test/sudoers.plist	2007-01-04 16:39:22 UTC (rev 914)
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//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>authorize-as</key>
+      <dict>
+	<key>allow</key>
+	<true/>
+	<key>principals</key>
+	<array>
+	  <string>all</string>
+	</array>
+      </dict>
+      <key>authorize-from</key>
+      <array>
+	<string>127.0.0.1</string>
+      </array>
+      <key>password</key>
+      <string>alice</string>
+      <key>username</key>
+      <string>alice</string>
+    </dict>
+  </array>
+</dict>
+</plist>

Copied: CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/directory/test/test_sudo.py (from rev 909, CalendarServer/branches/users/dreid/sudoers/twistedcaldav/directory/test/test_sudo.py)
===================================================================
--- CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/directory/test/test_sudo.py	                        (rev 0)
+++ CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/directory/test/test_sudo.py	2007-01-04 16:39:22 UTC (rev 914)
@@ -0,0 +1,66 @@
+##
+# 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: David Reid, dreid at apple.com
+##
+import os
+
+from twisted.python.filepath import FilePath
+
+import twistedcaldav.directory.test.util
+from twistedcaldav.directory.sudo import SudoDirectoryService
+from twistedcaldav.py.plistlib import writePlist
+
+plistFile = FilePath(os.path.join(os.path.dirname(__file__), "sudoers.plist"))
+
+class SudoTestCase(
+    twistedcaldav.directory.test.util.BasicTestCase,
+    twistedcaldav.directory.test.util.DigestTestCase
+):
+    """
+    Test the Sudo Directory Service
+    """
+
+    recordTypes = set(('sudoer',))
+    recordType = 'sudoer'
+
+    sudoers = {'alice': {'password': 'alice',},
+             }
+
+    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.shortName in self.sudoers)
+            self.assertEqual(self.sudoers[record.shortName]['password'],
+                             record.password)
+
+    def test_recordWithShortName(self):
+        service = self.service()
+
+        record = service.recordWithShortName('sudoer', 'alice')
+        self.assertEquals(record.password, 'alice')
+
+        record = service.recordWithShortName('sudoer', 'bob')
+        self.failIf(record)

Modified: CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/directory/xmlaccountsparser.py
===================================================================
--- CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/directory/xmlaccountsparser.py	2007-01-04 16:38:32 UTC (rev 913)
+++ CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/directory/xmlaccountsparser.py	2007-01-04 16:39:22 UTC (rev 914)
@@ -42,7 +42,7 @@
 ELEMENT_MEMBERS      = "members"
 ELEMENT_MEMBER       = "member"
 ELEMENT_CUADDR       = "cuaddr"
-ELEMENT_CANPROXY     = "canproxy"
+# ELEMENT_CANPROXY     = "canproxy"
 
 ATTRIBUTE_REALM      = "realm"
 ATTRIBUTE_REPEAT     = "repeat"
@@ -129,7 +129,7 @@
         self.members = set()
         self.groups = set()
         self.calendarUserAddresses = set()
-        self.canproxy = False
+#         self.canproxy = False
 
     def repeat(self, ctr):
         """
@@ -162,7 +162,7 @@
         result.name = name
         result.members = self.members
         result.calendarUserAddresses = calendarUserAddresses
-        result.canproxy = self.canproxy
+#         result.canproxy = self.canproxy
         return result
 
     def parseXML(self, node):
@@ -181,9 +181,9 @@
             elif child._get_localName() == ELEMENT_CUADDR:
                 if child.firstChild is not None:
                     self.calendarUserAddresses.add(child.firstChild.data.encode("utf-8"))
-            elif child._get_localName() == ELEMENT_CANPROXY:
-                CalDAVResource.proxyUsers.add(self.shortName)
-                self.canproxy = True
+#             elif child._get_localName() == ELEMENT_CANPROXY:
+#                 CalDAVResource.proxyUsers.add(self.shortName)
+#                 self.canproxy = True
 
     def _parseMembers(self, node):
         for child in node._get_childNodes():

Modified: CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/extensions.py
===================================================================
--- CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/extensions.py	2007-01-04 16:38:32 UTC (rev 913)
+++ CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/extensions.py	2007-01-04 16:39:22 UTC (rev 914)
@@ -46,6 +46,19 @@
     Extended L{twisted.web2.dav.resource.DAVResource} implementation.
     """
 
+    def findPrincipalForAuthID(self, authid):
+        """
+        Return an authentication and authorization principal identifiers for 
+        the authentication identifier passed in.  Check for sudo users before
+        regular users.
+        """
+        for collection in self.principalCollections():
+            principal = collection.principalForShortName('sudoer', authid)
+            if principal is not None:
+                return principal
+
+        return super(DAVFile, self).findPrincipalForAuthID(authid)
+
 class DAVFile (SuperDAVFile):
     """
     Extended L{twisted.web2.dav.static.DAVFile} implementation.
@@ -213,6 +226,21 @@
         response.headers.setHeader("content-type", MimeType("text", "html"))
         return response
 
+    def findPrincipalForAuthID(self, authid):
+        """
+        Return an authentication and authorization principal identifiers for 
+        the authentication identifier passed in.  Check for sudo users before
+        regular users.
+        """
+
+        for collection in self.principalCollections():
+            principal = collection.principalForShortName('sudoer', authid)
+            if principal is not None:
+                return principal
+
+        return super(DAVFile, self).findPrincipalForAuthID(authid)
+
+
 class ReadOnlyResourceMixIn (object):
     """
     Read only resource.

Modified: CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/resource.py
===================================================================
--- CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/resource.py	2007-01-04 16:38:32 UTC (rev 913)
+++ CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/resource.py	2007-01-04 16:39:22 UTC (rev 914)
@@ -74,10 +74,6 @@
     # resources to that size, or C{None} for no limit.
     sizeLimit = None
 
-    # Set containing user ids of all the users who have been given
-    # the right to authorize as someone else.
-    proxyUsers = set()
-
     ##
     # HTTP
     ##
@@ -258,10 +254,15 @@
             # Substitute the authz value for principal look up
             authz = authz[0]
 
-        # See if authenticated uid is a proxy user
-        if authid in CalDAVResource.proxyUsers:
+        def isSudoPrincipal(authid):
+            for collection in self.principalCollections():
+                if collection.principalForShortName('sudoer', authid):
+                    return True
+            return False
+
+        if isSudoPrincipal(authid):
             if authz:
-                if authz in CalDAVResource.proxyUsers:
+                if isSudoPrincipal(authz):
                     log.msg("Cannot proxy as another proxy: user '%s' as user '%s'" % (authid, authz))
                     raise HTTPError(responsecode.UNAUTHORIZED)
                 else:

Modified: CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/tap.py
===================================================================
--- CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/tap.py	2007-01-04 16:38:32 UTC (rev 913)
+++ CalendarServer/branches/users/dreid/sudoers-2/twistedcaldav/tap.py	2007-01-04 16:39:22 UTC (rev 914)
@@ -45,7 +45,11 @@
 from twistedcaldav.config import config, parseConfig, defaultConfig
 from twistedcaldav.logging import RotatingFileAccessLoggingObserver
 from twistedcaldav.root import RootResource
+from twistedcaldav.resource import CalDAVResource
 from twistedcaldav.directory.principal import DirectoryPrincipalProvisioningResource
+from twistedcaldav.directory.aggregate import AggregateDirectoryService
+from twistedcaldav.directory.sudo import SudoDirectoryService
+
 from twistedcaldav.static import CalendarHomeProvisioningFile
 
 try:
@@ -131,8 +135,19 @@
         # Setup the Directory
         #
         directoryClass = namedClass(config.DirectoryService['type'])
-        directory = directoryClass(**config.DirectoryService['params'])
+        baseDirectory = directoryClass(**config.DirectoryService['params'])
 
+        sudoDirectory = None
+
+        if config.SudoersFile:
+            sudoDirectory = SudoDirectoryService(config.SudoersFile)
+            sudoDirectory.realmName = baseDirectory.realmName
+
+            CalDAVResource.sudoDirectory = sudoDirectory
+        
+        directory = AggregateDirectoryService((baseDirectory,
+                                               sudoDirectory))
+
         #
         # Setup Resource hierarchy
         #
@@ -190,6 +205,12 @@
 
         portal.registerChecker(directory)
 
+        # FIXME: This is a hack, why doesn't aggregate directory service 
+        # do the right thing.
+
+#         if sudoDirectory:
+#             portal.registerChecker(sudoDirectory)
+
         realm = directory.realmName or ""
 
         for scheme, schemeConfig in config.Authentication.iteritems():

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20070104/4fe3c8fb/attachment.html


More information about the calendarserver-changes mailing list