Tres Seaver
2012-03-18 330d9573ecb2430127fa67d0f5f8602b6f30869f
commit | author | age
4a8c36 1 import binascii
CM 2
02a504 3 from webob.exc import HTTPUnauthorized
1fa560 4 from zope.interface import implementer
4a8c36 5
cb5426 6 from repoze.who.interfaces import IIdentifier
CM 7 from repoze.who.interfaces import IChallenger
a90306 8 from repoze.who._compat import AUTHORIZATION
TS 9 from repoze.who._compat import decodebytes
330d95 10 from repoze.who._compat import must_decode
4a8c36 11
1fa560 12 @implementer(IIdentifier, IChallenger)
4a8c36 13 class BasicAuthPlugin(object):
CM 14
d85ba6 15     def __init__(self, realm):
4a8c36 16         self.realm = realm
CM 17
c51195 18     # IIdentifier
CM 19     def identify(self, environ):
4a8c36 20         authorization = AUTHORIZATION(environ)
a90306 21         if type(authorization) != type(b''):
TS 22             # this header *must* be base64-encoded ASCII
23             authorization = authorization.encode('ascii')
4a8c36 24         try:
a90306 25             authmeth, auth = authorization.split(b' ', 1)
7dfea7 26         except ValueError: # not enough values to unpack
40a968 27             return None
330d95 28         if authmeth.lower() == b'basic':
4a8c36 29             try:
a90306 30                 auth = auth.strip()
TS 31                 auth = decodebytes(auth)
7dfea7 32             except binascii.Error: # can't decode
40a968 33                 return None
4a8c36 34             try:
a90306 35                 login, password = auth.split(b':', 1)
7dfea7 36             except ValueError: # not enough values to unpack
40a968 37                 return None
330d95 38             auth = {'login': must_decode(login),
TS 39                     'password': must_decode(password)}
7dfea7 40             return auth
4a8c36 41
40a968 42         return None
4a8c36 43
c51195 44     # IIdentifier
CM 45     def remember(self, environ, identity):
46         # we need to do nothing here; the browser remembers the basic
47         # auth info as a result of the user typing it in.
48         pass
49
50     def _get_wwwauth(self):
02a504 51         head = [('WWW-Authenticate', 'Basic realm="%s"' % self.realm)]
c51195 52         return head
CM 53
54     # IIdentifier
55     def forget(self, environ, identity):
56         return self._get_wwwauth()
57
58     # IChallenger
59     def challenge(self, environ, status, app_headers, forget_headers):
60         head = self._get_wwwauth()
4daaea 61         if head[0] not in forget_headers:
c51195 62             head = head + forget_headers
CM 63         return HTTPUnauthorized(headers=head)
7dfea7 64
97cfa2 65     def __repr__(self):
396eef 66         return '<%s %s>' % (self.__class__.__name__,
TS 67                             id(self)) #pragma NO COVERAGE
97cfa2 68
515c69 69 def make_plugin(realm='basic'):
d85ba6 70     plugin = BasicAuthPlugin(realm)
CM 71     return plugin
72