Anonymous users can see pages even if they are not logged in + factor code to decrease number of SQL requests
authorverrierj
Wed, 11 Jan 2012 14:57:33 +0100
changeset 350 c6953232099f
parent 347 271235724f54
child 351 74f898bd0983
Anonymous users can see pages even if they are not logged in + factor code to decrease number of SQL requests
src/ldt/ldt/security/__init__.py
src/ldt/ldt/security/manager.py
src/ldt/ldt/security/middleware.py
src/ldt/ldt/security/models.py
src/ldt/ldt/security/utils.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)
+
--- 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')