diff options
| author | Chris Rossi <chris@archimedeanco.com> | 2012-10-12 13:50:30 -0400 |
|---|---|---|
| committer | Chris Rossi <chris@archimedeanco.com> | 2012-10-12 13:50:30 -0400 |
| commit | 201596a39fd7c988924586ee9ab2c3c6e4b0387a (patch) | |
| tree | 7e84ada6c040dfa56413c568fb48fb942bc2d098 | |
| parent | b33a6a79fe614bd50a9a6993d8538ac0e8469bc1 (diff) | |
| download | pyramid-201596a39fd7c988924586ee9ab2c3c6e4b0387a.tar.gz pyramid-201596a39fd7c988924586ee9ab2c3c6e4b0387a.tar.bz2 pyramid-201596a39fd7c988924586ee9ab2c3c6e4b0387a.zip | |
Add basic auth authentication policy.
| -rw-r--r-- | pyramid/authentication.py | 91 |
1 files changed, 83 insertions, 8 deletions
diff --git a/pyramid/authentication.py b/pyramid/authentication.py index 83bdb13d1..7161e1d1f 100644 --- a/pyramid/authentication.py +++ b/pyramid/authentication.py @@ -1,3 +1,4 @@ +import binascii from codecs import utf_8_decode from codecs import utf_8_encode from hashlib import md5 @@ -330,13 +331,13 @@ class AuthTktAuthenticationPolicy(CallbackAuthenticationPolicy): Optional. ``path`` - + Default: ``/``. The path for which the auth_tkt cookie is valid. May be desirable if the application only serves part of a domain. Optional. - + ``http_only`` - + Default: ``False``. Hide cookie from JavaScript by setting the HttpOnly flag. Not honored by all browsers. Optional. @@ -553,7 +554,7 @@ class AuthTktCookieHelper(object): text_type: ('b64unicode', lambda x: b64encode(utf_8_encode(x)[0])), binary_type: ('b64str', lambda x: b64encode(x)), } - + def __init__(self, secret, cookie_name='auth_tkt', secure=False, include_ip=False, timeout=None, reissue_time=None, max_age=None, http_only=False, path="/", wild_domain=True): @@ -632,7 +633,7 @@ class AuthTktCookieHelper(object): remote_addr = environ['REMOTE_ADDR'] else: remote_addr = '0.0.0.0' - + try: timestamp, userid, tokens, user_data = self.parse_ticket( self.secret, cookie, remote_addr) @@ -641,7 +642,7 @@ class AuthTktCookieHelper(object): now = self.now # service tests - if now is None: + if now is None: now = time_mod.time() if self.timeout and ( (timestamp + self.timeout) < now ): @@ -689,7 +690,7 @@ class AuthTktCookieHelper(object): environ = request.environ request._authtkt_reissue_revoked = True return self._get_cookies(environ, '', max_age=EXPIRE) - + def remember(self, request, userid, max_age=None, tokens=()): """ Return a set of Set-Cookie headers; when set into a response, these headers will represent a valid authentication ticket. @@ -783,7 +784,7 @@ class SessionAuthenticationPolicy(CallbackAuthenticationPolicy): Pyramid debug logger about the results of various authentication steps. The output from debugging is useful for reporting to maillist or IRC channels when asking for support. - + """ def __init__(self, prefix='auth.', callback=None, debug=False): @@ -806,3 +807,77 @@ class SessionAuthenticationPolicy(CallbackAuthenticationPolicy): def unauthenticated_userid(self, request): return request.session.get(self.userid_key) + +@implementer(IAuthenticationPolicy) +class BasicAuthAuthenticationPolicy(CallbackAuthenticationPolicy): + """ A :app:`Pyramid` authentication policy which uses HTTP standard basic + authentication protocol to authenticate users. To use this policy you will + need to provide a callback which checks the supplied user credentials + against your source of login data. + + Constructor Arguments + + ``check`` + + A callback function passed a username, password and request, in that + order as positional arguments. Expected to return ``None`` if the + userid doesn't exist or a sequence of principal identifiers (possibly + empty) if the user does exist. + + ``realm`` + + Default: ``Realm``. The Basic Auth Realm string. Usually displayed to + the user by the browser in the login dialog. + + ``debug`` + + Default: ``False``. If ``debug`` is ``True``, log messages to the + Pyramid debug logger about the results of various authentication + steps. The output from debugging is useful for reporting to maillist + or IRC channels when asking for support. + + """ + def __init__(self, check, realm='Realm', debug=False): + self.check = check + self.realm = realm + self.debug = debug + + def unauthenticated_userid(self, request): + credentials = self._get_credentials(request) + if credentials: + return credentials[0] + + def remember(self, request, principal, **kw): + return [] + + def forget(self, request): + return [('WWW-Authenticate', 'Basic realm="%s"' % self.realm)] + + def callback(self, username, request): + # Username arg is ignored. Unfortunately _get_credentials winds up + # getting called twice when authenticated_userid is called. Avoiding + # that, however, winds up duplicating logic from the superclass. + credentials = self._get_credentials(request) + if credentials: + username, password = credentials + return self.check(username, password, request) + + def _get_credentials(self, request): + authorization = request.headers.get('Authorization') + if not authorization: + return None + try: + authmeth, auth = authorization.split(' ', 1) + except ValueError: # not enough values to unpack + return None + if authmeth.lower() != 'basic': + return None + try: + auth = auth.strip().decode('base64') + except binascii.Error: # can't decode + return None + try: + username, password = auth.split(':', 1) + except ValueError: # not enough values to unpack + return None + return username, password |
