changeset 1623:b7094c69979e beta

Merged in liads/rhodecode (pull request #14)
author Marcin Kuzminski <marcin@python-works.com>
date Mon, 31 Oct 2011 19:10:21 +0200
parents 5cb398de935e (current diff) d58e514c0a39 (diff)
children 69cd66071f02
files
diffstat 7 files changed, 123 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/rhodecode/config/deployment.ini_tmpl	Sun Oct 30 20:30:24 2011 +0200
+++ b/rhodecode/config/deployment.ini_tmpl	Mon Oct 31 19:10:21 2011 +0200
@@ -53,6 +53,8 @@
 force_https = false 
 commit_parse_limit = 50
 use_gravatar = true
+container_auth_enabled = false
+proxypass_auth_enabled = false
 
 ####################################
 ###        CELERY CONFIG        ####
--- a/rhodecode/lib/auth.py	Sun Oct 30 20:30:24 2011 +0200
+++ b/rhodecode/lib/auth.py	Mon Oct 31 19:10:21 2011 +0200
@@ -223,6 +223,43 @@
                 pass
     return False
 
+def login_container_auth(username):
+    user = User.get_by_username(username)
+    if user is None:
+        user_model = UserModel()
+        user_attrs = {
+                 'name': username,
+                 'lastname': None,
+                 'email': None,
+                }
+        if not user_model.create_for_container_auth(username, user_attrs):
+            return None
+        user = User.get_by_username(username)
+        log.info('User %s was created by container authentication', username)
+
+    if not user.active:
+        return None
+
+    user.update_lastlogin()
+    log.debug('User %s is now logged in by container authentication', user.username)
+    return user
+
+def get_container_username(environ, cfg=config):
+    from paste.httpheaders import REMOTE_USER
+    from paste.deploy.converters import asbool
+
+    username = REMOTE_USER(environ)
+
+    if not username and asbool(cfg.get('proxypass_auth_enabled', False)):
+        username = environ.get('HTTP_X_FORWARDED_USER')
+
+    if username:
+        #Removing realm and domain from username
+        username = username.partition('@')[0]
+        username = username.rpartition('\\')[2]
+        log.debug('Received username %s from container', username)
+
+    return username
 
 class  AuthUser(object):
     """
@@ -234,12 +271,12 @@
     in
     """
 
-    def __init__(self, user_id=None, api_key=None):
+    def __init__(self, user_id=None, api_key=None, username=None):
 
         self.user_id = user_id
         self.api_key = None
-
-        self.username = 'None'
+        self.username = username
+        
         self.name = ''
         self.lastname = ''
         self.email = ''
@@ -252,23 +289,37 @@
     def propagate_data(self):
         user_model = UserModel()
         self.anonymous_user = User.get_by_username('default')
+        is_user_loaded = False
         if self._api_key and self._api_key != self.anonymous_user.api_key:
             #try go get user by api key
             log.debug('Auth User lookup by API KEY %s', self._api_key)
-            user_model.fill_data(self, api_key=self._api_key)
-        else:
+            is_user_loaded = user_model.fill_data(self, api_key=self._api_key)
+        elif self.user_id is not None \
+            and self.user_id != self.anonymous_user.user_id:
             log.debug('Auth User lookup by USER ID %s', self.user_id)
-            if self.user_id is not None \
-                and self.user_id != self.anonymous_user.user_id:
-                user_model.fill_data(self, user_id=self.user_id)
+            is_user_loaded = user_model.fill_data(self, user_id=self.user_id)
+        elif self.username:
+            log.debug('Auth User lookup by USER NAME %s', self.username)
+            dbuser = login_container_auth(self.username)
+            if dbuser is not None:
+                for k, v in dbuser.get_dict().items():
+                    setattr(self, k, v)
+                self.set_authenticated()
+                is_user_loaded = True
+
+        if not is_user_loaded:
+            if self.anonymous_user.active is True:
+                user_model.fill_data(self,
+                                     user_id=self.anonymous_user.user_id)
+                #then we set this user is logged in
+                self.is_authenticated = True
             else:
-                if self.anonymous_user.active is True:
-                    user_model.fill_data(self,
-                                         user_id=self.anonymous_user.user_id)
-                    #then we set this user is logged in
-                    self.is_authenticated = True
-                else:
-                    self.is_authenticated = False
+                self.user_id = None
+                self.username = None
+                self.is_authenticated = False
+
+        if not self.username:
+            self.username = 'None'
 
         log.debug('Auth User is now %s', self)
         user_model.fill_perms(self)
--- a/rhodecode/lib/base.py	Sun Oct 30 20:30:24 2011 +0200
+++ b/rhodecode/lib/base.py	Mon Oct 31 19:10:21 2011 +0200
@@ -8,9 +8,10 @@
 from pylons.controllers import WSGIController
 from pylons.controllers.util import redirect
 from pylons.templating import render_mako as render
+from paste.deploy.converters import asbool
 
 from rhodecode import __version__
-from rhodecode.lib.auth import AuthUser
+from rhodecode.lib.auth import AuthUser, get_container_username
 from rhodecode.lib.utils import get_repo_slug
 from rhodecode.model import meta
 from rhodecode.model.scm import ScmModel
@@ -44,8 +45,15 @@
             # putting this here makes sure that we update permissions each time
             api_key = request.GET.get('api_key')
             user_id = getattr(session.get('rhodecode_user'), 'user_id', None)
-            self.rhodecode_user = c.rhodecode_user = AuthUser(user_id, api_key)
-            self.rhodecode_user.set_authenticated(
+            if asbool(config.get('container_auth_enabled', False)):
+                username = get_container_username(environ)
+            else:
+                username = None
+
+            self.rhodecode_user = c.rhodecode_user = AuthUser(user_id, api_key, username)
+            if not self.rhodecode_user.is_authenticated and \
+                       self.rhodecode_user.user_id is not None:
+                self.rhodecode_user.set_authenticated(
                                         getattr(session.get('rhodecode_user'),
                                        'is_authenticated', False))
             session['rhodecode_user'] = self.rhodecode_user
--- a/rhodecode/lib/helpers.py	Sun Oct 30 20:30:24 2011 +0200
+++ b/rhodecode/lib/helpers.py	Mon Oct 31 19:10:21 2011 +0200
@@ -455,7 +455,8 @@
 
 def gravatar_url(email_address, size=30):
     if not str2bool(config['app_conf'].get('use_gravatar')) or \
-        email_address == 'anonymous@rhodecode.org':
+            not email_address or \
+            email_address == 'anonymous@rhodecode.org':
         return url("/images/user%s.png" % size)
 
     ssl_enabled = 'https' == request.environ.get('wsgi.url_scheme')
--- a/rhodecode/lib/middleware/simplegit.py	Sun Oct 30 20:30:24 2011 +0200
+++ b/rhodecode/lib/middleware/simplegit.py	Mon Oct 31 19:10:21 2011 +0200
@@ -70,7 +70,7 @@
 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
 
 from rhodecode.lib import safe_str
-from rhodecode.lib.auth import authfunc, HasPermissionAnyMiddleware
+from rhodecode.lib.auth import authfunc, HasPermissionAnyMiddleware, get_container_username
 from rhodecode.lib.utils import invalidate_cache, is_valid_repo
 from rhodecode.model.db import User
 
@@ -148,7 +148,7 @@
                 # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS
                 #==============================================================
 
-                if not REMOTE_USER(environ):
+                if not get_container_username(environ, self.config):
                     self.authenticate.realm = \
                         safe_str(self.config['rhodecode_realm'])
                     result = self.authenticate(environ)
@@ -164,10 +164,10 @@
                 #==============================================================
 
                 if action in ['pull', 'push']:
-                    username = REMOTE_USER(environ)
+                    username = get_container_username(environ, self.config)
                     try:
                         user = self.__get_user(username)
-                        if user is None:
+                        if user is None or not user.active:
                             return HTTPForbidden()(environ, start_response)                        
                         username = user.username
                     except:
--- a/rhodecode/lib/middleware/simplehg.py	Sun Oct 30 20:30:24 2011 +0200
+++ b/rhodecode/lib/middleware/simplehg.py	Mon Oct 31 19:10:21 2011 +0200
@@ -35,7 +35,7 @@
 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
 
 from rhodecode.lib import safe_str
-from rhodecode.lib.auth import authfunc, HasPermissionAnyMiddleware
+from rhodecode.lib.auth import authfunc, HasPermissionAnyMiddleware, get_container_username
 from rhodecode.lib.utils import make_ui, invalidate_cache, \
     is_valid_repo, ui_sections
 from rhodecode.model.db import User
@@ -114,7 +114,7 @@
                 # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS
                 #==============================================================
 
-                if not REMOTE_USER(environ):
+                if not get_container_username(environ, self.config):
                     self.authenticate.realm = \
                         safe_str(self.config['rhodecode_realm'])
                     result = self.authenticate(environ)
@@ -130,10 +130,10 @@
                 #==============================================================
 
                 if action in ['pull', 'push']:
-                    username = REMOTE_USER(environ)
+                    username = get_container_username(environ, self.config)
                     try:
                         user = self.__get_user(username)
-                        if user is None:
+                        if user is None or not user.active:
                             return HTTPForbidden()(environ, start_response)
                         username = user.username
                     except:
--- a/rhodecode/model/user.py	Sun Oct 30 20:30:24 2011 +0200
+++ b/rhodecode/model/user.py	Mon Oct 31 19:10:21 2011 +0200
@@ -92,6 +92,35 @@
             self.sa.rollback()
             raise
 
+    def create_for_container_auth(self, username, attrs):
+        """
+        Creates the given user if it's not already in the database
+        
+        :param username:
+        :param attrs:
+        """
+        if self.get_by_username(username, case_insensitive=True) is None:
+            try:
+                new_user = User()
+                new_user.username = username
+                new_user.password = None
+                new_user.api_key = generate_api_key(username)
+                new_user.email = attrs['email']
+                new_user.active = True
+                new_user.name = attrs['name']
+                new_user.lastname = attrs['lastname']
+
+                self.sa.add(new_user)
+                self.sa.commit()
+                return True
+            except (DatabaseError,):
+                log.error(traceback.format_exc())
+                self.sa.rollback()
+                raise
+        log.debug('User %s already exists. Skipping creation of account for container auth.',
+                  username)
+        return False
+
     def create_ldap(self, username, password, user_dn, attrs):
         """
         Checks if user is in database, if not creates this user marked
@@ -243,16 +272,19 @@
             else:
                 dbuser = self.get(user_id)
 
-            if dbuser is not None:
+            if dbuser is not None and dbuser.active:
                 log.debug('filling %s data', dbuser)
                 for k, v in dbuser.get_dict().items():
                     setattr(auth_user, k, v)
+            else:
+                return False
 
         except:
             log.error(traceback.format_exc())
             auth_user.is_authenticated = False
+            return False
 
-        return auth_user
+        return True
 
     def fill_perms(self, user):
         """