diff rhodecode/lib/auth.py @ 673:dd532af216d9 beta

#49 Enabled anonymous access for web interface controllable from permissions pannel
author Marcin Kuzminski <marcin@python-works.com>
date Thu, 11 Nov 2010 01:05:43 +0100
parents 7e536d1af60d
children 99875a8f2ad1
line wrap: on
line diff
--- a/rhodecode/lib/auth.py	Tue Nov 09 22:53:24 2010 +0100
+++ b/rhodecode/lib/auth.py	Thu Nov 11 01:05:43 2010 +0100
@@ -26,15 +26,16 @@
 from pylons.controllers.util import abort, redirect
 from rhodecode.lib.utils import get_repo_slug
 from rhodecode.model import meta
+from rhodecode.model.user import UserModel
 from rhodecode.model.caching_query import FromCache
 from rhodecode.model.db import User, RepoToPerm, Repository, Permission, \
-    UserToPerm    
+    UserToPerm
 import bcrypt
 from decorator import decorator
 import logging
 import random
 
-log = logging.getLogger(__name__) 
+log = logging.getLogger(__name__)
 
 class PasswordGenerator(object):
     """This is a simple class for generating password from
@@ -53,7 +54,7 @@
     ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
     ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM#[6]
     ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM#[7]
-            
+
     def __init__(self, passwd=''):
         self.passwd = passwd
 
@@ -61,20 +62,19 @@
         self.passwd = ''.join([random.choice(type) for _ in xrange(len)])
         return self.passwd
 
-    
+
 def get_crypt_password(password):
     """Cryptographic function used for password hashing based on sha1
     :param password: password to hash
-    """    
+    """
     return bcrypt.hashpw(password, bcrypt.gensalt(10))
 
 def check_password(password, hashed):
     return bcrypt.hashpw(password, hashed) == hashed
 
 def authfunc(environ, username, password):
-    from rhodecode.model.user import UserModel
     user = UserModel().get_by_username(username, cache=False)
-            
+
     if user:
         if user.active:
             if user.username == username and check_password(password, user.password):
@@ -82,7 +82,7 @@
                 return True
         else:
             log.error('user %s is disabled', username)
-            
+
     return False
 
 class  AuthUser(object):
@@ -99,6 +99,8 @@
         self.is_admin = False
         self.permissions = {}
 
+    def __repr__(self):
+        return "<AuthUser('id:%s:%s')>" % (self.user_id, self.username)
 
 def set_available_permissions(config):
     """
@@ -116,85 +118,56 @@
         pass
     finally:
         meta.Session.remove()
-    
+
     config['available_permissions'] = [x.permission_name for x in all_perms]
 
 def set_base_path(config):
     config['base_path'] = config['pylons.app_globals'].base_path
 
-def fill_data(user):
-    """
-    Fills user data with those from database and log out user if not present
-    in database
-    :param user:
-    """
-    sa = meta.Session()
-    try:
-        dbuser = sa.query(User)\
-        .options(FromCache('sql_cache_short', 'getuser_%s' % user.user_id))\
-        .get(user.user_id)
-    except:
-        pass
-    finally:
-        meta.Session.remove()
-        
-    if dbuser:
-        user.username = dbuser.username
-        user.is_admin = dbuser.admin
-        user.name = dbuser.name
-        user.lastname = dbuser.lastname
-        user.email = dbuser.email
-    else:
-        user.is_authenticated = False
-        
-    
-    return user
-            
+
 def fill_perms(user):
     """
     Fills user permission attribute with permissions taken from database
     :param user:
     """
-    
+
     sa = meta.Session()
     user.permissions['repositories'] = {}
     user.permissions['global'] = set()
-    
+
     #===========================================================================
     # fetch default permissions
     #===========================================================================
-    default_user = sa.query(User)\
-        .options(FromCache('sql_cache_short', 'getuser_%s' % 'default'))\
-        .filter(User.username == 'default').scalar()
-                                            
+    default_user = UserModel(sa).get_by_username('default', cache=True)
+
     default_perms = sa.query(RepoToPerm, Repository, Permission)\
         .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
         .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
         .filter(RepoToPerm.user == default_user).all()
-                                            
+
     if user.is_admin:
         #=======================================================================
         # #admin have all default rights set to admin        
         #=======================================================================
         user.permissions['global'].add('hg.admin')
-        
+
         for perm in default_perms:
             p = 'repository.admin'
             user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
-    
+
     else:
         #=======================================================================
         # set default permissions
         #=======================================================================
-        
+
         #default global
         default_global_perms = sa.query(UserToPerm)\
-            .filter(UserToPerm.user == sa.query(User).filter(User.username == 
+            .filter(UserToPerm.user == sa.query(User).filter(User.username ==
             'default').one())
-        
+
         for perm in default_global_perms:
             user.permissions['global'].add(perm.permission.permission_name)
-                    
+
         #default repositories
         for perm in default_perms:
             if perm.Repository.private and not perm.Repository.user_id == user.user_id:
@@ -205,9 +178,9 @@
                 p = 'repository.admin'
             else:
                 p = perm.Permission.permission_name
-                
+
             user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
-                                                
+
         #=======================================================================
         # #overwrite default with user permissions if any
         #=======================================================================
@@ -215,38 +188,52 @@
             .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
             .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
             .filter(RepoToPerm.user_id == user.user_id).all()
-            
+
         for perm in user_perms:
             if perm.Repository.user_id == user.user_id:#set admin if owner
                 p = 'repository.admin'
             else:
                 p = perm.Permission.permission_name
             user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
-    meta.Session.remove()         
+    meta.Session.remove()
     return user
-    
+
 def get_user(session):
     """
     Gets user from session, and wraps permissions into user
     :param session:
     """
     user = session.get('rhodecode_user', AuthUser())
+
+
+    #if the user is not logged in we check for anonymous access
+    #if user is logged and it's a default user check if we still have anonymous
+    #access enabled
+    if user.user_id is None or user.username == 'default':
+        anonymous_user = UserModel().get_by_username('default', cache=True)
+        if anonymous_user.active is True:
+            #then we set this user is logged in
+            user.is_authenticated = True
+        else:
+            user.is_authenticated = False
+
     if user.is_authenticated:
-        user = fill_data(user)
+        user = UserModel().fill_data(user)
+
     user = fill_perms(user)
     session['rhodecode_user'] = user
     session.save()
     return user
-        
+
 #===============================================================================
 # CHECK DECORATORS
 #===============================================================================
 class LoginRequired(object):
     """Must be logged in to execute this function else redirect to login page"""
-   
+
     def __call__(self, func):
         return decorator(self.__wrapper, func)
-    
+
     def __wrapper(self, func, *fargs, **fkwargs):
         user = session.get('rhodecode_user', AuthUser())
         log.debug('Checking login required for user:%s', user.username)
@@ -255,21 +242,21 @@
             return func(*fargs, **fkwargs)
         else:
             log.warn('user %s not authenticated', user.username)
-            
+
             p = ''
             if request.environ.get('SCRIPT_NAME') != '/':
                 p += request.environ.get('SCRIPT_NAME')
-                
+
             p += request.environ.get('PATH_INFO')
             if request.environ.get('QUERY_STRING'):
                 p += '?' + request.environ.get('QUERY_STRING')
-                
-            log.debug('redirecting to login page with %s', p)                
+
+            log.debug('redirecting to login page with %s', p)
             return redirect(url('login_home', came_from=p))
 
 class PermsDecorator(object):
     """Base class for decorators"""
-    
+
     def __init__(self, *required_perms):
         available_perms = config['available_permissions']
         for perm in required_perms:
@@ -277,32 +264,33 @@
                 raise Exception("'%s' permission is not defined" % perm)
         self.required_perms = set(required_perms)
         self.user_perms = None
-        
+
     def __call__(self, func):
         return decorator(self.__wrapper, func)
-    
-    
+
+
     def __wrapper(self, func, *fargs, **fkwargs):
 #        _wrapper.__name__ = func.__name__
 #        _wrapper.__dict__.update(func.__dict__)
 #        _wrapper.__doc__ = func.__doc__
+        self.user = session.get('rhodecode_user', AuthUser())
+        self.user_perms = self.user.permissions
+        log.debug('checking %s permissions %s for %s %s',
+           self.__class__.__name__, self.required_perms, func.__name__,
+               self.user)
 
-        self.user_perms = session.get('rhodecode_user', AuthUser()).permissions
-        log.debug('checking %s permissions %s for %s',
-           self.__class__.__name__, self.required_perms, func.__name__)
-        
         if self.check_permissions():
-            log.debug('Permission granted for %s', func.__name__)
-            
+            log.debug('Permission granted for %s %s', func.__name__, self.user)
+
             return func(*fargs, **fkwargs)
-        
+
         else:
-            log.warning('Permission denied for %s', func.__name__)
+            log.warning('Permission denied for %s %s', func.__name__, self.user)
             #redirect with forbidden ret code
             return abort(403)
 
-        
-        
+
+
     def check_permissions(self):
         """Dummy function for overriding"""
         raise Exception('You have to write this function in child class')
@@ -311,18 +299,18 @@
     """Checks for access permission for all given predicates. All of them 
     have to be meet in order to fulfill the request
     """
-        
+
     def check_permissions(self):
         if self.required_perms.issubset(self.user_perms.get('global')):
             return True
         return False
-            
+
 
 class HasPermissionAnyDecorator(PermsDecorator):
     """Checks for access permission for any of given predicates. In order to 
     fulfill the request any of predicates must be meet
     """
-    
+
     def check_permissions(self):
         if self.required_perms.intersection(self.user_perms.get('global')):
             return True
@@ -332,7 +320,7 @@
     """Checks for access permission for all given predicates for specific 
     repository. All of them have to be meet in order to fulfill the request
     """
-            
+
     def check_permissions(self):
         repo_name = get_repo_slug(request)
         try:
@@ -342,16 +330,16 @@
         if self.required_perms.issubset(user_perms):
             return True
         return False
-            
+
 
 class HasRepoPermissionAnyDecorator(PermsDecorator):
     """Checks for access permission for any of given predicates for specific 
     repository. In order to fulfill the request any of predicates must be meet
     """
-            
+
     def check_permissions(self):
         repo_name = get_repo_slug(request)
-        
+
         try:
             user_perms = set([self.user_perms['repositories'][repo_name]])
         except KeyError:
@@ -365,10 +353,10 @@
 
 class PermsFunction(object):
     """Base function for other check functions"""
-    
+
     def __init__(self, *perms):
         available_perms = config['available_permissions']
-        
+
         for perm in perms:
             if perm not in available_perms:
                 raise Exception("'%s' permission in not defined" % perm)
@@ -376,29 +364,30 @@
         self.user_perms = None
         self.granted_for = ''
         self.repo_name = None
-        
+
     def __call__(self, check_Location=''):
         user = session.get('rhodecode_user', False)
         if not user:
             return False
         self.user_perms = user.permissions
-        self.granted_for = user.username        
-        log.debug('checking %s %s', self.__class__.__name__, self.required_perms)            
-        
+        self.granted_for = user.username
+        log.debug('checking %s %s %s', self.__class__.__name__,
+                  self.required_perms, user)
+
         if self.check_permissions():
-            log.debug('Permission granted for %s @%s', self.granted_for,
-                      check_Location)
+            log.debug('Permission granted for %s @ %s %s', self.granted_for,
+                      check_Location, user)
             return True
-        
+
         else:
-            log.warning('Permission denied for %s @%s', self.granted_for,
-                        check_Location)
-            return False 
-    
+            log.warning('Permission denied for %s @ %s %s', self.granted_for,
+                        check_Location, user)
+            return False
+
     def check_permissions(self):
         """Dummy function for overriding"""
         raise Exception('You have to write this function in child class')
-        
+
 class HasPermissionAll(PermsFunction):
     def check_permissions(self):
         if self.required_perms.issubset(self.user_perms.get('global')):
@@ -412,11 +401,11 @@
         return False
 
 class HasRepoPermissionAll(PermsFunction):
-    
+
     def __call__(self, repo_name=None, check_Location=''):
         self.repo_name = repo_name
         return super(HasRepoPermissionAll, self).__call__(check_Location)
-            
+
     def check_permissions(self):
         if not self.repo_name:
             self.repo_name = get_repo_slug(request)
@@ -426,17 +415,17 @@
                                    [self.repo_name]])
         except KeyError:
             return False
-        self.granted_for = self.repo_name       
+        self.granted_for = self.repo_name
         if self.required_perms.issubset(self.user_perms):
             return True
         return False
-            
+
 class HasRepoPermissionAny(PermsFunction):
-    
+
     def __call__(self, repo_name=None, check_Location=''):
         self.repo_name = repo_name
         return super(HasRepoPermissionAny, self).__call__(check_Location)
-        
+
     def check_permissions(self):
         if not self.repo_name:
             self.repo_name = get_repo_slug(request)
@@ -458,13 +447,13 @@
 class HasPermissionAnyMiddleware(object):
     def __init__(self, *perms):
         self.required_perms = set(perms)
-    
+
     def __call__(self, user, repo_name):
         usr = AuthUser()
         usr.user_id = user.user_id
         usr.username = user.username
         usr.is_admin = user.admin
-        
+
         try:
             self.user_perms = set([fill_perms(usr)\
                                    .permissions['repositories'][repo_name]])
@@ -472,9 +461,9 @@
             self.user_perms = set()
         self.granted_for = ''
         self.username = user.username
-        self.repo_name = repo_name        
+        self.repo_name = repo_name
         return self.check_permissions()
-            
+
     def check_permissions(self):
         log.debug('checking mercurial protocol '
                   'permissions for user:%s repository:%s',