Permalink
Browse files

BACKWARD-INCOMPATIBLE: ``Authentication`` classes now require users t…

…o be ``is_active = True``.

This can be disabled to work the old way. Please see the documentation for an example.
  • Loading branch information...
toastdriven committed Jun 26, 2012
1 parent 7175815 commit a57d85b77b65099a077b5aab795e6cfb47617cb8
@@ -1 +1,2 @@
[2012-05-04] AutoFields will now serialize and deserialize as Integers
+[2012-06-26] ``Authentication`` classes now require ``User.is_active = True``
@@ -43,6 +43,21 @@ Authentication Options
Tastypie ships with the following ``Authentication`` classes:
+.. warning:
+
+ Tastypie, when used with ``django.contrib.auth.models.User``, will check
+ to ensure that the ``User.is_active = True`` by default.
+
+ You can disable this behavior by initializing your ``Authentication`` class
+ with ``require_active=False``::
+
+ class UserResource(ModelResource):
+ class Meta:
+ # ...
+ authentication = BasicAuthentication(require_active=False)
+
+ *The behavior changed to active-by-default in v0.9.12.*
+
``Authentication``
~~~~~~~~~~~~~~~~~~
View
@@ -37,6 +37,9 @@ class Authentication(object):
By default, this indicates the user is always authenticated.
"""
+ def __init__(self, require_active=True):
+ self.require_active = require_active
+
def is_authenticated(self, request, **kwargs):
"""
Identifies if the user is authenticated to continue or not.
@@ -54,6 +57,18 @@ def get_identifier(self, request):
"""
return "%s_%s" % (request.META.get('REMOTE_ADDR', 'noaddr'), request.META.get('REMOTE_HOST', 'nohost'))
+ def check_active(self, user):
+ """
+ Ensures the user has an active account.
+
+ Optimized for the ``django.contrib.auth.models.User`` case.
+ """
+ if not self.require_active:
+ # Ignore & move on.
+ return True
+
+ return user.is_active
+
class BasicAuthentication(Authentication):
"""
@@ -71,7 +86,8 @@ class BasicAuthentication(Authentication):
The realm to use in the ``HttpUnauthorized`` response. Default:
``django-tastypie``.
"""
- def __init__(self, backend=None, realm='django-tastypie'):
+ def __init__(self, backend=None, realm='django-tastypie', **kwargs):
+ super(BasicAuthentication, self).__init__(**kwargs)
self.backend = backend
self.realm = realm
@@ -113,6 +129,9 @@ def is_authenticated(self, request, **kwargs):
if user is None:
return self._unauthorized()
+ if not self.check_active(user):
+ return False
+
request.user = user
return True
@@ -172,6 +191,9 @@ def is_authenticated(self, request, **kwargs):
except (User.DoesNotExist, User.MultipleObjectsReturned):
return self._unauthorized()
+ if not self.check_active(user):
+ return False
+
request.user = user
return self.get_key(user, api_key)
@@ -216,7 +238,8 @@ class DigestAuthentication(Authentication):
The realm to use in the ``HttpUnauthorized`` response. Default:
``django-tastypie``.
"""
- def __init__(self, backend=None, realm='django-tastypie'):
+ def __init__(self, backend=None, realm='django-tastypie', **kwargs):
+ super(DigestAuthentication, self).__init__(**kwargs)
self.backend = backend
self.realm = realm
@@ -268,6 +291,9 @@ def is_authenticated(self, request, **kwargs):
if not digest_response.response == expected:
return self._unauthorized()
+ if not self.check_active(user):
+ return False
+
request.user = user
return True
@@ -319,8 +345,8 @@ class OAuthAuthentication(Authentication):
This does *NOT* provide OAuth authentication in your API, strictly
consumption.
"""
- def __init__(self):
- super(OAuthAuthentication, self).__init__()
+ def __init__(self, **kwargs):
+ super(OAuthAuthentication, self).__init__(**kwargs)
if oauth2 is None:
raise ImproperlyConfigured("The 'python-oauth2' package could not be imported. It is required for use with the 'OAuthAuthentication' class.")
@@ -346,6 +372,9 @@ def is_authenticated(self, request, **kwargs):
return oauth_provider.utils.send_oauth_error(e)
if consumer and token:
+ if not self.check_active(token.user):
+ return False
+
request.user = token.user
return True
@@ -359,6 +388,7 @@ def is_in(self, params):
provided ``params``.
"""
from oauth_provider.consts import OAUTH_PARAMETERS_NAMES
+
for param_name in OAUTH_PARAMETERS_NAMES:
if param_name not in params:
return False
@@ -383,7 +413,8 @@ class MultiAuthentication(object):
"""
An authentication backend that tries a number of backends in order.
"""
- def __init__(self, *backends):
+ def __init__(self, *backends, **kwargs):
+ super(MultiAuthentication, self).__init__(**kwargs)
self.backends = backends
def is_authenticated(self, request, **kwargs):
@@ -17,7 +17,17 @@
"model": "auth.user",
"pk": 2
},
-
+ {
+ "fields": {
+ "username": "bobdoe",
+ "email": "bob@doe.com",
+ "password": "ghi789",
+ "is_active": false
+ },
+ "model": "auth.user",
+ "pk": 3
+ },
+
{
"fields": {
"author": 1,
@@ -96,7 +106,7 @@
"model": "core.note",
"pk": 6
},
-
+
{
"fields": {
"note": 1,
Oops, something went wrong.

0 comments on commit a57d85b

Please sign in to comment.