diff options
| author | Jamie Matthews | 2012-09-26 13:05:21 +0100 |
|---|---|---|
| committer | Jamie Matthews | 2012-09-26 13:05:21 +0100 |
| commit | 01770c53cd9045e6ea054f32b1e40b5d2ff7fe44 (patch) | |
| tree | 657cb66f92d78add3b2f587754387832043168e6 /rest_framework/authentication.py | |
| parent | f6488cb0589d3b11fb8d831e00d1389f3fff74b6 (diff) | |
| parent | 09a445b257532be69ffab69a3f62b84bfa90463d (diff) | |
| download | django-rest-framework-01770c53cd9045e6ea054f32b1e40b5d2ff7fe44.tar.bz2 | |
Merge branch 'restframework2' of git://github.com/tomchristie/django-rest-framework into improved-view-decorators
* 'restframework2' of git://github.com/tomchristie/django-rest-framework: (56 commits)
Bits of cleanup
Add request.QUERY_PARAMS
Add readonly 'id' field
Tweak browseable API
Don't display readonly fields
Fix some bits of serialization
Add csrf note
Fix incorrect bit of tutorial
Added tox.ini
Tweak media_type -> accepted_media_type. Need to document, but marginally less confusing
Tweak media_type -> accepted_media_type. Need to document, but marginally less confusing
Tweak media_type -> accepted_media_type. Need to document, but marginally less confusing
Clean up bits of templates etc
Hack out bunch of unneccesary private methods on View class
Clean up template tags
Remove dumbass __all__ variables
Remove old 'djangorestframework directories
Change package name: djangorestframework -> rest_framework
Dont strip final '/'
Use get_script_prefix to play nicely if not installed at the root.
...
Conflicts:
rest_framework/decorators.py
Diffstat (limited to 'rest_framework/authentication.py')
| -rw-r--r-- | rest_framework/authentication.py | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/rest_framework/authentication.py b/rest_framework/authentication.py new file mode 100644 index 00000000..fd597397 --- /dev/null +++ b/rest_framework/authentication.py @@ -0,0 +1,132 @@ +""" +The :mod:`authentication` module provides a set of pluggable authentication classes. + +Authentication behavior is provided by mixing the :class:`mixins.RequestMixin` class into a :class:`View` class. +""" + +from django.contrib.auth import authenticate +from rest_framework.compat import CsrfViewMiddleware +from rest_framework.authtoken.models import Token +import base64 + + +class BaseAuthentication(object): + """ + All authentication classes should extend BaseAuthentication. + """ + + def authenticate(self, request): + """ + Authenticate the :obj:`request` and return a :obj:`User` or :const:`None`. [*]_ + + .. [*] The authentication context *will* typically be a :obj:`User`, + but it need not be. It can be any user-like object so long as the + permissions classes (see the :mod:`permissions` module) on the view can + handle the object and use it to determine if the request has the required + permissions or not. + + This can be an important distinction if you're implementing some token + based authentication mechanism, where the authentication context + may be more involved than simply mapping to a :obj:`User`. + """ + return None + + +class BasicAuthentication(BaseAuthentication): + """ + Base class for HTTP Basic authentication. + Subclasses should implement `.authenticate_credentials()`. + """ + + def authenticate(self, request): + """ + Returns a `User` if a correct username and password have been supplied + using HTTP Basic authentication. Otherwise returns `None`. + """ + from django.utils.encoding import smart_unicode, DjangoUnicodeDecodeError + + if 'HTTP_AUTHORIZATION' in request.META: + auth = request.META['HTTP_AUTHORIZATION'].split() + if len(auth) == 2 and auth[0].lower() == "basic": + try: + auth_parts = base64.b64decode(auth[1]).partition(':') + except TypeError: + return None + + try: + userid, password = smart_unicode(auth_parts[0]), smart_unicode(auth_parts[2]) + except DjangoUnicodeDecodeError: + return None + + return self.authenticate_credentials(userid, password) + + def authenticate_credentials(self, userid, password): + """ + Given the Basic authentication userid and password, authenticate + and return a user instance. + """ + raise NotImplementedError('.authenticate_credentials() must be overridden') + + +class UserBasicAuthentication(BasicAuthentication): + def authenticate_credentials(self, userid, password): + """ + Authenticate the userid and password against username and password. + """ + user = authenticate(username=userid, password=password) + if user is not None and user.is_active: + return (user, None) + + +class SessionAuthentication(BaseAuthentication): + """ + Use Django's session framework for authentication. + """ + + def authenticate(self, request): + """ + Returns a :obj:`User` if the request session currently has a logged in user. + Otherwise returns :const:`None`. + """ + user = getattr(request._request, 'user', None) + + if user and user.is_active: + # Enforce CSRF validation for session based authentication. + resp = CsrfViewMiddleware().process_view(request, None, (), {}) + + if resp is None: # csrf passed + return (user, None) + + +class TokenAuthentication(BaseAuthentication): + """ + Simple token based authentication. + + Clients should authenticate by passing the token key in the "Authorization" + HTTP header, prepended with the string "Token ". For example: + + Authorization: Token 401f7ac837da42b97f613d789819ff93537bee6a + """ + + model = Token + """ + A custom token model may be used, but must have the following properties. + + * key -- The string identifying the token + * user -- The user to which the token belongs + """ + + def authenticate(self, request): + auth = request.META.get('HTTP_AUTHORIZATION', '').split() + + if len(auth) == 2 and auth[0].lower() == "token": + key = auth[1] + try: + token = self.model.objects.get(key=key) + except self.model.DoesNotExist: + return None + + if token.user.is_active and not getattr(token, 'revoked', False): + return (token.user, token) + +# TODO: OAuthAuthentication |
