diff --git a/rhodecode/lib/base.py b/rhodecode/lib/base.py --- a/rhodecode/lib/base.py +++ b/rhodecode/lib/base.py @@ -1,7 +1,31 @@ -"""The base Controller API +# -*- coding: utf-8 -*- +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . -Provides the BaseController class for subclassing. """ +rhodecode.lib.base +~~~~~~~~~~~~~~~~~~ + +The base Controller API +Provides the BaseController class for subclassing. And usage in different +controllers + +:created_on: Oct 06, 2010 +:author: marcink +:copyright: (c) 2013 RhodeCode GmbH. +:license: GPLv3, see LICENSE for more details. +""" + import logging import time import traceback @@ -13,14 +37,14 @@ from paste.httpheaders import WWW_AUTHEN from pylons import config, tmpl_context as c, request, session, url from pylons.controllers import WSGIController from pylons.controllers.util import redirect -from pylons.templating import render_mako as render +from pylons.templating import render_mako as render # don't remove this import from rhodecode import __version__, BACKENDS from rhodecode.lib.utils2 import str2bool, safe_unicode, AttributeDict,\ safe_str, safe_int -from rhodecode.lib.auth import AuthUser, get_container_username, authfunc,\ - HasPermissionAnyMiddleware, CookieStoreWrapper +from rhodecode.lib import auth_modules +from rhodecode.lib.auth import AuthUser, HasPermissionAnyMiddleware, CookieStoreWrapper from rhodecode.lib.utils import get_repo_slug from rhodecode.lib.exceptions import UserCreationError from rhodecode.model import meta @@ -100,7 +124,7 @@ class BasicAuth(AuthBasicAuthenticator): _parts = auth.split(':', 1) if len(_parts) == 2: username, password = _parts - if self.authfunc(environ, username, password): + if self.authfunc(username, password, environ): return username return self.build_authentication() @@ -114,8 +138,8 @@ class BaseVCSController(object): self.config = config # base path of repo locations self.basepath = self.config['base_path'] - #authenticate this mercurial request using authfunc - self.authenticate = BasicAuth('', authfunc, + #authenticate this VCS request using authfunc + self.authenticate = BasicAuth('', auth_modules.authenticate, config.get('auth_ret_code')) self.ip_addr = '0.0.0.0' @@ -129,18 +153,13 @@ class BaseVCSController(object): :param repo_name: """ - try: - data = repo_name.split('/') - if len(data) >= 2: - by_id = data[1].split('_') - if len(by_id) == 2 and by_id[1].isdigit(): - _repo_name = Repository.get(by_id[1]).repo_name - data[1] = _repo_name - except Exception: - log.debug('Failed to extract repo_name from id %s' % ( - traceback.format_exc() - ) - ) + + data = repo_name.split('/') + if len(data) >= 2: + from rhodecode.lib.utils import get_repo_by_id + by_id_match = get_repo_by_id(repo_name) + if by_id_match: + data[1] = by_id_match return '/'.join(data) @@ -161,12 +180,15 @@ class BaseVCSController(object): :param user: user instance :param repo_name: repository name """ - #check IP - authuser = AuthUser(user_id=user.user_id, ip_addr=ip_addr) - if not authuser.ip_allowed: + # check IP + inherit = user.inherit_default_permissions + ip_allowed = AuthUser.check_ip_allowed(user.user_id, ip_addr, + inherit_from_default=inherit) + if ip_allowed: + log.info('Access for IP:%s allowed' % (ip_addr,)) + else: return False - else: - log.info('Access for IP:%s allowed' % (ip_addr)) + if action == 'push': if not HasPermissionAnyMiddleware('repository.write', 'repository.admin')(user, @@ -261,31 +283,40 @@ class BaseController(WSGIController): __before__ is called before controller methods and after __call__ """ c.rhodecode_version = __version__ - c.rhodecode_instanceid = config.get('instance_id') - c.rhodecode_name = config.get('rhodecode_title') - c.rhodecode_bugtracker = config.get('bugtracker', 'http://bitbucket.org/marcinkuzminski/rhodecode/issues') - c.use_gravatar = str2bool(config.get('use_gravatar')) - c.ga_code = config.get('rhodecode_ga_code') + rc_config = RhodeCodeSetting.get_app_settings() + # Visual options c.visual = AttributeDict({}) - rc_config = RhodeCodeSetting.get_app_settings() + ## DB stored c.visual.show_public_icon = str2bool(rc_config.get('rhodecode_show_public_icon')) c.visual.show_private_icon = str2bool(rc_config.get('rhodecode_show_private_icon')) c.visual.stylify_metatags = str2bool(rc_config.get('rhodecode_stylify_metatags')) c.visual.dashboard_items = safe_int(rc_config.get('rhodecode_dashboard_items', 100)) + c.visual.admin_grid_items = safe_int(rc_config.get('rhodecode_admin_grid_items', 100)) c.visual.repository_fields = str2bool(rc_config.get('rhodecode_repository_fields')) c.visual.show_version = str2bool(rc_config.get('rhodecode_show_version')) + c.visual.use_gravatar = str2bool(rc_config.get('rhodecode_use_gravatar')) + c.visual.gravatar_url = rc_config.get('rhodecode_gravatar_url') + + c.ga_code = rc_config.get('rhodecode_ga_code') + c.rhodecode_name = rc_config.get('rhodecode_title') + c.clone_uri_tmpl = rc_config.get('rhodecode_clone_uri_tmpl') ## INI stored - self.cut_off_limit = int(config.get('cut_off_limit')) c.visual.allow_repo_location_change = str2bool(config.get('allow_repo_location_change', True)) c.visual.allow_custom_hooks_settings = str2bool(config.get('allow_custom_hooks_settings', True)) + c.rhodecode_instanceid = config.get('instance_id') + c.rhodecode_bugtracker = config.get('bugtracker', url('rc_issue_tracker')) + # END CONFIG VARS + c.repo_name = get_repo_slug(request) # can be empty c.backends = BACKENDS.keys() c.unread_notifications = NotificationModel()\ .get_unread_cnt_for_user(c.rhodecode_user.user_id) + + self.cut_off_limit = safe_int(config.get('cut_off_limit')) self.sa = meta.Session self.scm_model = ScmModel(self.sa) @@ -298,27 +329,33 @@ class BaseController(WSGIController): self.ip_addr = _get_ip_addr(environ) # make sure that we update permissions each time we call controller api_key = request.GET.get('api_key') - cookie_store = CookieStoreWrapper(session.get('rhodecode_user')) - user_id = cookie_store.get('user_id', None) - username = get_container_username(environ, config) - try: - auth_user = AuthUser(user_id, api_key, username, self.ip_addr) - except UserCreationError, e: - from rhodecode.lib import helpers as h - h.flash(e, 'error') - # container auth or other auth functions that create users on - # the fly can throw this exception signaling that there's issue - # with user creation, explanation should be provided in - # Exception itself - auth_user = AuthUser(ip_addr=self.ip_addr) + if api_key: + # when using API_KEY we are sure user exists. + auth_user = AuthUser(api_key=api_key, ip_addr=self.ip_addr) + authenticated = False + else: + cookie_store = CookieStoreWrapper(session.get('rhodecode_user')) + try: + auth_user = AuthUser(user_id=cookie_store.get('user_id', None), + ip_addr=self.ip_addr) + except UserCreationError, e: + from rhodecode.lib import helpers as h + h.flash(e, 'error') + # container auth or other auth functions that create users on + # the fly can throw this exception signaling that there's issue + # with user creation, explanation should be provided in + # Exception itself + auth_user = AuthUser(ip_addr=self.ip_addr) + + authenticated = cookie_store.get('is_authenticated') + + if not auth_user.is_authenticated and auth_user.user_id is not None: + # user is not authenticated and not empty + auth_user.set_authenticated(authenticated) request.user = auth_user + #set globals for auth user self.rhodecode_user = c.rhodecode_user = auth_user - if not self.rhodecode_user.is_authenticated and \ - self.rhodecode_user.user_id is not None: - self.rhodecode_user.set_authenticated( - cookie_store.get('is_authenticated') - ) log.info('IP: %s User: %s accessed %s' % ( self.ip_addr, auth_user, safe_unicode(_get_access_path(environ))) ) @@ -341,21 +378,39 @@ class BaseRepoController(BaseController) def __before__(self): super(BaseRepoController, self).__before__() - if c.repo_name: + if c.repo_name: # extracted from routes + _dbr = Repository.get_by_repo_name(c.repo_name) + if not _dbr: + return + + log.debug('Found repository in database %s with state `%s`' + % (safe_unicode(_dbr), safe_unicode(_dbr.repo_state))) + route = getattr(request.environ.get('routes.route'), 'name', '') - dbr = c.rhodecode_db_repo = Repository.get_by_repo_name(c.repo_name) + # allow to delete repos that are somehow damages in filesystem + if route in ['delete_repo']: + return + + if _dbr.repo_state in [Repository.STATE_PENDING]: + if route in ['repo_creating_home']: + return + check_url = url('repo_creating_home', repo_name=c.repo_name) + return redirect(check_url) + + dbr = c.rhodecode_db_repo = _dbr c.rhodecode_repo = c.rhodecode_db_repo.scm_instance - # update last change according to VCS data - dbr.update_changeset_cache(dbr.get_changeset()) if c.rhodecode_repo is None: log.error('%s this repository is present in database but it ' 'cannot be created as an scm instance', c.repo_name) redirect(url('home')) + # update last change according to VCS data + dbr.update_changeset_cache(dbr.get_changeset()) + # some globals counter for menu c.repository_followers = self.scm_model.get_followers(dbr) c.repository_forks = self.scm_model.get_forks(dbr) c.repository_pull_requests = self.scm_model.get_pull_requests(dbr) - c.repository_following = self.scm_model.is_following_repo(c.repo_name, - self.rhodecode_user.user_id) + c.repository_following = self.scm_model.is_following_repo( + c.repo_name, self.rhodecode_user.user_id)