def test_autodiscover_cache(self, m): # Mock the default endpoint that we test in step 1 of autodiscovery m.post(self.dummy_ad_endpoint, status_code=200, content=self.dummy_ad_response) # Also mock the EWS URL. We try to guess its auth method as part of autodiscovery m.post(self.dummy_ews_endpoint, status_code=200) discovery = Autodiscovery( email=self.account.primary_smtp_address, credentials=self.account.protocol.credentials, retry_policy=self.retry_policy, ) # Not cached self.assertNotIn(discovery._cache_key, autodiscover_cache) discovery.discover() # Now it's cached self.assertIn(discovery._cache_key, autodiscover_cache) # Make sure the cache can be looked by value, not by id(). This is important for multi-threading/processing self.assertIn( (self.account.primary_smtp_address.split('@')[1], Credentials(self.account.protocol.credentials.username, self.account.protocol.credentials.password), True), autodiscover_cache) # Poison the cache with a failing autodiscover endpoint. discover() must handle this and rebuild the cache autodiscover_cache[discovery._cache_key] = AutodiscoverProtocol( config=Configuration( service_endpoint= 'https://example.com/Autodiscover/Autodiscover.xml', credentials=Credentials(get_random_string(8), get_random_string(8)), auth_type=NTLM, retry_policy=FailFast(), )) m.post('https://example.com/Autodiscover/Autodiscover.xml', status_code=404) discovery.discover() self.assertIn(discovery._cache_key, autodiscover_cache) # Make sure that the cache is actually used on the second call to discover() _orig = discovery._step_1 def _mock(slf, *args, **kwargs): raise NotImplementedError() discovery._step_1 = MethodType(_mock, discovery) discovery.discover() # Fake that another thread added the cache entry into the persistent storage but we don't have it in our # in-memory cache. The cache should work anyway. autodiscover_cache._protocols.clear() discovery.discover() discovery._step_1 = _orig # Make sure we can delete cache entries even though we don't have it in our in-memory cache autodiscover_cache._protocols.clear() del autodiscover_cache[discovery._cache_key] # This should also work if the cache does not contain the entry anymore del autodiscover_cache[discovery._cache_key]
def get_test_protocol(**kwargs): return AutodiscoverProtocol( config=Configuration( service_endpoint=kwargs.get("service_endpoint", "https://example.com/Autodiscover/Autodiscover.xml"), credentials=kwargs.get("credentials", Credentials(get_random_string(8), get_random_string(8))), auth_type=kwargs.get("auth_type", NTLM), retry_policy=kwargs.get("retry_policy", FailFast()), ) )
def test_autodiscover_direct_gc(self, m): # Test garbage collection of the autodiscover cache c = Credentials('leet_user', 'cannaguess') autodiscover_cache[('example.com', c)] = AutodiscoverProtocol( config=Configuration( service_endpoint= 'https://example.com/Autodiscover/Autodiscover.xml', credentials=c, auth_type=NTLM, retry_policy=FailFast(), )) self.assertEqual(len(autodiscover_cache), 1) autodiscover_cache.__del__()
def test_close_autodiscover_connections(self, m): # A live test that we can close TCP connections c = Credentials('leet_user', 'cannaguess') autodiscover_cache[('example.com', c)] = AutodiscoverProtocol( config=Configuration( service_endpoint= 'https://example.com/Autodiscover/Autodiscover.xml', credentials=c, auth_type=NTLM, retry_policy=FailFast(), )) self.assertEqual(len(autodiscover_cache), 1) close_connections()
def test_autodiscover_cache(self, m): # Empty the cache from exchangelib.autodiscover import _autodiscover_cache _autodiscover_cache.clear() cache_key = (self.account.domain, self.account.protocol.credentials) # Not cached self.assertNotIn(cache_key, _autodiscover_cache) discover(email=self.account.primary_smtp_address, credentials=self.account.protocol.credentials) # Now it's cached self.assertIn(cache_key, _autodiscover_cache) # Make sure the cache can be looked by value, not by id(). This is important for multi-threading/processing self.assertIn( (self.account.primary_smtp_address.split('@')[1], Credentials(self.account.protocol.credentials.username, self.account.protocol.credentials.password), True), _autodiscover_cache) # Poison the cache. discover() must survive and rebuild the cache _autodiscover_cache[cache_key] = AutodiscoverProtocol( config=Configuration( service_endpoint='https://example.com/blackhole.asmx', credentials=Credentials('leet_user', 'cannaguess'), auth_type=NTLM, retry_policy=FailFast(), )) m.post('https://example.com/blackhole.asmx', status_code=404) discover(email=self.account.primary_smtp_address, credentials=self.account.protocol.credentials) self.assertIn(cache_key, _autodiscover_cache) # Make sure that the cache is actually used on the second call to discover() _orig = exchangelib.autodiscover._try_autodiscover def _mock(*args, **kwargs): raise NotImplementedError() exchangelib.autodiscover._try_autodiscover = _mock discover(email=self.account.primary_smtp_address, credentials=self.account.protocol.credentials) # Fake that another thread added the cache entry into the persistent storage but we don't have it in our # in-memory cache. The cache should work anyway. _autodiscover_cache._protocols.clear() discover(email=self.account.primary_smtp_address, credentials=self.account.protocol.credentials) exchangelib.autodiscover._try_autodiscover = _orig # Make sure we can delete cache entries even though we don't have it in our in-memory cache _autodiscover_cache._protocols.clear() del _autodiscover_cache[cache_key] # This should also work if the cache does not contain the entry anymore del _autodiscover_cache[cache_key]
def test_magic(self, m): # Just test we don't fail when calling repr() and str(). Insert a dummy cache entry for testing c = Credentials('leet_user', 'cannaguess') autodiscover_cache[('example.com', c)] = AutodiscoverProtocol( config=Configuration( service_endpoint= 'https://example.com/Autodiscover/Autodiscover.xml', credentials=c, auth_type=NTLM, retry_policy=FailFast(), )) self.assertEqual(len(autodiscover_cache), 1) str(autodiscover_cache) repr(autodiscover_cache) for protocol in autodiscover_cache._protocols.values(): str(protocol) repr(protocol)
def test_autodiscover_failure(self): # A live test that errors can be raised. Here, we try to aútodiscover a non-existing email address if not self.settings.get('autodiscover_server'): self.skipTest( "Skipping %s - no 'autodiscover_server' entry in settings.yml" % self.__class__.__name__) # Autodiscovery may take a long time. Prime the cache with the autodiscover server from the config file ad_endpoint = 'https://%s/Autodiscover/Autodiscover.xml' % self.settings[ 'autodiscover_server'] cache_key = (self.domain, self.account.protocol.credentials) autodiscover_cache[cache_key] = AutodiscoverProtocol( config=Configuration( service_endpoint=ad_endpoint, credentials=self.account.protocol.credentials, auth_type=NTLM, retry_policy=self.retry_policy, )) with self.assertRaises(ErrorNonExistentMailbox): exchangelib.autodiscover.discovery.discover( email='XXX.' + self.account.primary_smtp_address, credentials=self.account.protocol.credentials, retry_policy=self.retry_policy, )