Skip to content

Commit

Permalink
Merge httpauth-wrapper-child-3679
Browse files Browse the repository at this point in the history
Author: exarkun
Reviewer: dreid
Fixes: twisted#3679

Fix a bug in the HTTP auth resource wrapper which caused it to disregard
the first segment of the request after the segment representing the wrapper.

Also change the unit tests to use the real resource traversal API instead of
bugfully imitating it.


git-svn-id: svn://svn.twistedmatrix.com/svn/Twisted/trunk@26540 bbbe8e31-12d6-0310-92fd-ac37d47ddeeb
  • Loading branch information
exarkun committed Mar 30, 2009
1 parent 60c2d10 commit ba532b4
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 31 deletions.
1 change: 1 addition & 0 deletions twisted/web/_auth/wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ def getChildWithDefault(self, path, request):
log.err(None, "Unexpected failure from credentials factory")
return ErrorPage(500, None, None)
else:
request.postpath.insert(0, request.prepath.pop())
return util.DeferredResource(self._login(credentials))


Expand Down
69 changes: 38 additions & 31 deletions twisted/web/test/test_httpauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from twisted.cred.credentials import IUsernamePassword

from twisted.web.iweb import ICredentialFactory
from twisted.web.resource import IResource, Resource
from twisted.web.resource import IResource, Resource, getChildForRequest
from twisted.web._auth import basic, digest
from twisted.web._auth.wrapper import HTTPAuthSessionWrapper, UnauthorizedResource
from twisted.web._auth.basic import BasicCredentialFactory
Expand Down Expand Up @@ -331,21 +331,21 @@ def setUp(self):
self.portal, self.credentialFactories)


def _authorizedBasicLogin(self, request, creds=None):
if creds is None:
username, password = self.username, self.password
else:
username, password = creds
authorization = b64encode(username + ':' + password)
def _authorizedBasicLogin(self, request):
"""
Add an I{basic authorization} header to the given request and then
dispatch it, starting from C{self.wrapper} and returning the resulting
L{IResource}.
"""
authorization = b64encode(self.username + ':' + self.password)
request.headers['authorization'] = 'Basic ' + authorization
child = self.wrapper.getChildWithDefault(request.postpath[0], request)
return child
return getChildForRequest(self.wrapper, request)


def test_getChildWithDefault(self):
"""
L{HTTPAuthSessionWrapper.getChildWithDefault} returns an
L{UnauthorizedResource} instance when called with a request which does
Resource traversal which encounters an L{HTTPAuthSessionWrapper}
results in an L{UnauthorizedResource} instance when the request does
not have the required I{Authorization} headers.
"""
request = self.makeRequest([self.childName])
Expand All @@ -354,10 +354,16 @@ def test_getChildWithDefault(self):


def _invalidAuthorizationTest(self, response):
"""
Create a request with the given value as the value of an
I{Authorization} header and perform resource traversal with it,
starting at C{self.wrapper}. Assert that the result is a 401 response
code. Return a L{Deferred} which fires when this is all done.
"""
self.credentialFactories.append(BasicCredentialFactory('example.com'))
request = self.makeRequest([self.childName])
request.headers['authorization'] = response
child = self.wrapper.getChildWithDefault(self.childName, request)
child = getChildForRequest(self.wrapper, request)
d = request.notifyFinish()
def cbFinished(result):
self.assertEqual(request.responseCode, 401)
Expand All @@ -368,38 +374,39 @@ def cbFinished(result):

def test_getChildWithDefaultUnauthorizedUser(self):
"""
If L{HTTPAuthSessionWrapper.getChildWithDefault} is called with a
request with an I{Authorization} header with a user which does not
exist, an L{IResource} which renders a 401 response code is returned.
Resource traversal which enouncters an L{HTTPAuthSessionWrapper}
results in an L{UnauthorizedResource} when the request has an
I{Authorization} header with a user which does not exist.
"""
return self._invalidAuthorizationTest('Basic ' + b64encode('foo:bar'))


def test_getChildWithDefaultUnauthorizedPassword(self):
"""
If L{HTTPAuthSessionWrapper.getChildWithDefault} is called with a
request with an I{Authorization} header with a user which exists and
the wrong password, an L{IResource} which renders a 401 response code
is returned.
Resource traversal which enouncters an L{HTTPAuthSessionWrapper}
results in an L{UnauthorizedResource} when the request has an
I{Authorization} header with a user which exists and the wrong
password.
"""
return self._invalidAuthorizationTest(
'Basic ' + b64encode(self.username + ':bar'))


def test_getChildWithDefaultUnrecognizedScheme(self):
"""
If L{HTTPAuthSessionWrapper.getChildWithDefault} is called with a
request with an I{Authorization} header with an unrecognized scheme, an
L{IResource} which renders a 401 response code is returned.
Resource traversal which enouncters an L{HTTPAuthSessionWrapper}
results in an L{UnauthorizedResource} when the request has an
I{Authorization} header with an unrecognized scheme.
"""
return self._invalidAuthorizationTest('Quux foo bar baz')


def test_getChildWithDefaultAuthorized(self):
"""
When called with a request with a valid I{Authorization} header,
L{HTTPAuthSessionWrapper.getChildWithDefault} returns an L{IResource}
which renders the L{IResource} avatar retrieved from the portal.
Resource traversal which enouncters an L{HTTPAuthSessionWrapper}
results in an L{IResource} which renders the L{IResource} avatar
retrieved from the portal when the request has a valid I{Authorization}
header.
"""
self.credentialFactories.append(BasicCredentialFactory('example.com'))
request = self.makeRequest([self.childName])
Expand Down Expand Up @@ -432,7 +439,7 @@ def getChallenge(self, request):
factory = DumbCredentialFactory()
self.credentialFactories.append(factory)
request = self.makeRequest([self.childName])
child = self.wrapper.getChildWithDefault(request.postpath[0], request)
child = getChildForRequest(self.wrapper, request)
d = request.notifyFinish()
def cbFinished(ignored):
self.assertEqual(factory.requests, [request])
Expand Down Expand Up @@ -462,14 +469,14 @@ def render(self, request):

def test_decodeRaises(self):
"""
L{HTTPAuthSessionWrapper.getChildWithDefault} returns an
L{UnauthorizedResource} instance when called with a request which has a
I{Basic Authorization} header which cannot be decoded using base64.
Resource traversal which enouncters an L{HTTPAuthSessionWrapper}
results in an L{UnauthorizedResource} when the request has a I{Basic
Authorization} header which cannot be decoded using base64.
"""
self.credentialFactories.append(BasicCredentialFactory('example.com'))
request = self.makeRequest([self.childName])
request.headers['authorization'] = 'Basic decode should fail'
child = self.wrapper.getChildWithDefault(self.childName, request)
child = getChildForRequest(self.wrapper, request)
self.assertIsInstance(child, UnauthorizedResource)


Expand Down Expand Up @@ -511,7 +518,7 @@ def decode(self, response, request):
self.credentialFactories.append(BadFactory())
request = self.makeRequest([self.childName])
request.headers['authorization'] = 'Bad abc'
child = self.wrapper.getChildWithDefault(self.childName, request)
child = getChildForRequest(self.wrapper, request)
render(child, request)
self.assertEqual(request.responseCode, 500)
self.assertEqual(len(self.flushLoggedErrors(UnexpectedException)), 1)
Expand Down

0 comments on commit ba532b4

Please sign in to comment.