# HG changeset patch # User Marcin Kuzminski # Date 2010-11-11 00:05:43 # Node ID dd532af216d9c273dccbd1b58fe9d4a8bff18784 # Parent e7c670cc03cb06e24ce66b32e082623b5a039533 #49 Enabled anonymous access for web interface controllable from permissions pannel diff --git a/rhodecode/controllers/admin/permissions.py b/rhodecode/controllers/admin/permissions.py --- a/rhodecode/controllers/admin/permissions.py +++ b/rhodecode/controllers/admin/permissions.py @@ -57,11 +57,12 @@ class PermissionsController(BaseControll ('repository.write', _('Write'),), ('repository.admin', _('Admin'),)] self.register_choices = [ - ('hg.register.none', 'disabled'), + ('hg.register.none', + _('disabled')), ('hg.register.manual_activate', - _('allowed with manual account activation')), + _('allowed with manual account activation')), ('hg.register.auto_activate', - _('allowed with automatic account activation')), ] + _('allowed with automatic account activation')), ] self.create_choices = [('hg.create.none', _('Disabled')), ('hg.create.repository', _('Enabled'))] @@ -142,8 +143,10 @@ class PermissionsController(BaseControll c.create_choices = self.create_choices if id == 'default': - defaults = {'_method':'put'} - for p in UserModel().get_by_username('default').user_perms: + default_user = UserModel().get_by_username('default') + defaults = {'_method':'put', + 'anonymous':default_user.active} + for p in default_user.user_perms: if p.permission.permission_name.startswith('repository.'): defaults['default_perm'] = p.permission.permission_name diff --git a/rhodecode/controllers/admin/settings.py b/rhodecode/controllers/admin/settings.py --- a/rhodecode/controllers/admin/settings.py +++ b/rhodecode/controllers/admin/settings.py @@ -121,11 +121,15 @@ class SettingsController(BaseController) try: hgsettings1 = self.sa.query(RhodeCodeSettings)\ - .filter(RhodeCodeSettings.app_settings_name == 'title').one() + .filter(RhodeCodeSettings.app_settings_name \ + == 'title').one() + hgsettings1.app_settings_value = form_result['rhodecode_title'] hgsettings2 = self.sa.query(RhodeCodeSettings)\ - .filter(RhodeCodeSettings.app_settings_name == 'realm').one() + .filter(RhodeCodeSettings.app_settings_name \ + == 'realm').one() + hgsettings2.app_settings_value = form_result['rhodecode_realm'] diff --git a/rhodecode/controllers/admin/users.py b/rhodecode/controllers/admin/users.py --- a/rhodecode/controllers/admin/users.py +++ b/rhodecode/controllers/admin/users.py @@ -45,26 +45,26 @@ class UsersController(BaseController): # To properly map this controller, ensure your config/routing.py # file has a resource setup: # map.resource('user', 'users') - + @LoginRequired() @HasPermissionAllDecorator('hg.admin') def __before__(self): c.admin_user = session.get('admin_user') c.admin_username = session.get('admin_username') super(UsersController, self).__before__() - + def index(self, format='html'): """GET /users: All items in the collection""" # url('users') - - c.users_list = self.sa.query(User).all() + + c.users_list = self.sa.query(User).all() return render('admin/users/users.html') - + def create(self): """POST /users: Create a new item""" # url('users') - + user_model = UserModel() login_form = UserForm()() try: @@ -79,13 +79,13 @@ class UsersController(BaseController): defaults=errors.value, errors=errors.error_dict or {}, prefix_error=False, - encoding="UTF-8") + encoding="UTF-8") except Exception: log.error(traceback.format_exc()) h.flash(_('error occured during creation of user %s') \ - % request.POST.get('username'), category='error') + % request.POST.get('username'), category='error') return redirect(url('users')) - + def new(self, format='html'): """GET /users/new: Form to create a new item""" # url('new_user') @@ -101,7 +101,7 @@ class UsersController(BaseController): # url('user', id=ID) user_model = UserModel() c.user = user_model.get(id) - + _form = UserForm(edit=True, old_data={'user_id':id, 'email':c.user.email})() form_result = {} @@ -109,21 +109,21 @@ class UsersController(BaseController): form_result = _form.to_python(dict(request.POST)) user_model.update(id, form_result) h.flash(_('User updated succesfully'), category='success') - + except formencode.Invalid, errors: return htmlfill.render( render('admin/users/user_edit.html'), defaults=errors.value, errors=errors.error_dict or {}, prefix_error=False, - encoding="UTF-8") + encoding="UTF-8") except Exception: log.error(traceback.format_exc()) h.flash(_('error occured during update of user %s') \ % form_result.get('username'), category='error') - + return redirect(url('users')) - + def delete(self, id): """DELETE /users/id: Delete an existing item""" # Forms posted to this method should contain a hidden field: @@ -140,14 +140,14 @@ class UsersController(BaseController): h.flash(str(e), category='warning') except Exception: h.flash(_('An error occured during deletion of user'), - category='error') + category='error') return redirect(url('users')) - + def show(self, id, format='html'): """GET /users/id: Show a specific item""" # url('user', id=ID) - - + + def edit(self, id, format='html'): """GET /users/id/edit: Form to edit an existing item""" # url('edit_user', id=ID) @@ -155,14 +155,13 @@ class UsersController(BaseController): if not c.user: return redirect(url('users')) if c.user.username == 'default': - h.flash(_("You can't edit this user since it's" - " crucial for entire application"), category='warning') + h.flash(_("You can't edit this user"), category='warning') return redirect(url('users')) - + defaults = c.user.__dict__ return htmlfill.render( render('admin/users/user_edit.html'), defaults=defaults, encoding="UTF-8", force_defaults=False - ) + ) diff --git a/rhodecode/controllers/login.py b/rhodecode/controllers/login.py --- a/rhodecode/controllers/login.py +++ b/rhodecode/controllers/login.py @@ -46,7 +46,9 @@ class LoginController(BaseController): #redirect if already logged in c.came_from = request.GET.get('came_from', None) - if c.rhodecode_user.is_authenticated: + if c.rhodecode_user.is_authenticated \ + and c.rhodecode_user.username != 'default': + return redirect(url('home')) if request.POST: diff --git a/rhodecode/lib/auth.py b/rhodecode/lib/auth.py --- a/rhodecode/lib/auth.py +++ b/rhodecode/lib/auth.py @@ -26,15 +26,16 @@ from pylons import config, session, url, 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 @@ class PasswordGenerator(object): 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 @@ class PasswordGenerator(object): 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 @@ def authfunc(environ, username, password return True else: log.error('user %s is disabled', username) - + return False class AuthUser(object): @@ -99,6 +99,8 @@ class AuthUser(object): self.is_admin = False self.permissions = {} + def __repr__(self): + return "" % (self.user_id, self.username) def set_available_permissions(config): """ @@ -116,85 +118,56 @@ def set_available_permissions(config): 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 @@ def fill_perms(user): 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 @@ def fill_perms(user): .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 @@ class LoginRequired(object): 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 @@ class PermsDecorator(object): 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 @@ class HasPermissionAllDecorator(PermsDec """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 @@ class HasRepoPermissionAllDecorator(Perm """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 @@ class HasRepoPermissionAllDecorator(Perm 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 HasRepoPermissionAnyDecorator(Perm 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 @@ class PermsFunction(object): 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 @@ class HasPermissionAny(PermsFunction): 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 @@ class HasRepoPermissionAll(PermsFunction [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 HasRepoPermissionAny(PermsFunction 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 @@ class HasPermissionAnyMiddleware(object) 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', diff --git a/rhodecode/lib/db_manage.py b/rhodecode/lib/db_manage.py --- a/rhodecode/lib/db_manage.py +++ b/rhodecode/lib/db_manage.py @@ -138,17 +138,17 @@ class DbManage(object): hooks2.ui_section = 'hooks' hooks2.ui_key = 'changegroup.repo_size' hooks2.ui_value = 'python:rhodecode.lib.hooks.repo_size' - + hooks3 = RhodeCodeUi() hooks3.ui_section = 'hooks' hooks3.ui_key = 'pretxnchangegroup.push_logger' hooks3.ui_value = 'python:rhodecode.lib.hooks.log_push_action' - + hooks4 = RhodeCodeUi() hooks4.ui_section = 'hooks' hooks4.ui_key = 'preoutgoing.pull_logger' hooks4.ui_value = 'python:rhodecode.lib.hooks.log_pull_action' - + web1 = RhodeCodeUi() web1.ui_section = 'web' @@ -227,9 +227,9 @@ class DbManage(object): def_user = User() def_user.username = 'default' def_user.password = get_crypt_password(str(uuid.uuid1())[:8]) - def_user.name = 'default' - def_user.lastname = 'default' - def_user.email = 'default@default.com' + def_user.name = 'Anonymous' + def_user.lastname = 'User' + def_user.email = 'anonymous@rhodecode.org' def_user.admin = False def_user.active = False try: diff --git a/rhodecode/model/forms.py b/rhodecode/model/forms.py --- a/rhodecode/model/forms.py +++ b/rhodecode/model/forms.py @@ -358,6 +358,7 @@ def DefaultPermissionsForm(perms_choices allow_extra_fields = True filter_extra_fields = True overwrite_default = OneOf(['true', 'false'], if_missing='false') + anonymous = OneOf(['True', 'False'], if_missing=False) default_perm = OneOf(perms_choices) default_register = OneOf(register_choices) default_create = OneOf(create_choices) diff --git a/rhodecode/model/permission_model.py b/rhodecode/model/permission_model.py --- a/rhodecode/model/permission_model.py +++ b/rhodecode/model/permission_model.py @@ -59,30 +59,41 @@ class PermissionModel(object): .filter(User.username == form_result['perm_user_name']).scalar() u2p = self.sa.query(UserToPerm).filter(UserToPerm.user == perm_user).all() if len(u2p) != 3: - raise Exception('There is more than 3 defined' - ' permissions for default user. This should not happen please verify' - ' your database') + raise Exception('Defined: %s should be 3 permissions for default' + ' user. This should not happen please verify' + ' your database' % len(u2p)) try: #stage 1 change defaults for p in u2p: if p.permission.permission_name.startswith('repository.'): - p.permission = self.get_permission_by_name(form_result['default_perm']) + p.permission = self.get_permission_by_name( + form_result['default_perm']) self.sa.add(p) if p.permission.permission_name.startswith('hg.register.'): - p.permission = self.get_permission_by_name(form_result['default_register']) + p.permission = self.get_permission_by_name( + form_result['default_register']) self.sa.add(p) if p.permission.permission_name.startswith('hg.create.'): - p.permission = self.get_permission_by_name(form_result['default_create']) + p.permission = self.get_permission_by_name( + form_result['default_create']) self.sa.add(p) #stage 2 update all default permissions for repos if checked if form_result['overwrite_default'] == 'true': - for r2p in self.sa.query(RepoToPerm).filter(RepoToPerm.user == perm_user).all(): - r2p.permission = self.get_permission_by_name(form_result['default_perm']) + for r2p in self.sa.query(RepoToPerm)\ + .filter(RepoToPerm.user == perm_user).all(): + r2p.permission = self.get_permission_by_name( + form_result['default_perm']) self.sa.add(r2p) + #stage 3 set anonymous access + if perm_user.username == 'default': + perm_user.active = bool(form_result['anonymous']) + self.sa.add(perm_user) + + self.sa.commit() except: log.error(traceback.format_exc()) diff --git a/rhodecode/model/user.py b/rhodecode/model/user.py --- a/rhodecode/model/user.py +++ b/rhodecode/model/user.py @@ -143,3 +143,24 @@ class UserModel(object): def reset_password(self, data): from rhodecode.lib.celerylib import tasks, run_task run_task(tasks.reset_user_password, data['email']) + + + def fill_data(self, user): + """ + Fills user data with those from database and log out user if not + present in database + :param user: + """ + log.debug('filling auth user data') + try: + dbuser = self.get(user.user_id) + user.username = dbuser.username + user.is_admin = dbuser.admin + user.name = dbuser.name + user.lastname = dbuser.lastname + user.email = dbuser.email + except: + log.error(traceback.format_exc()) + user.is_authenticated = False + + return user diff --git a/rhodecode/public/css/style.css b/rhodecode/public/css/style.css --- a/rhodecode/public/css/style.css +++ b/rhodecode/public/css/style.css @@ -2096,7 +2096,7 @@ border:1px solid #666; clear:both; overflow:hidden; margin:0; -padding:2px 0; +padding:2px 2px; } #content div.box div.form div.fields div.field div.checkboxes div.checkbox input,#content div.box div.form div.fields div.field div.radios div.radio input { diff --git a/rhodecode/templates/admin/permissions/permissions.html b/rhodecode/templates/admin/permissions/permissions.html --- a/rhodecode/templates/admin/permissions/permissions.html +++ b/rhodecode/templates/admin/permissions/permissions.html @@ -26,7 +26,16 @@
- +
+
+ +
+
+
+ ${h.checkbox('anonymous',True)} +
+
+
diff --git a/rhodecode/templates/base/base.html b/rhodecode/templates/base/base.html --- a/rhodecode/templates/base/base.html +++ b/rhodecode/templates/base/base.html @@ -20,12 +20,22 @@
gravatar
+ %if c.rhodecode_user.username == 'default': + + +
  • ${h.link_to(u'Login',h.url('login_home'))}
  • + %else: +
  • ${h.link_to(u'Logout',h.url('logout_home'))}
  • + %endif