Removed the deprecated-since-1.2 "supports_object_permissions" and "supports_anonymous_user" flags on authentication backends. If you have an authenication backend it now *must* suport these.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@16789 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Alex Gaynor 2011-09-10 21:00:32 +00:00
parent 0609255dd2
commit e130dc3275
5 changed files with 27 additions and 113 deletions

View File

@ -5,8 +5,6 @@ class ModelBackend(object):
""" """
Authenticates against django.contrib.auth.models.User. Authenticates against django.contrib.auth.models.User.
""" """
supports_object_permissions = False
supports_anonymous_user = True
supports_inactive_user = True supports_inactive_user = True
# TODO: Model, login attribute name and password attribute name should be # TODO: Model, login attribute name and password attribute name should be
@ -19,11 +17,13 @@ class ModelBackend(object):
except User.DoesNotExist: except User.DoesNotExist:
return None return None
def get_group_permissions(self, user_obj): def get_group_permissions(self, user_obj, obj=None):
""" """
Returns a set of permission strings that this user has through his/her Returns a set of permission strings that this user has through his/her
groups. groups.
""" """
if user_obj.is_anonymous() or obj is not None:
return set()
if not hasattr(user_obj, '_group_perm_cache'): if not hasattr(user_obj, '_group_perm_cache'):
if user_obj.is_superuser: if user_obj.is_superuser:
perms = Permission.objects.all() perms = Permission.objects.all()
@ -33,18 +33,18 @@ class ModelBackend(object):
user_obj._group_perm_cache = set(["%s.%s" % (ct, name) for ct, name in perms]) user_obj._group_perm_cache = set(["%s.%s" % (ct, name) for ct, name in perms])
return user_obj._group_perm_cache return user_obj._group_perm_cache
def get_all_permissions(self, user_obj): def get_all_permissions(self, user_obj, obj=None):
if user_obj.is_anonymous(): if user_obj.is_anonymous() or obj is not None:
return set() return set()
if not hasattr(user_obj, '_perm_cache'): if not hasattr(user_obj, '_perm_cache'):
user_obj._perm_cache = set([u"%s.%s" % (p.content_type.app_label, p.codename) for p in user_obj.user_permissions.select_related()]) user_obj._perm_cache = set([u"%s.%s" % (p.content_type.app_label, p.codename) for p in user_obj.user_permissions.select_related()])
user_obj._perm_cache.update(self.get_group_permissions(user_obj)) user_obj._perm_cache.update(self.get_group_permissions(user_obj))
return user_obj._perm_cache return user_obj._perm_cache
def has_perm(self, user_obj, perm): def has_perm(self, user_obj, perm, obj=None):
if not user_obj.is_active: if not user_obj.is_active:
return False return False
return perm in self.get_all_permissions(user_obj) return perm in self.get_all_permissions(user_obj, obj)
def has_module_perms(self, user_obj, app_label): def has_module_perms(self, user_obj, app_label):
""" """

View File

@ -132,46 +132,33 @@ class UserManager(models.Manager):
# A few helper functions for common logic between User and AnonymousUser. # A few helper functions for common logic between User and AnonymousUser.
def _user_get_all_permissions(user, obj): def _user_get_all_permissions(user, obj):
permissions = set() permissions = set()
anon = user.is_anonymous()
for backend in auth.get_backends(): for backend in auth.get_backends():
if not anon or backend.supports_anonymous_user: if hasattr(backend, "get_all_permissions"):
if hasattr(backend, "get_all_permissions"): if obj is not None:
if obj is not None: permissions.update(backend.get_all_permissions(user, obj))
if backend.supports_object_permissions: else:
permissions.update( permissions.update(backend.get_all_permissions(user))
backend.get_all_permissions(user, obj)
)
else:
permissions.update(backend.get_all_permissions(user))
return permissions return permissions
def _user_has_perm(user, perm, obj): def _user_has_perm(user, perm, obj):
anon = user.is_anonymous()
active = user.is_active
for backend in auth.get_backends(): for backend in auth.get_backends():
if (not active and not anon and backend.supports_inactive_user) or \ if hasattr(backend, "has_perm"):
(not anon or backend.supports_anonymous_user): if obj is not None:
if hasattr(backend, "has_perm"): if backend.has_perm(user, perm, obj):
if obj is not None:
if (backend.supports_object_permissions and
backend.has_perm(user, perm, obj)):
return True
else:
if backend.has_perm(user, perm):
return True return True
else:
if backend.has_perm(user, perm):
return True
return False return False
def _user_has_module_perms(user, app_label): def _user_has_module_perms(user, app_label):
anon = user.is_anonymous()
active = user.is_active active = user.is_active
for backend in auth.get_backends(): for backend in auth.get_backends():
if (not active and not anon and backend.supports_inactive_user) or \ if hasattr(backend, "has_module_perms"):
(not anon or backend.supports_anonymous_user): if backend.has_module_perms(user, app_label):
if hasattr(backend, "has_module_perms"): return True
if backend.has_module_perms(user, app_label):
return True
return False return False
@ -264,10 +251,7 @@ class User(models.Model):
for backend in auth.get_backends(): for backend in auth.get_backends():
if hasattr(backend, "get_group_permissions"): if hasattr(backend, "get_group_permissions"):
if obj is not None: if obj is not None:
if backend.supports_object_permissions: permissions.update(backend.get_group_permissions(self, obj))
permissions.update(
backend.get_group_permissions(self, obj)
)
else: else:
permissions.update(backend.get_group_permissions(self)) permissions.update(backend.get_group_permissions(self))
return permissions return permissions

View File

@ -1,6 +1,6 @@
from django.contrib.auth.tests.auth_backends import (BackendTest, from django.contrib.auth.tests.auth_backends import (BackendTest,
RowlevelBackendTest, AnonymousUserBackendTest, NoAnonymousUserBackendTest, RowlevelBackendTest, AnonymousUserBackendTest, NoBackendsTest,
NoBackendsTest, InActiveUserBackendTest, NoInActiveUserBackendTest) InActiveUserBackendTest, NoInActiveUserBackendTest)
from django.contrib.auth.tests.basic import BasicTestCase, PasswordUtilsTestCase from django.contrib.auth.tests.basic import BasicTestCase, PasswordUtilsTestCase
from django.contrib.auth.tests.context_processors import AuthContextProcessorTests from django.contrib.auth.tests.context_processors import AuthContextProcessorTests
from django.contrib.auth.tests.decorators import LoginRequiredTestCase from django.contrib.auth.tests.decorators import LoginRequiredTestCase

View File

@ -103,14 +103,12 @@ class TestObj(object):
class SimpleRowlevelBackend(object): class SimpleRowlevelBackend(object):
supports_object_permissions = True
supports_inactive_user = False supports_inactive_user = False
# This class also supports tests for anonymous user permissions, and # This class also supports tests for anonymous user permissions, and
# inactive user permissions via subclasses which just set the # inactive user permissions via subclasses which just set the
# 'supports_anonymous_user' or 'supports_inactive_user' attribute. # 'supports_anonymous_user' or 'supports_inactive_user' attribute.
def has_perm(self, user, perm, obj=None): def has_perm(self, user, perm, obj=None):
if not obj: if not obj:
return # We only support row level perms return # We only support row level perms
@ -119,7 +117,6 @@ class SimpleRowlevelBackend(object):
if user.username == 'test2': if user.username == 'test2':
return True return True
elif user.is_anonymous() and perm == 'anon': elif user.is_anonymous() and perm == 'anon':
# not reached due to supports_anonymous_user = False
return True return True
elif not user.is_active and perm == 'inactive': elif not user.is_active and perm == 'inactive':
return True return True
@ -199,20 +196,12 @@ class RowlevelBackendTest(TestCase):
class AnonymousUserBackend(SimpleRowlevelBackend): class AnonymousUserBackend(SimpleRowlevelBackend):
supports_anonymous_user = True
supports_inactive_user = False
class NoAnonymousUserBackend(SimpleRowlevelBackend):
supports_anonymous_user = False
supports_inactive_user = False supports_inactive_user = False
class AnonymousUserBackendTest(TestCase): class AnonymousUserBackendTest(TestCase):
""" """
Tests for AnonymousUser delegating to backend if it has 'supports_anonymous_user' = True Tests for AnonymousUser delegating to backend.
""" """
backend = 'django.contrib.auth.tests.auth_backends.AnonymousUserBackend' backend = 'django.contrib.auth.tests.auth_backends.AnonymousUserBackend'
@ -241,33 +230,6 @@ class AnonymousUserBackendTest(TestCase):
self.assertEqual(self.user1.get_all_permissions(TestObj()), set(['anon'])) self.assertEqual(self.user1.get_all_permissions(TestObj()), set(['anon']))
class NoAnonymousUserBackendTest(TestCase):
"""
Tests that AnonymousUser does not delegate to backend if it has 'supports_anonymous_user' = False
"""
backend = 'django.contrib.auth.tests.auth_backends.NoAnonymousUserBackend'
def setUp(self):
self.curr_auth = settings.AUTHENTICATION_BACKENDS
settings.AUTHENTICATION_BACKENDS = tuple(self.curr_auth) + (self.backend,)
self.user1 = AnonymousUser()
def tearDown(self):
settings.AUTHENTICATION_BACKENDS = self.curr_auth
def test_has_perm(self):
self.assertEqual(self.user1.has_perm('perm', TestObj()), False)
self.assertEqual(self.user1.has_perm('anon', TestObj()), False)
def test_has_perms(self):
self.assertEqual(self.user1.has_perms(['anon'], TestObj()), False)
def test_has_module_perms(self):
self.assertEqual(self.user1.has_module_perms("app1"), False)
self.assertEqual(self.user1.has_module_perms("app2"), False)
def test_get_all_permissions(self):
self.assertEqual(self.user1.get_all_permissions(TestObj()), set())
class NoBackendsTest(TestCase): class NoBackendsTest(TestCase):
@ -287,14 +249,10 @@ class NoBackendsTest(TestCase):
class InActiveUserBackend(SimpleRowlevelBackend): class InActiveUserBackend(SimpleRowlevelBackend):
supports_anonymous_user = False
supports_inactive_user = True supports_inactive_user = True
class NoInActiveUserBackend(SimpleRowlevelBackend): class NoInActiveUserBackend(SimpleRowlevelBackend):
supports_anonymous_user = False
supports_inactive_user = False supports_inactive_user = False

View File

@ -1633,8 +1633,6 @@ object the first time a user authenticates::
ADMIN_PASSWORD = 'sha1$4e987$afbcf42e21bd417fb71db8c66b321e9fc33051de' ADMIN_PASSWORD = 'sha1$4e987$afbcf42e21bd417fb71db8c66b321e9fc33051de'
""" """
supports_object_permissions = False
supports_anonymous_user = False
supports_inactive_user = False supports_inactive_user = False
def authenticate(self, username=None, password=None): def authenticate(self, username=None, password=None):
@ -1683,7 +1681,7 @@ fairly simply::
# ... # ...
def has_perm(self, user_obj, perm): def has_perm(self, user_obj, perm, obj=None):
if user_obj.username == settings.ADMIN_LOGIN: if user_obj.username == settings.ADMIN_LOGIN:
return True return True
else: else:
@ -1720,19 +1718,6 @@ for the authors of re-usable apps, who can delegate all questions of authorizati
to the auth backend, rather than needing settings, for example, to control to the auth backend, rather than needing settings, for example, to control
anonymous access. anonymous access.
To enable this in your own backend, you must set the class attribute
``supports_anonymous_user`` to ``True``. (This precaution is to maintain
compatibility with backends that assume that all user objects are actual
instances of the :class:`django.contrib.auth.models.User` class). With this
in place, :class:`django.contrib.auth.models.AnonymousUser` will delegate all
the relevant permission methods to the authentication backends.
A nonexistent ``supports_anonymous_user`` attribute will raise a hidden
``PendingDeprecationWarning`` if used in Django 1.2. In Django 1.3, this
warning will be upgraded to a ``DeprecationWarning``, which will be displayed
loudly. Additionally ``supports_anonymous_user`` will be set to ``False``.
Django 1.4 will assume that every backend supports anonymous users being
passed to the authorization methods.
Authorization for inactive users Authorization for inactive users
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -1765,17 +1750,4 @@ Handling object permissions
Django's permission framework has a foundation for object permissions, though Django's permission framework has a foundation for object permissions, though
there is no implementation for it in the core. That means that checking for there is no implementation for it in the core. That means that checking for
object permissions will always return ``False`` or an empty list (depending on object permissions will always return ``False`` or an empty list (depending on
the check performed). the check performed).
To enable object permissions in your own
:doc:`authentication backend </ref/authbackends>` you'll just have
to allow passing an ``obj`` parameter to the permission methods and set the
``supports_object_permissions`` class attribute to ``True``.
A nonexistent ``supports_object_permissions`` will raise a hidden
``PendingDeprecationWarning`` if used in Django 1.2. In Django 1.3, this
warning will be upgraded to a ``DeprecationWarning``, which will be displayed
loudly. Additionally ``supports_object_permissions`` will be set to ``False``.
Django 1.4 will assume that every backend supports object permissions and
won't check for the existence of ``supports_object_permissions``, which
means not supporting ``obj`` as a parameter will raise a ``TypeError``.