Skip to content

Instantly share code, notes, and snippets.

@ScottEAdams
Last active December 20, 2015 22:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ScottEAdams/6209642 to your computer and use it in GitHub Desktop.
Save ScottEAdams/6209642 to your computer and use it in GitHub Desktop.
Two similar ways for doing email based authentication for tastypie. Based on a mixture of BasicAuthentication and userena email login. Good for when using USERENA_WITHOUT_USERNAMES = True.
import base64
from django.contrib.auth import get_user_model, authenticate
from django.core.exceptions import ValidationError
from django.core.validators import validate_email
from tastypie.authentication import Authentication
from tastypie.http import HttpUnauthorized
class TastyEmailAuthentication(Authentication):
def __init__(self, realm='django-tastypie', **kwargs):
super(TastyEmailAuthentication, self).__init__(**kwargs)
self.realm = realm
def _unauthorized(self):
response = HttpUnauthorized()
# FIXME: Sanitize realm.
response['WWW-Authenticate'] = 'Basic Realm="%s"' % self.realm
return response
def is_authenticated(self, request, **kwargs):
"""
Checks a user's basic auth credentials using email address.
Should return either ``True`` if allowed, ``False`` if not or an
``HttpResponse`` if you need something custom.
"""
if not request.META.get('HTTP_AUTHORIZATION'):
return self._unauthorized()
try:
(auth_type, data) = request.META['HTTP_AUTHORIZATION'].split()
if auth_type.lower() != 'basic':
return self._unauthorized()
user_pass = base64.b64decode(data).decode('utf-8')
except:
return self._unauthorized()
bits = user_pass.split(':', 1)
if len(bits) != 2:
return self._unauthorized()
User = get_user_model()
try:
validate_email(bits[0])
try:
user = User.objects.get(email__iexact=bits[0])
if not self.check_active(user):
return False
if user.check_password(bits[1]):
request.user = user
return True
else:
return self._unauthorized()
except User.DoesNotExist:
return self._unauthorized()
except ValidationError:
return self._unauthorized()
class BasicEmailAuthentication(Authentication):
"""
Handles HTTP Basic auth against a specific auth backend if provided,
or against all configured authentication backends using the
``authenticate`` method from ``django.contrib.auth``.
Optional keyword arguments:
``backend``
If specified, use a specific ``django.contrib.auth`` backend instead
of checking all backends specified in the ``AUTHENTICATION_BACKENDS``
setting.
``realm``
The realm to use in the ``HttpUnauthorized`` response. Default:
``django-tastypie``.
"""
def __init__(self, backend=None, realm='django-tastypie', **kwargs):
super(BasicEmailAuthentication, self).__init__(**kwargs)
self.backend = backend
self.realm = realm
def _unauthorized(self):
response = HttpUnauthorized()
# FIXME: Sanitize realm.
response['WWW-Authenticate'] = 'Basic Realm="%s"' % self.realm
return response
def is_authenticated(self, request, **kwargs):
"""
Checks a user's basic auth credentials against the current
Django auth backend.
Should return either ``True`` if allowed, ``False`` if not or an
``HttpResponse`` if you need something custom.
"""
if not request.META.get('HTTP_AUTHORIZATION'):
return self._unauthorized()
try:
(auth_type, data) = request.META['HTTP_AUTHORIZATION'].split()
if auth_type.lower() != 'basic':
return self._unauthorized()
user_pass = base64.b64decode(data).decode('utf-8')
except:
return self._unauthorized()
bits = user_pass.split(':', 1)
if len(bits) != 2:
return self._unauthorized()
User = get_user_model()
try:
validate_email(bits[0])
try:
email_user = User.objects.get(email__iexact=bits[0])
username = email_user.username
if self.backend:
user = self.backend.authenticate(username=username, password=bits[1])
else:
user = authenticate(username=username, password=bits[1])
if user is None:
return self._unauthorized()
if not self.check_active(user):
return False
request.user = user
return True
except User.DoesNotExist:
return self._unauthorized()
except ValidationError:
return self._unauthorized()
def get_identifier(self, request):
"""
Provides a unique string identifier for the requestor.
This implementation returns the user's basic auth username.
"""
return request.META.get('REMOTE_USER', 'nouser')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment