Anonymous users can see pages even if they are not logged in + factor code to decrease number of SQL requests
--- a/src/ldt/ldt/security/__init__.py Wed Jan 11 10:56:43 2012 +0100
+++ b/src/ldt/ldt/security/__init__.py Wed Jan 11 14:57:33 2012 +0100
@@ -0,0 +1,99 @@
+from django.conf import settings
+from django.contrib.contenttypes.models import ContentType
+from django.contrib.auth.models import User
+from django.core.signals import request_started
+
+try:
+ from threading import local
+except ImportError:
+ from django.utils._threading_local import local
+
+_thread_locals = local()
+
+# The function that protect models is called on the first
+# HTTP request sent to the server (see function protect_models_request
+# in this file), and can not be called in this file directly
+# because of circular import.
+#
+# To protect models from command line, use set_current_user(my_user)
+# and protect_models().
+
+_models_are_protected = False
+
+def get_current_user():
+ return getattr(_thread_locals, 'user', None)
+
+def set_current_user(user):
+ _thread_locals.user = user
+
+def del_current_user():
+ del _thread_locals.user
+
+def get_anonymous_user():
+ if hasattr(get_anonymous_user, 'anonymous_user'):
+ return get_anonymous_user.anonymous_user
+
+ get_anonymous_user.anonymous_user = User.objects.get(id=settings.ANONYMOUS_USER_ID)
+ return get_anonymous_user.anonymous_user
+
+def protect_models():
+ cls_list = get_models_to_protect()
+ if cls_list:
+ for cls in get_models_to_protect():
+ protect_model(cls)
+
+ _models_are_protected = True
+
+def unprotect_models():
+ for cls in get_models_to_protect():
+ unprotect_model(cls)
+
+ _models_are_protected = False
+
+def get_models_to_protect():
+ if hasattr(get_models_to_protect, 'cls_list'):
+ return get_models_to_protect.cls_list
+
+ cls_list = []
+ for cls_name in settings.USE_GROUP_PERMISSIONS:
+ cls_type = ContentType.objects.get(model=cls_name.lower())
+ cls_list.append(cls_type.model_class())
+ get_models_to_protect.cls_list = cls_list
+
+ return cls_list
+
+def protect_model(cls):
+
+ cls.old_save = cls.save
+ cls.old_delete = cls.delete
+ class_name = cls.__name__.lower()
+ cls.save = change_security(class_name)(cls.save)
+ cls.delete = change_security(class_name)(cls.delete)
+
+def unprotect_model(cls):
+ if hasattr(cls, 'old_save'):
+ cls.save = cls.old_save
+ cls.delete = cls.old_delete
+ del cls.old_save
+ del cls.old_delete
+ cls.safe_objects.user = None
+ cls.safe_objects.check_perm = False
+
+def change_security(cls_name):
+ def wrapper(func):
+ def wrapped(self, *args, **kwargs):
+
+ if self.pk and not get_current_user().has_perm('change_%s' % cls_name, self):
+ raise AttributeError('User %s is not allowed to change object %s' % (get_current_user(), self))
+
+ return func(self, *args, **kwargs)
+ return wrapped
+ return wrapper
+
+
+def protect_models_request(sender, **kwargs):
+ if not _models_are_protected:
+ protect_models()
+
+request_started.connect(protect_models_request)
+
--- a/src/ldt/ldt/security/manager.py Wed Jan 11 10:56:43 2012 +0100
+++ b/src/ldt/ldt/security/manager.py Wed Jan 11 14:57:33 2012 +0100
@@ -1,6 +1,6 @@
from django.db.models import Manager
from guardian.shortcuts import get_objects_for_user
-from utils import get_current_user
+from ldt.security import get_current_user, get_anonymous_user
class SafeManager(Manager):
use_for_related_fields = True
@@ -11,17 +11,21 @@
self.check_perm = check_perm
def get_query_set(self):
+
if not self.check_perm:
return super(SafeManager, self).get_query_set()
-
+
if not self.user:
- self.user = get_current_user()
-
+ self.user = get_current_user()
+
if not self.user:
raise AttributeError("No user is attached to the current thread.")
+ if not self.user.is_authenticated():
+ self.user = get_anonymous_user()
+
perm_name = '%s.view_%s' % (self.model._meta.app_label, self.model.__name__.lower())
user_objects = get_objects_for_user(self.user, perm_name, klass=self.model.objects)
-
+
return user_objects
\ No newline at end of file
--- a/src/ldt/ldt/security/middleware.py Wed Jan 11 10:56:43 2012 +0100
+++ b/src/ldt/ldt/security/middleware.py Wed Jan 11 14:57:33 2012 +0100
@@ -1,16 +1,14 @@
-from ldt.security.utils import protect_models, unprotect_models, _thread_locals, set_current_user, del_current_user
+from ldt.security import set_current_user, del_current_user, _thread_locals
class SecurityMiddleware(object):
def process_request(self, request):
if not hasattr(_thread_locals, 'user'):
set_current_user(request.user)
- protect_models()
def process_response(self, request, response):
if hasattr(_thread_locals, 'user'):
- unprotect_models()
del_current_user()
return response
--- a/src/ldt/ldt/security/models.py Wed Jan 11 10:56:43 2012 +0100
+++ b/src/ldt/ldt/security/models.py Wed Jan 11 14:57:33 2012 +0100
@@ -2,8 +2,8 @@
from manager import SafeManager
class SafeModel(models.Model):
- objects = SafeManager() # By default, SafeManagers do not chek permissions.
- safe_objects = SafeManager() # This setting is activated in the middleware
+ objects = SafeManager()
+ safe_objects = SafeManager(check_perm=True)
class Meta:
abstract = True
\ No newline at end of file
--- a/src/ldt/ldt/security/utils.py Wed Jan 11 10:56:43 2012 +0100
+++ b/src/ldt/ldt/security/utils.py Wed Jan 11 14:57:33 2012 +0100
@@ -2,65 +2,9 @@
from django.contrib.contenttypes.models import ContentType
from guardian.shortcuts import assign, remove_perm, get_users_with_perms, get_groups_with_perms, get_objects_for_user
from cache import get_cached_userlist
+from ldt.security import change_security
import types
-
-try:
- from threading import local
-except ImportError:
- from django.utils._threading_local import local
-
-_thread_locals = local()
-
-def get_current_user():
- return getattr(_thread_locals, 'user', None)
-
-def set_current_user(user):
- _thread_locals.user = user
-
-def del_current_user():
- del _thread_locals.user
-
-def protect_models():
- cls_list = get_models_to_protect()
- if cls_list:
- user = get_current_user()
- for cls in get_models_to_protect():
- protect_model(cls, user)
-
-def unprotect_models():
- for cls in get_models_to_protect():
- unprotect_model(cls)
-
-def get_models_to_protect():
- if hasattr(get_models_to_protect, 'cls_list'):
- return get_models_to_protect.cls_list
-
- cls_list = []
- for cls_name in settings.USE_GROUP_PERMISSIONS:
- cls_type = ContentType.objects.get(model=cls_name.lower())
- cls_list.append(cls_type.model_class())
- get_models_to_protect.cls_list = cls_list
-
- return cls_list
-
-def protect_model(cls, user):
- cls.safe_objects.user = user
- cls.safe_objects.check_perm = True
-
- cls.old_save = cls.save
- cls.old_delete = cls.delete
- class_name = cls.__name__.lower()
- cls.save = change_security(class_name)(cls.save)
- cls.delete = change_security(class_name)(cls.delete)
-
-def unprotect_model(cls):
- if hasattr(cls, 'old_save'):
- cls.save = cls.old_save
- cls.delete = cls.old_delete
- del cls.old_save
- del cls.old_delete
- cls.safe_objects.user = None
-
+
def unprotect_instance(instance):
if hasattr(instance, 'old_save'):
instance.save = instance.old_save
@@ -77,16 +21,6 @@
delete = types.MethodType(change_security('project')(cls.delete), instance, cls)
instance.delete = delete
-def change_security(cls_name):
- def wrapper(func):
- def wrapped(self, *args, **kwargs):
-
- if self.pk and not get_current_user().has_perm('change_%s' % cls_name, self):
- raise AttributeError('User %s is not allowed to change object %s' % (get_current_user(), self))
-
- return func(self, *args, **kwargs)
- return wrapped
- return wrapper
def set_forbidden_stream(xml, user):
cls = ContentType.objects.get(model='content')