[CalendarServer-changes] [4653] CalendarServer/branches/users/wsanchez/deployment
source_changes at macosforge.org
source_changes at macosforge.org
Wed Oct 28 12:08:06 PDT 2009
Revision: 4653
http://trac.macosforge.org/projects/calendarserver/changeset/4653
Author: sagen at apple.com
Date: 2009-10-28 12:08:05 -0700 (Wed, 28 Oct 2009)
Log Message:
-----------
Adding a Basic auth caching mechanism to cut down on the traffic to OD
Modified Paths:
--------------
CalendarServer/branches/users/wsanchez/deployment/memcacheclient.py
CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/appleopendirectory.py
CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/test/test_digest.py
CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/test/test_opendirectoryrecords.py
CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/test/test_memcacher.py
CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/test/test_resource.py
CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/test/test_root.py
CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/test/test_static.py
CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/test/test_tap.py
Modified: CalendarServer/branches/users/wsanchez/deployment/memcacheclient.py
===================================================================
--- CalendarServer/branches/users/wsanchez/deployment/memcacheclient.py 2009-10-28 19:00:37 UTC (rev 4652)
+++ CalendarServer/branches/users/wsanchez/deployment/memcacheclient.py 2009-10-28 19:08:05 UTC (rev 4653)
@@ -1274,6 +1274,9 @@
Is not a string (Raises MemcachedKeyError)
Is None (Raises MemcachedKeyError)
"""
+
+ return # Short circuit this expensive method
+
if type(key) == types.TupleType: key = key[1]
if not key:
raise Client.MemcachedKeyNoneError, ("Key is None")
Modified: CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/appleopendirectory.py
===================================================================
--- CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/appleopendirectory.py 2009-10-28 19:00:37 UTC (rev 4652)
+++ CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/appleopendirectory.py 2009-10-28 19:08:05 UTC (rev 4653)
@@ -33,7 +33,14 @@
import opendirectory
import dsattributes
import dsquery
+import memcacheclient
+try:
+ from hashlib import md5
+except ImportError:
+ from md5 import new as md5
+
+
from twisted.internet.reactor import callLater
from twisted.internet.threads import deferToThread
from twisted.cred.credentials import UsernamePassword
@@ -174,6 +181,14 @@
h = (h + hash(getattr(self, attr))) & sys.maxint
return h
+ def _getMemcacheClient(self, refresh=False):
+ if refresh or not hasattr(self, "memcacheClient"):
+ self.memcacheClient = memcacheclient.ClientFactory.getClient(['%s:%s' %
+ (config.Memcached.BindAddress, config.Memcached.Port)],
+ debug=0, pickleProtocol=2)
+ return self.memcacheClient
+
+
def _lookupVHostRecord(self):
"""
Get the OD service record for this host.
@@ -1087,20 +1102,36 @@
result.update(self.service.readOnlyProxiesForGUID(DirectoryService.recordType_locations, self.guid))
return result
+
+ def getMemcacheKey(self, shortName):
+ key = "auth-%s" % (md5(shortName).hexdigest(),)
+ return key
+
def verifyCredentials(self, credentials):
if isinstance(credentials, UsernamePassword):
- # Check cached password
+ # Check cached password which is an md5 hexdigest
+
+ credPassword = md5(credentials.password).hexdigest()
try:
- if credentials.password == self.password:
+ if credPassword == self.password:
return True
except AttributeError:
- pass
+ # No locally stored password; check memcached
+ key = self.getMemcacheKey(self.shortName)
+ memcachePassword = self.service._getMemcacheClient().get(key)
+ if memcachePassword is not None:
+ if credPassword == memcachePassword:
+ # Memcached version matches, store locally
+ self.password = credPassword
+ return True
- # Check with directory services
+ # No local version, *or* local version differs; check directory services
try:
if opendirectory.authenticateUserBasic(self.service.directory, self.nodeName, self.shortName, credentials.password):
# Cache the password to avoid future DS queries
- self.password = credentials.password
+ self.password = credPassword
+ key = self.getMemcacheKey(self.shortName)
+ self.service._getMemcacheClient().set(key, self.password, time=self.service.cacheTimeout*60)
return True
except opendirectory.ODError, e:
self.log_error("Open Directory (node=%s) error while performing basic authentication for user %s: %s"
Modified: CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/test/test_digest.py
===================================================================
--- CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/test/test_digest.py 2009-10-28 19:00:37 UTC (rev 4652)
+++ CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/test/test_digest.py 2009-10-28 19:08:05 UTC (rev 4653)
@@ -2,7 +2,7 @@
from twisted.cred import error
from twisted.internet import address
-from twisted.trial import unittest
+from twistedcaldav.test.util import TestCase
from twisted.web2.auth import digest
from twisted.web2.auth.wrapper import UnauthorizedResponse
from twisted.web2.test.test_server import SimpleRequest
@@ -71,7 +71,7 @@
emtpyAttributeAuthRequest = 'realm="",nonce="doesn\'t matter"'
-class DigestAuthTestCase(unittest.TestCase):
+class DigestAuthTestCase(TestCase):
"""
Test the behavior of DigestCredentialFactory
"""
@@ -80,6 +80,7 @@
"""
Create a DigestCredentialFactory for testing
"""
+ super(DigestAuthTestCase, self).setUp()
self.path1 = self.mktemp()
self.path2 = self.mktemp()
os.mkdir(self.path1)
Modified: CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/test/test_opendirectoryrecords.py
===================================================================
--- CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/test/test_opendirectoryrecords.py 2009-10-28 19:00:37 UTC (rev 4652)
+++ CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/test/test_opendirectoryrecords.py 2009-10-28 19:08:05 UTC (rev 4653)
@@ -14,8 +14,12 @@
# limitations under the License.
##
-import twisted.trial.unittest
+from twistedcaldav.test.util import TestCase
+from twisted.cred.credentials import UsernamePassword
+import opendirectory
+
+
try:
from twistedcaldav.directory.appleopendirectory import OpenDirectoryService as RealOpenDirectoryService
import dsattributes
@@ -42,7 +46,7 @@
return tuple(records)
- class ReloadCache(twisted.trial.unittest.TestCase):
+ class ReloadCache(TestCase):
def setUp(self):
super(ReloadCache, self).setUp()
self._service = OpenDirectoryService(node="/Search", dosetup=False)
@@ -449,6 +453,71 @@
user3 = self._service.recordWithCalendarUserAddress("mailto:user03 at example.com")
self.assertTrue(user3 is not None)
+
+ class AuthCacheTests(TestCase):
+
+ def _authenticateUserBasic(self, ignore, node, name, password):
+ self._odAccessed = True
+ return self._passwords.get(name, "") == password
+
+ def setUp(self):
+ super(AuthCacheTests, self).setUp()
+ self._service = OpenDirectoryService(node="/Search", dosetup=False)
+ self._service.servicetags.add("FE588D50-0514-4DF9-BCB5-8ECA5F3DA274:030572AE-ABEC-4E0F-83C9-FCA304769E5F:calendar")
+ self._passwords = { }
+
+ # Monkeypatch the real opendirectory.authenticateUserBasic
+ self._prev = opendirectory.authenticateUserBasic
+ opendirectory.authenticateUserBasic = self._authenticateUserBasic
+
+ def tearDown(self):
+ for call in self._service._delayedCalls:
+ call.cancel()
+ opendirectory.authenticateUserBasic = self._prev
+
+ def test_caching(self):
+
+ self._service.fakerecords = {
+ DirectoryService.recordType_users: [
+ fakeODRecord("User 01"),
+ ],
+ }
+ self._service.reloadCache(DirectoryService.recordType_users)
+
+ user1 = self._service.recordWithCalendarUserAddress("mailto:user01 at example.com")
+ self._passwords["user01"] = "user01"
+ cred = UsernamePassword("user01", "user01")
+
+ # Verify we go to OD when password is neither local nor in memcache
+ self._odAccessed = False
+ self.assertTrue(user1.verifyCredentials(cred))
+ self.assertTrue(self._odAccessed)
+
+ # Verify we don't go to OD when password is local
+ self._odAccessed = False
+ self.assertTrue(user1.verifyCredentials(cred))
+ self.assertFalse(self._odAccessed)
+
+ # Verify we don't go to OD when password not local but *is* in
+ # memcache
+ del user1.password
+ self._odAccessed = False
+ self.assertTrue(user1.verifyCredentials(cred))
+ self.assertFalse(self._odAccessed)
+
+ # Verify a password change will send us to OD
+ self._passwords["user01"] = "new user01"
+ cred = UsernamePassword("user01", "new user01")
+ self._odAccessed = False
+ self.assertTrue(user1.verifyCredentials(cred))
+ self.assertTrue(self._odAccessed)
+
+ # Verify the new password was memcached correctly
+ del user1.password
+ self._odAccessed = False
+ self.assertTrue(user1.verifyCredentials(cred))
+ self.assertFalse(self._odAccessed)
+
def fakeODRecord(fullName, shortName=None, guid=None, email=None, addLocator=True, members=None):
if shortName is None:
shortName = shortNameForFullName(fullName)
Modified: CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/test/test_memcacher.py
===================================================================
--- CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/test/test_memcacher.py 2009-10-28 19:00:37 UTC (rev 4652)
+++ CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/test/test_memcacher.py 2009-10-28 19:08:05 UTC (rev 4653)
@@ -6,7 +6,7 @@
"""
from twisted.internet.defer import inlineCallbacks
-from twisted.trial.unittest import TestCase
+from twistedcaldav.test.util import TestCase
from twistedcaldav.config import config
from twistedcaldav.memcacher import Memcacher
Modified: CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/test/test_resource.py
===================================================================
--- CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/test/test_resource.py 2009-10-28 19:00:37 UTC (rev 4652)
+++ CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/test/test_resource.py 2009-10-28 19:08:05 UTC (rev 4653)
@@ -14,7 +14,7 @@
# limitations under the License.
##
-from twisted.trial.unittest import TestCase
+from twistedcaldav.test.util import TestCase
from twistedcaldav.resource import CalDAVResource
@@ -28,6 +28,7 @@
class CalDAVResourceTests(TestCase):
def setUp(self):
+ super(CalDAVResourceTests, self).setUp()
self.resource = CalDAVResource()
self.resource._dead_properties = InMemoryPropertyStore()
Modified: CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/test/test_root.py
===================================================================
--- CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/test/test_root.py 2009-10-28 19:00:37 UTC (rev 4652)
+++ CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/test/test_root.py 2009-10-28 19:08:05 UTC (rev 4653)
@@ -52,6 +52,7 @@
class RootTests(TestCase):
def setUp(self):
+ super(RootTests, self).setUp()
self.docroot = self.mktemp()
os.mkdir(self.docroot)
Modified: CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/test/test_static.py
===================================================================
--- CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/test/test_static.py 2009-10-28 19:00:37 UTC (rev 4652)
+++ CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/test/test_static.py 2009-10-28 19:08:05 UTC (rev 4653)
@@ -14,7 +14,7 @@
# limitations under the License.
##
-from twisted.trial.unittest import TestCase
+from twistedcaldav.test.util import TestCase
from twistedcaldav.static import CalendarHomeFile, CalDAVFile
from twistedcaldav.cache import DisabledCacheNotifier
@@ -27,6 +27,7 @@
class CalendarHomeFileTests(TestCase):
def setUp(self):
+ super(CalendarHomeFileTests, self).setUp()
self.calendarHome = CalendarHomeFile(self.mktemp(),
StubParentResource(),
object())
@@ -44,6 +45,7 @@
class CalDAVFileTests(TestCase):
def setUp(self):
+ super(CalDAVFileTests, self).setUp()
self.caldavFile = CalDAVFile(self.mktemp())
self.caldavFile.fp.createDirectory()
self.caldavFile.cacheNotifier = StubCacheChangeNotifier()
Modified: CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/test/test_tap.py
===================================================================
--- CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/test/test_tap.py 2009-10-28 19:00:37 UTC (rev 4652)
+++ CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/test/test_tap.py 2009-10-28 19:08:05 UTC (rev 4653)
@@ -18,6 +18,7 @@
from copy import deepcopy
from twisted.trial import unittest
+from twistedcaldav.test.util import TestCase
from twisted.python.usage import Options, UsageError
from twisted.python.util import sibpath
@@ -53,7 +54,7 @@
pass
-class CalDAVOptionsTest(unittest.TestCase):
+class CalDAVOptionsTest(TestCase):
"""
Test various parameters of our usage.Options subclass
"""
@@ -63,6 +64,7 @@
Set up our options object, giving it a parent, and forcing the
global config to be loaded from defaults.
"""
+ super(CalDAVOptionsTest, self).setUp()
self.config = TestCalDAVOptions()
self.config.parent = Options()
self.config.parent['uid'] = 0
@@ -163,7 +165,7 @@
self.assertEquals(config.MultiProcess['ProcessCount'], 102)
-class BaseServiceMakerTests(unittest.TestCase):
+class BaseServiceMakerTests(TestCase):
"""
Utility class for ServiceMaker tests.
"""
@@ -171,6 +173,7 @@
configOptions = None
def setUp(self):
+ super(BaseServiceMakerTests, self).setUp()
self.options = TestCalDAVOptions()
self.options.parent = Options()
self.options.parent['gid'] = None
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20091028/97d80343/attachment-0001.html>
More information about the calendarserver-changes
mailing list