# HG changeset patch # User verrierj # Date 1326290253 -3600 # Node ID c6953232099f6ed71d38e5981538b6d4de0a8aed # Parent 271235724f542f0bef94df6059ca6e46db191aec Anonymous users can see pages even if they are not logged in + factor code to decrease number of SQL requests diff -r 271235724f54 -r c6953232099f src/ldt/ldt/security/__init__.py --- 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) + diff -r 271235724f54 -r c6953232099f src/ldt/ldt/security/manager.py --- 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 diff -r 271235724f54 -r c6953232099f src/ldt/ldt/security/middleware.py --- 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 diff -r 271235724f54 -r c6953232099f src/ldt/ldt/security/models.py --- 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 diff -r 271235724f54 -r c6953232099f src/ldt/ldt/security/utils.py --- 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')