def checkSACL(self, request): """ Check SACLs against the current request """ topLevel = request.path.strip("/").split("/")[0] saclServices = self.saclMap.get(topLevel, None) if not saclServices: returnValue(True) try: authnUser, authzUser = yield self.authenticate(request) except Exception: response = (yield UnauthorizedResponse.makeResponse( request.credentialFactories, request.remoteAddr)) raise HTTPError(response) # SACLs are enabled in the plist, but there may not actually # be a SACL group assigned to this service. Let's see if # unauthenticated users are allowed by calling CheckSACL # with an empty string. if authzUser is None: for saclService in saclServices: if checkSACL("", saclService): # No group actually exists for this SACL, so allow # unauthenticated access returnValue(True) # There is a SACL group for at least one of the SACLs, so no # unauthenticated access response = (yield UnauthorizedResponse.makeResponse( request.credentialFactories, request.remoteAddr)) log.info("Unauthenticated user denied by SACLs") raise HTTPError(response) # Cache the authentication details request.authnUser = authnUser request.authzUser = authzUser # Figure out the "username" from the davxml.Principal object username = authzUser.record.shortNames[0] access = False for saclService in saclServices: if checkSACL(username, saclService): # Access is allowed access = True break # Mark SACLs as having been checked so we can avoid doing it # multiple times request.checkedSACL = True if access: returnValue(True) log.warn("User {user!r} is not enabled with the {sacl!r} SACL(s)", user=username, sacl=saclServices) raise HTTPError(responsecode.FORBIDDEN)
def checkSACL(self, request): """ Check SACLs against the current request """ topLevel = request.path.strip("/").split("/")[0] saclServices = self.saclMap.get(topLevel, None) if not saclServices: returnValue(True) try: authnUser, authzUser = yield self.authenticate(request) except Exception: response = (yield UnauthorizedResponse.makeResponse(request.credentialFactories, request.remoteAddr)) raise HTTPError(response) # SACLs are enabled in the plist, but there may not actually # be a SACL group assigned to this service. Let's see if # unauthenticated users are allowed by calling CheckSACL # with an empty string. if authzUser is None: for saclService in saclServices: if checkSACL("", saclService): # No group actually exists for this SACL, so allow # unauthenticated access returnValue(True) # There is a SACL group for at least one of the SACLs, so no # unauthenticated access response = (yield UnauthorizedResponse.makeResponse(request.credentialFactories, request.remoteAddr)) log.info("Unauthenticated user denied by SACLs") raise HTTPError(response) # Cache the authentication details request.authnUser = authnUser request.authzUser = authzUser # Figure out the "username" from the davxml.Principal object username = authzUser.record.shortNames[0] access = False for saclService in saclServices: if checkSACL(username, saclService): # Access is allowed access = True break # Mark SACLs as having been checked so we can avoid doing it # multiple times request.checkedSACL = True if access: returnValue(True) log.warn("User {user!r} is not enabled with the {sacl!r} SACL(s)", user=username, sacl=saclServices) raise HTTPError(responsecode.FORBIDDEN)
def test_invalidNonce(self): """ Test that login fails when the given nonce from the response, does not match the nonce encoded in the opaque. """ credentialFactories = (FakeDigestCredentialFactory( 'md5', 'auth', 'test realm', self.namespace1), FakeDigestCredentialFactory( 'md5', '', 'test realm', self.namespace2)) for ctr, factory in enumerate(credentialFactories): challenge = (yield factory.getChallenge(clientAddress)) challenge['nonce'] = "noNoncense" clientResponse = authRequest1[ctr] % ( challenge['nonce'], self.getDigestResponse(challenge, "00000001"), ) request = _trivial_GET() yield self.assertRaisesDeferred(error.LoginFailed, factory.decode, clientResponse, request) factory._invalidate(FAKE_STATIC_NONCE) response = (yield UnauthorizedResponse.makeResponse({"Digest": factory}, request.remoteAddr)) response.headers.getHeader("www-authenticate")[0][1]
def test_invalidNonce(self): """ Test that login fails when the given nonce from the response, does not match the nonce encoded in the opaque. """ credentialFactories = ( FakeDigestCredentialFactory('md5', 'auth', 'test realm', self.namespace1), FakeDigestCredentialFactory('md5', '', 'test realm', self.namespace2) ) for ctr, factory in enumerate(credentialFactories): challenge = (yield factory.getChallenge(clientAddress)) challenge['nonce'] = "noNoncense" clientResponse = authRequest1[ctr] % ( challenge['nonce'], self.getDigestResponse(challenge, "00000001"), ) request = _trivial_GET() yield self.assertRaisesDeferred( error.LoginFailed, factory.decode, clientResponse, request ) factory._invalidate(FAKE_STATIC_NONCE) response = (yield UnauthorizedResponse.makeResponse( {"Digest": factory}, request.remoteAddr )) response.headers.getHeader("www-authenticate")[0][1]
def renderHTTP(self, request): try: _ignore_authnUser, authzUser = yield self.authenticate(request) except Exception: authzUser = None # Turn 404 into 401 if authzUser is None: response = (yield UnauthorizedResponse.makeResponse( request.credentialFactories, request.remoteAddr)) returnValue(response) else: response = StatusResponse(responsecode.NOT_FOUND, "Resource not found") returnValue(response)
def handleMissingTrailingSlash(self, request): try: _ignore_authnUser, authzUser = yield self.authenticate(request) except Exception: authzUser = None # Turn 301 into 401 if authzUser is None: response = (yield UnauthorizedResponse.makeResponse( request.credentialFactories, request.remoteAddr)) returnValue(response) else: response = RedirectResponse( request.unparseURL(path=urllib.quote( urllib.unquote(request.path), safe=':/') + '/')) returnValue(response)
def renderHTTP(self, request): try: _ignore_authnUser, authzUser = yield self.authenticate(request) except Exception: authzUser = None # Turn 404 into 401 if authzUser is None: response = (yield UnauthorizedResponse.makeResponse( request.credentialFactories, request.remoteAddr )) returnValue(response) else: response = StatusResponse(responsecode.NOT_FOUND, "Resource not found") returnValue(response)
def test_oldNonce(self): """ Test that the login fails when the given opaque is older than DigestCredentialFactory.CHALLENGE_LIFETIME_SECS """ credentialFactories = (FakeDigestCredentialFactory( 'md5', 'auth', 'test realm', self.namespace1), FakeDigestCredentialFactory( 'md5', '', 'test realm', self.namespace2)) for ctr, factory in enumerate(credentialFactories): challenge = (yield factory.getChallenge(clientAddress)) nonce_count, timestamp = (yield factory.db.get(challenge['nonce'])) factory.db.set( challenge['nonce'], (nonce_count, timestamp - 2 * digest.DigestCredentialFactory.CHALLENGE_LIFETIME_SECS)) clientResponse = authRequest1[ctr] % ( challenge['nonce'], self.getDigestResponse(challenge, "00000001"), ) request = _trivial_GET() yield self.assertRaisesDeferred(error.LoginFailed, factory.decode, clientResponse, request) response = (yield UnauthorizedResponse.makeResponse( {"Digest": factory}, request.remoteAddr, )) wwwhdrs = response.headers.getHeader("www-authenticate")[0][1] self.assertTrue( 'stale' in wwwhdrs, msg="No stale parameter in Digest WWW-Authenticate headers: %s" % (wwwhdrs, )) self.assertEquals( wwwhdrs['stale'], 'true', msg= "stale parameter not set to true in Digest WWW-Authenticate headers: %s" % (wwwhdrs, ))
def handleMissingTrailingSlash(self, request): try: _ignore_authnUser, authzUser = yield self.authenticate(request) except Exception: authzUser = None # Turn 301 into 401 if authzUser is None: response = (yield UnauthorizedResponse.makeResponse( request.credentialFactories, request.remoteAddr )) returnValue(response) else: response = RedirectResponse( request.unparseURL( path=quote( unquote(request.path), safe=':/') + '/' ) ) returnValue(response)
def test_oldNonce(self): """ Test that the login fails when the given opaque is older than DigestCredentialFactory.CHALLENGE_LIFETIME_SECS """ credentialFactories = ( FakeDigestCredentialFactory('md5', 'auth', 'test realm', self.namespace1), FakeDigestCredentialFactory('md5', '', 'test realm', self.namespace2) ) for ctr, factory in enumerate(credentialFactories): challenge = (yield factory.getChallenge(clientAddress)) nonce_count, timestamp = (yield factory.db.get(challenge['nonce'])) factory.db.set(challenge['nonce'], (nonce_count, timestamp - 2 * digest.DigestCredentialFactory.CHALLENGE_LIFETIME_SECS)) clientResponse = authRequest1[ctr] % ( challenge['nonce'], self.getDigestResponse(challenge, "00000001"), ) request = _trivial_GET() yield self.assertRaisesDeferred( error.LoginFailed, factory.decode, clientResponse, request ) response = (yield UnauthorizedResponse.makeResponse( {"Digest": factory}, request.remoteAddr, )) wwwhdrs = response.headers.getHeader("www-authenticate")[0][1] self.assertTrue('stale' in wwwhdrs, msg="No stale parameter in Digest WWW-Authenticate headers: %s" % (wwwhdrs,)) self.assertEquals(wwwhdrs['stale'], 'true', msg="stale parameter not set to true in Digest WWW-Authenticate headers: %s" % (wwwhdrs,))
def locateChild(self, request, segments): for filter in self.contentFilters: request.addResponseFilter(filter[0], atEnd=filter[1]) # Examine cookies for wiki auth token; if there, ask the paired wiki # server for the corresponding record name. If that maps to a # principal, assign that to authnuser. # Also, certain non-browser clients send along the wiki auth token # sometimes, so we now also look for the presence of x-requested-with # header that the webclient sends. However, in the case of a GET on # /webcal that header won't be sent so therefore we allow wiki auth # for any path in the authServiceMap even if that header is missing. allowWikiAuth = False topLevel = request.path.strip("/").split("/")[0] if self.authServiceMap.get(topLevel, False): allowWikiAuth = True if not hasattr(request, "checkedWiki"): # Only do this once per request request.checkedWiki = True wikiConfig = config.Authentication.Wiki cookies = request.headers.getHeader("cookie") requestedWith = request.headers.hasHeader("x-requested-with") if ( wikiConfig["Enabled"] and (requestedWith or allowWikiAuth) and cookies is not None ): for cookie in cookies: if cookie.name == wikiConfig["Cookie"]: token = cookie.value break else: token = None if token is not None and token != "unauthenticated": log.debug( "Wiki sessionID cookie value: {token}", token=token ) try: uid = yield uidForAuthToken(token, wikiConfig["EndpointDescriptor"]) if uid == "unauthenticated": uid = None except WebError as w: uid = None # FORBIDDEN status means it's an unknown token if int(w.status) == responsecode.NOT_FOUND: log.debug( "Unknown wiki token: {token}", token=token ) else: log.error( "Failed to look up wiki token {token}: {msg}", token=token, msg=w.message ) except Exception as e: log.error( "Failed to look up wiki token: {error}", error=e ) uid = None if uid is not None: log.debug( "Wiki lookup returned uid: {uid}", uid=uid ) principal = yield self.principalForUID(request, uid) if principal: log.debug( "Wiki-authenticated principal {uid} " "being assigned to authnUser and authzUser", uid=uid ) request.authzUser = request.authnUser = principal if not hasattr(request, "authzUser") and config.WebCalendarAuthPath: topLevel = request.path.strip("/").split("/")[0] if self.authServiceMap.get(topLevel, False): # We've not been authenticated and the auth service is enabled # for this resource, so redirect. # Use config.ServerHostName if no x-forwarded-host header, # otherwise use the final hostname in x-forwarded-host. host = request.headers.getRawHeaders( "x-forwarded-host", [config.ServerHostName] )[-1].split(",")[-1].strip() port = 443 if (config.EnableSSL or config.BehindTLSProxy) else 80 scheme = "https" if config.EnableSSL else "http" response = RedirectResponse( request.unparseURL( host=host, port=port, scheme=scheme, path=config.WebCalendarAuthPath, querystring="redirect={}://{}{}".format( scheme, host, request.path ) ), temporary=True ) raise HTTPError(response) # We don't want the /inbox resource to pay attention to SACLs because # we just want it to use the hard-coded ACL for the imip reply user. # The /timezones resource is used by the wiki web calendar, so open # up that resource. if segments[0] in ("inbox", "timezones"): request.checkedSACL = True elif ( ( len(segments) > 2 and segments[0] in ("calendars", "principals") and ( segments[1] == "wikis" or ( segments[1] == "__uids__" and segments[2].startswith(WikiDirectoryService.uidPrefix) ) ) ) ): # This is a wiki-related calendar resource. SACLs are not checked. request.checkedSACL = True # The authzuser value is set to that of the wiki principal if # not already set. if not hasattr(request, "authzUser") and segments[2]: wikiUid = None if segments[1] == "wikis": wikiUid = "{}{}".format(WikiDirectoryService.uidPrefix, segments[2]) else: wikiUid = segments[2] if wikiUid: log.debug( "Wiki principal {name} being assigned to authzUser", name=wikiUid ) request.authzUser = yield self.principalForUID(request, wikiUid) elif ( self.useSacls and not hasattr(request, "checkedSACL") ): yield self.checkSACL(request) if config.RejectClients: # # Filter out unsupported clients # agent = request.headers.getHeader("user-agent") if agent is not None: for reject in config.RejectClients: if reject.search(agent) is not None: log.info("Rejecting user-agent: {agent}", agent=agent) raise HTTPError(StatusResponse( responsecode.FORBIDDEN, "Your client software ({}) is not allowed to " "access this service." .format(agent) )) if not hasattr(request, "authnUser"): try: authnUser, authzUser = yield self.authenticate(request) request.authnUser = authnUser request.authzUser = authzUser except (UnauthorizedLogin, LoginFailed): response = yield UnauthorizedResponse.makeResponse( request.credentialFactories, request.remoteAddr ) raise HTTPError(response) if ( config.EnableResponseCache and request.method == "PROPFIND" and not getattr(request, "notInCache", False) and len(segments) > 1 ): try: if not getattr(request, "checkingCache", False): request.checkingCache = True response = yield self.responseCache.getResponseForRequest( request ) if response is None: request.notInCache = True raise KeyError("Not found in cache.") returnValue((_CachedResponseResource(response), [])) except KeyError: pass child = yield super(RootResource, self).locateChild( request, segments ) returnValue(child)
def getWikiACL(resource, request): """ Ask the wiki server we're paired with what level of access the authnUser has. Returns an ACL. Wiki authentication is a bit tricky because the end-user accessing a group calendar may not actually be enabled for calendaring. Therefore in that situation, the authzUser will have been replaced with the wiki principal in locateChild( ), so that any changes the user makes will have the wiki as the originator. The authnUser will always be the end-user. """ from twistedcaldav.directory.principal import DirectoryPrincipalResource if (not hasattr(resource, "record") or resource.record.recordType != WikiDirectoryService.recordType_wikis): returnValue(None) if hasattr(request, 'wikiACL'): returnValue(request.wikiACL) userID = "unauthenticated" wikiID = resource.record.shortNames[0] try: url = str(request.authnUser.children[0]) principal = (yield request.locateResource(url)) if isinstance(principal, DirectoryPrincipalResource): userID = principal.record.guid except: # TODO: better error handling pass try: access = (yield getWikiAccess(userID, wikiID)) # The ACL we returns has ACEs for the end-user and the wiki principal # in case authzUser is the wiki principal. if access == "read": request.wikiACL = davxml.ACL( davxml.ACE( request.authnUser, davxml.Grant( davxml.Privilege(davxml.Read()), davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()), # We allow write-properties so that direct sharees can change # e.g. calendar color properties davxml.Privilege(davxml.WriteProperties()), ), TwistedACLInheritable(), ), davxml.ACE( davxml.Principal( davxml.HRef.fromString("/principals/wikis/%s/" % (wikiID,)) ), davxml.Grant( davxml.Privilege(davxml.Read()), davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()), ), TwistedACLInheritable(), ) ) returnValue(request.wikiACL) elif access in ("write", "admin"): request.wikiACL = davxml.ACL( davxml.ACE( request.authnUser, davxml.Grant( davxml.Privilege(davxml.Read()), davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()), davxml.Privilege(davxml.Write()), ), TwistedACLInheritable(), ), davxml.ACE( davxml.Principal( davxml.HRef.fromString("/principals/wikis/%s/" % (wikiID,)) ), davxml.Grant( davxml.Privilege(davxml.Read()), davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()), davxml.Privilege(davxml.Write()), ), TwistedACLInheritable(), ) ) returnValue(request.wikiACL) else: # "no-access": if userID == "unauthenticated": # Return a 401 so they have an opportunity to log in response = (yield UnauthorizedResponse.makeResponse( request.credentialFactories, request.remoteAddr, )) raise HTTPError(response) raise HTTPError( StatusResponse( responsecode.FORBIDDEN, "You are not allowed to access this wiki" ) ) except HTTPError: # pass through the HTTPError we might have raised above raise except Exception, e: log.error("Wiki ACL lookup failed: %s" % (e,)) raise HTTPError(StatusResponse(responsecode.SERVICE_UNAVAILABLE, "Wiki ACL lookup failed"))
def getWikiACL(resource, request): """ Ask the wiki server we're paired with what level of access the authnUser has. Returns an ACL. Wiki authentication is a bit tricky because the end-user accessing a group calendar may not actually be enabled for calendaring. Therefore in that situation, the authzUser will have been replaced with the wiki principal in locateChild( ), so that any changes the user makes will have the wiki as the originator. The authnUser will always be the end-user. """ from twistedcaldav.directory.principal import DirectoryPrincipalResource if (not hasattr(resource, "record") or resource.record.recordType != RecordType.macOSXServerWiki): returnValue(None) if hasattr(request, 'wikiACL'): returnValue(request.wikiACL) wikiRecord = resource.record wikiID = wikiRecord.shortNames[0] userRecord = None try: url = request.authnUser.principalURL() principal = (yield request.locateResource(url)) if isinstance(principal, DirectoryPrincipalResource): userRecord = principal.record except: # TODO: better error handling pass try: access = yield wikiRecord.accessForRecord(userRecord) # The ACL we returns has ACEs for the end-user and the wiki principal # in case authzUser is the wiki principal. if access == WikiAccessLevel.read: request.wikiACL = davxml.ACL( davxml.ACE( (request.authnUser.principalElement() if request.authnUser is not None else davxml.Principal( davxml.Unauthenticated())), davxml.Grant( davxml.Privilege(davxml.Read()), davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()), # We allow write-properties so that direct sharees can # change e.g. calendar color properties davxml.Privilege(davxml.WriteProperties()), ), TwistedACLInheritable(), ), davxml.ACE( davxml.Principal( davxml.HRef.fromString( "/principals/wikis/{}/".format(wikiID))), davxml.Grant( davxml.Privilege(davxml.Read()), davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()), ), TwistedACLInheritable(), )) returnValue(request.wikiACL) elif access == WikiAccessLevel.write: request.wikiACL = davxml.ACL( davxml.ACE( (request.authnUser.principalElement() if request.authnUser is not None else davxml.Principal( davxml.Unauthenticated())), davxml.Grant( davxml.Privilege(davxml.Read()), davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()), davxml.Privilege(davxml.Write()), ), TwistedACLInheritable(), ), davxml.ACE( davxml.Principal( davxml.HRef.fromString( "/principals/wikis/{}/".format(wikiID))), davxml.Grant( davxml.Privilege(davxml.Read()), davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()), davxml.Privilege(davxml.Write()), ), TwistedACLInheritable(), )) returnValue(request.wikiACL) else: # "no-access": if userRecord is None: # Return a 401 so they have an opportunity to log in response = (yield UnauthorizedResponse.makeResponse( request.credentialFactories, request.remoteAddr, )) raise HTTPError(response) raise HTTPError( StatusResponse(responsecode.FORBIDDEN, "You are not allowed to access this wiki")) except HTTPError: # pass through the HTTPError we might have raised above raise except Exception as e: log.error("Wiki ACL lookup failed: {error}", error=e) raise HTTPError( StatusResponse(responsecode.SERVICE_UNAVAILABLE, "Wiki ACL lookup failed"))
def locateChild(self, request, segments): for filter in self.contentFilters: request.addResponseFilter(filter[0], atEnd=filter[1]) # Examine cookies for wiki auth token; if there, ask the paired wiki # server for the corresponding record name. If that maps to a # principal, assign that to authnuser. # Also, certain non-browser clients send along the wiki auth token # sometimes, so we now also look for the presence of x-requested-with # header that the webclient sends. However, in the case of a GET on # /webcal that header won't be sent so therefore we allow wiki auth # for any path in the authServiceMap even if that header is missing. allowWikiAuth = False topLevel = request.path.strip("/").split("/")[0] if self.authServiceMap.get(topLevel, False): allowWikiAuth = True if not hasattr(request, "checkedWiki"): # Only do this once per request request.checkedWiki = True wikiConfig = config.Authentication.Wiki cookies = request.headers.getHeader("cookie") requestedWith = request.headers.hasHeader("x-requested-with") if ( wikiConfig["Enabled"] and (requestedWith or allowWikiAuth) and cookies is not None ): for cookie in cookies: if cookie.name == wikiConfig["Cookie"]: token = cookie.value break else: token = None if token is not None and token != "unauthenticated": log.debug( "Wiki sessionID cookie value: {token}", token=token ) try: uid = yield uidForAuthToken(token) if uid == "unauthenticated": uid = None except WebError as w: uid = None # FORBIDDEN status means it's an unknown token if int(w.status) == responsecode.NOT_FOUND: log.debug( "Unknown wiki token: {token}", token=token ) else: log.error( "Failed to look up wiki token {token}: " "{message}", token=token, message=w.message ) except Exception as e: log.error( "Failed to look up wiki token: {error}", error=e ) uid = None if uid is not None: log.debug( "Wiki lookup returned uid: {uid}", uid=uid ) principal = yield self.principalForUID(request, uid) if principal: log.debug( "Wiki-authenticated principal {uid} " "being assigned to authnUser and authzUser", uid=uid ) request.authzUser = request.authnUser = principal if not hasattr(request, "authzUser") and config.WebCalendarAuthPath: topLevel = request.path.strip("/").split("/")[0] if self.authServiceMap.get(topLevel, False): # We've not been authenticated and the auth service is enabled # for this resource, so redirect. # Use config.ServerHostName if no x-forwarded-host header, # otherwise use the final hostname in x-forwarded-host. host = request.headers.getRawHeaders( "x-forwarded-host", [config.ServerHostName] )[-1].split(",")[-1].strip() port = 443 if config.EnableSSL else 80 scheme = "https" if config.EnableSSL else "http" response = RedirectResponse( request.unparseURL( host=host, port=port, scheme=scheme, path=config.WebCalendarAuthPath, querystring="redirect={}://{}{}".format( scheme, host, request.path ) ), temporary=True ) raise HTTPError(response) # We don't want the /inbox resource to pay attention to SACLs because # we just want it to use the hard-coded ACL for the imip reply user. # The /timezones resource is used by the wiki web calendar, so open # up that resource. if segments[0] in ("inbox", "timezones"): request.checkedSACL = True elif ( ( len(segments) > 2 and segments[0] in ("calendars", "principals") and ( segments[1] == "wikis" or ( segments[1] == "__uids__" and segments[2].startswith(WikiDirectoryService.uidPrefix) ) ) ) ): # This is a wiki-related calendar resource. SACLs are not checked. request.checkedSACL = True # The authzuser value is set to that of the wiki principal if # not already set. if not hasattr(request, "authzUser") and segments[2]: wikiUid = None if segments[1] == "wikis": wikiUid = "{}{}".format(WikiDirectoryService.uidPrefix, segments[2]) else: wikiUid = segments[2] if wikiUid: log.debug( "Wiki principal {name} being assigned to authzUser", name=wikiUid ) request.authzUser = yield self.principalForUID(request, wikiUid) elif ( self.useSacls and not hasattr(request, "checkedSACL") ): yield self.checkSACL(request) if config.RejectClients: # # Filter out unsupported clients # agent = request.headers.getHeader("user-agent") if agent is not None: for reject in config.RejectClients: if reject.search(agent) is not None: log.info("Rejecting user-agent: {agent}", agent=agent) raise HTTPError(StatusResponse( responsecode.FORBIDDEN, "Your client software ({}) is not allowed to " "access this service." .format(agent) )) if not hasattr(request, "authnUser"): try: authnUser, authzUser = yield self.authenticate(request) request.authnUser = authnUser request.authzUser = authzUser except (UnauthorizedLogin, LoginFailed): response = yield UnauthorizedResponse.makeResponse( request.credentialFactories, request.remoteAddr ) raise HTTPError(response) if ( config.EnableResponseCache and request.method == "PROPFIND" and not getattr(request, "notInCache", False) and len(segments) > 1 ): try: if not getattr(request, "checkingCache", False): request.checkingCache = True response = yield self.responseCache.getResponseForRequest( request ) if response is None: request.notInCache = True raise KeyError("Not found in cache.") returnValue((_CachedResponseResource(response), [])) except KeyError: pass child = yield super(RootResource, self).locateChild( request, segments ) returnValue(child)
for reject in config.RejectClients: if reject.search(agent) is not None: log.info("Rejecting user-agent: %s" % (agent,)) raise HTTPError(StatusResponse( responsecode.FORBIDDEN, "Your client software (%s) is not allowed to access this service." % (agent,) )) if config.EnableResponseCache and request.method == "PROPFIND" and not getattr(request, "notInCache", False) and len(segments) > 1: try: authnUser, authzUser = (yield self.authenticate(request)) request.authnUser = authnUser request.authzUser = authzUser except (UnauthorizedLogin, LoginFailed): response = (yield UnauthorizedResponse.makeResponse( request.credentialFactories, request.remoteAddr )) raise HTTPError(response) try: if not getattr(request, "checkingCache", False): request.checkingCache = True response = (yield self.responseCache.getResponseForRequest(request)) if response is None: request.notInCache = True raise KeyError("Not found in cache.") returnValue((_CachedResponseResource(response), [])) except KeyError: pass