def vcs_operation_context( environ, repo_name, username, action, scm, check_locking=True): """ Generate the context for a vcs operation, e.g. push or pull. This context is passed over the layers so that hooks triggered by the vcs operation know details like the user, the user's IP address etc. :param check_locking: Allows to switch of the computation of the locking data. This serves mainly the need of the simplevcs middleware to be able to disable this for certain operations. """ # Tri-state value: False: unlock, None: nothing, True: lock make_lock = None locked_by = [None, None, None] is_anonymous = username == User.DEFAULT_USER if not is_anonymous and check_locking: log.debug('Checking locking on repository "%s"', repo_name) user = User.get_by_username(username) repo = Repository.get_by_repo_name(repo_name) make_lock, __, locked_by = repo.get_locking_state( action, user.user_id) settings_model = VcsSettingsModel(repo=repo_name) ui_settings = settings_model.get_ui_settings() extras = { 'ip': get_ip_addr(environ), 'username': username, 'action': action, 'repository': repo_name, 'scm': scm, 'config': rhodecode.CONFIG['__file__'], 'make_lock': make_lock, 'locked_by': locked_by, 'server_url': utils2.get_server_url(environ), 'hooks': get_enabled_hook_classes(ui_settings), } return extras
def _handle_push(self, repo, username, action, repo_name, revisions): """ Triggers push action hooks :param repo: SCM repo :param username: username who pushes :param action: push/push_loca/push_remote :param repo_name: name of repo :param revisions: list of revisions that we pushed """ from rhodecode import CONFIG from rhodecode.lib.base import _get_ip_addr try: from pylons import request environ = request.environ except TypeError: # we might use this outside of request context, let's fake the # environ data from webob import Request environ = Request.blank('').environ #trigger push hook extras = { 'ip': _get_ip_addr(environ), 'username': username, 'action': 'push_local', 'repository': repo_name, 'scm': repo.alias, 'config': CONFIG['__file__'], 'server_url': get_server_url(environ), 'make_lock': None, 'locked_by': [None, None] } _scm_repo = repo._repo _set_extras(extras) if repo.alias == 'hg': log_push_action(_scm_repo.ui, _scm_repo, node=revisions[0]) elif repo.alias == 'git': log_push_action(None, _scm_repo, _git_revs=revisions)
def _handle_rc_scm_extras(self, username, repo_name, repo_alias, action=None): from rhodecode import CONFIG from rhodecode.lib.base import _get_ip_addr try: from pylons import request environ = request.environ except TypeError: # we might use this outside of request context, let's fake the # environ data from webob import Request environ = Request.blank('').environ extras = { 'ip': _get_ip_addr(environ), 'username': username, 'action': action or 'push_local', 'repository': repo_name, 'scm': repo_alias, 'config': CONFIG['__file__'], 'server_url': get_server_url(environ), 'make_lock': None, 'locked_by': [None, None] } _set_extras(extras)
def _handle_request(self, environ, start_response): if not is_mercurial(environ): return self.application(environ, start_response) if not self._check_ssl(environ, start_response): return HTTPNotAcceptable('SSL REQUIRED !')(environ, start_response) ip_addr = self._get_ip_addr(environ) username = None # skip passing error to error controller environ['pylons.status_code_redirect'] = True #====================================================================== # EXTRACT REPOSITORY NAME FROM ENV #====================================================================== try: repo_name = environ['REPO_NAME'] = self.__get_repository(environ) log.debug('Extracted repo name is %s' % repo_name) except Exception: return HTTPInternalServerError()(environ, start_response) # quick check if that dir exists... if not is_valid_repo(repo_name, self.basepath, 'hg'): return HTTPNotFound()(environ, start_response) #====================================================================== # GET ACTION PULL or PUSH #====================================================================== action = self.__get_action(environ) #====================================================================== # CHECK ANONYMOUS PERMISSION #====================================================================== if action in ['pull', 'push']: anonymous_user = self.__get_user('default') username = anonymous_user.username anonymous_perm = self._check_permission(action, anonymous_user, repo_name, ip_addr) if not anonymous_perm or not anonymous_user.active: if not anonymous_perm: log.debug('Not enough credentials to access this ' 'repository as anonymous user') if not anonymous_user.active: log.debug('Anonymous access is disabled, running ' 'authentication') #============================================================== # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS #============================================================== # Attempting to retrieve username from the container username = get_container_username(environ, self.config) # If not authenticated by the container, running basic auth if not username: self.authenticate.realm = \ safe_str(self.config['rhodecode_realm']) result = self.authenticate(environ) if isinstance(result, str): AUTH_TYPE.update(environ, 'basic') REMOTE_USER.update(environ, result) username = result else: return result.wsgi_application(environ, start_response) #============================================================== # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME #============================================================== try: user = self.__get_user(username) if user is None or not user.active: return HTTPForbidden()(environ, start_response) username = user.username except Exception: log.error(traceback.format_exc()) return HTTPInternalServerError()(environ, start_response) #check permissions for this repository perm = self._check_permission(action, user, repo_name, ip_addr) if not perm: return HTTPForbidden()(environ, start_response) # extras are injected into mercurial UI object and later available # in hg hooks executed by rhodecode from rhodecode import CONFIG server_url = get_server_url(environ) extras = { 'ip': ip_addr, 'username': username, 'action': action, 'repository': repo_name, 'scm': 'hg', 'config': CONFIG['__file__'], 'server_url': server_url, 'make_lock': None, 'locked_by': [None, None] } #====================================================================== # MERCURIAL REQUEST HANDLING #====================================================================== str_repo_name = safe_str(repo_name) repo_path = os.path.join(safe_str(self.basepath), str_repo_name) log.debug('Repository path is %s' % repo_path) # CHECK LOCKING only if it's not ANONYMOUS USER if username != User.DEFAULT_USER: log.debug('Checking locking on repository') (make_lock, locked, locked_by) = self._check_locking_state(environ=environ, action=action, repo=repo_name, user_id=user.user_id) # store the make_lock for later evaluation in hooks extras.update({'make_lock': make_lock, 'locked_by': locked_by}) fix_PATH() log.debug('HOOKS extras is %s' % extras) baseui = make_ui('db') self.__inject_extras(repo_path, baseui, extras) try: log.info('%s action on HG repo "%s" by "%s" from %s' % (action, str_repo_name, safe_str(username), ip_addr)) app = self.__make_app(repo_path, baseui, extras) return app(environ, start_response) except RepoError, e: if str(e).find('not found') != -1: return HTTPNotFound()(environ, start_response)
def _handle_request(self, environ, start_response): if not is_git(environ): return self.application(environ, start_response) if not self._check_ssl(environ, start_response): return HTTPNotAcceptable("SSL REQUIRED !")(environ, start_response) ipaddr = self._get_ip_addr(environ) username = None self._git_first_op = False # skip passing error to error controller environ["pylons.status_code_redirect"] = True # ====================================================================== # EXTRACT REPOSITORY NAME FROM ENV # ====================================================================== try: repo_name = self.__get_repository(environ) log.debug("Extracted repo name is %s" % repo_name) except: return HTTPInternalServerError()(environ, start_response) # quick check if that dir exists... if is_valid_repo(repo_name, self.basepath, "git") is False: return HTTPNotFound()(environ, start_response) # ====================================================================== # GET ACTION PULL or PUSH # ====================================================================== action = self.__get_action(environ) # ====================================================================== # CHECK ANONYMOUS PERMISSION # ====================================================================== if action in ["pull", "push"]: anonymous_user = self.__get_user("default") username = anonymous_user.username anonymous_perm = self._check_permission(action, anonymous_user, repo_name) if anonymous_perm is not True or anonymous_user.active is False: if anonymous_perm is not True: log.debug("Not enough credentials to access this " "repository as anonymous user") if anonymous_user.active is False: log.debug("Anonymous access is disabled, running " "authentication") # ============================================================== # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS # ============================================================== # Attempting to retrieve username from the container username = get_container_username(environ, self.config) # If not authenticated by the container, running basic auth if not username: self.authenticate.realm = safe_str(self.config["rhodecode_realm"]) result = self.authenticate(environ) if isinstance(result, str): AUTH_TYPE.update(environ, "basic") REMOTE_USER.update(environ, result) username = result else: return result.wsgi_application(environ, start_response) # ============================================================== # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME # ============================================================== try: user = self.__get_user(username) if user is None or not user.active: return HTTPForbidden()(environ, start_response) username = user.username except: log.error(traceback.format_exc()) return HTTPInternalServerError()(environ, start_response) # check permissions for this repository perm = self._check_permission(action, user, repo_name) if perm is not True: return HTTPForbidden()(environ, start_response) # extras are injected into UI object and later available # in hooks executed by rhodecode from rhodecode import CONFIG server_url = get_server_url(environ) extras = { "ip": ipaddr, "username": username, "action": action, "repository": repo_name, "scm": "git", "config": CONFIG["__file__"], "server_url": server_url, "make_lock": None, "locked_by": [None, None], } # =================================================================== # GIT REQUEST HANDLING # =================================================================== repo_path = os.path.join(safe_str(self.basepath), safe_str(repo_name)) log.debug("Repository path is %s" % repo_path) # CHECK LOCKING only if it's not ANONYMOUS USER if username != User.DEFAULT_USER: log.debug("Checking locking on repository") (make_lock, locked, locked_by) = self._check_locking_state( environ=environ, action=action, repo=repo_name, user_id=user.user_id ) # store the make_lock for later evaluation in hooks extras.update({"make_lock": make_lock, "locked_by": locked_by}) # set the environ variables for this request os.environ["RC_SCM_DATA"] = json.dumps(extras) fix_PATH() log.debug("HOOKS extras is %s" % extras) baseui = make_ui("db") self.__inject_extras(repo_path, baseui, extras) try: # invalidate cache on push if action == "push": self._invalidate_cache(repo_name) self._handle_githooks(repo_name, action, baseui, environ) log.info('%s action on GIT repo "%s"' % (action, repo_name)) app = self.__make_app(repo_name, repo_path, extras) return app(environ, start_response) except HTTPLockedRC, e: log.debug("Repositry LOCKED ret code 423!") return e(environ, start_response)
def _handle_request(self, environ, start_response): if not is_git(environ): return self.application(environ, start_response) if not self._check_ssl(environ, start_response): return HTTPNotAcceptable('SSL REQUIRED !')(environ, start_response) ip_addr = self._get_ip_addr(environ) username = None self._git_first_op = False # skip passing error to error controller environ['pylons.status_code_redirect'] = True #====================================================================== # EXTRACT REPOSITORY NAME FROM ENV #====================================================================== try: repo_name = self.__get_repository(environ) log.debug('Extracted repo name is %s' % repo_name) except Exception: return HTTPInternalServerError()(environ, start_response) # quick check if that dir exists... if not is_valid_repo(repo_name, self.basepath, 'git'): return HTTPNotFound()(environ, start_response) #====================================================================== # GET ACTION PULL or PUSH #====================================================================== action = self.__get_action(environ) #====================================================================== # CHECK ANONYMOUS PERMISSION #====================================================================== if action in ['pull', 'push']: anonymous_user = self.__get_user('default') username = anonymous_user.username anonymous_perm = self._check_permission(action, anonymous_user, repo_name, ip_addr) if not anonymous_perm or not anonymous_user.active: if not anonymous_perm: log.debug('Not enough credentials to access this ' 'repository as anonymous user') if not anonymous_user.active: log.debug('Anonymous access is disabled, running ' 'authentication') #============================================================== # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS #============================================================== # Attempting to retrieve username from the container username = get_container_username(environ, self.config) # If not authenticated by the container, running basic auth if not username: self.authenticate.realm = \ safe_str(self.config['rhodecode_realm']) result = self.authenticate(environ) if isinstance(result, str): AUTH_TYPE.update(environ, 'basic') REMOTE_USER.update(environ, result) username = result else: return result.wsgi_application(environ, start_response) #============================================================== # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME #============================================================== try: user = self.__get_user(username) if user is None or not user.active: return HTTPForbidden()(environ, start_response) username = user.username except Exception: log.error(traceback.format_exc()) return HTTPInternalServerError()(environ, start_response) #check permissions for this repository perm = self._check_permission(action, user, repo_name, ip_addr) if not perm: return HTTPForbidden()(environ, start_response) # extras are injected into UI object and later available # in hooks executed by rhodecode from rhodecode import CONFIG server_url = get_server_url(environ) extras = { 'ip': ip_addr, 'username': username, 'action': action, 'repository': repo_name, 'scm': 'git', 'config': CONFIG['__file__'], 'server_url': server_url, 'make_lock': None, 'locked_by': [None, None] } #=================================================================== # GIT REQUEST HANDLING #=================================================================== str_repo_name = safe_str(repo_name) repo_path = os.path.join(safe_str(self.basepath),str_repo_name) log.debug('Repository path is %s' % repo_path) # CHECK LOCKING only if it's not ANONYMOUS USER if username != User.DEFAULT_USER: log.debug('Checking locking on repository') (make_lock, locked, locked_by) = self._check_locking_state( environ=environ, action=action, repo=repo_name, user_id=user.user_id ) # store the make_lock for later evaluation in hooks extras.update({'make_lock': make_lock, 'locked_by': locked_by}) fix_PATH() log.debug('HOOKS extras is %s' % extras) baseui = make_ui('db') self.__inject_extras(repo_path, baseui, extras) try: self._handle_githooks(repo_name, action, baseui, environ) log.info('%s action on GIT repo "%s" by "%s" from %s' % (action, str_repo_name, safe_str(username), ip_addr)) app = self.__make_app(repo_name, repo_path, extras) return app(environ, start_response) except HTTPLockedRC, e: _code = CONFIG.get('lock_ret_code') log.debug('Repository LOCKED ret code %s!' % (_code)) return e(environ, start_response)