Ejemplo n.º 1
0
        def validate_python(self, value, state):
            from kallithea.lib import auth_modules

            password = value['password']
            username = value['username']

            # authenticate returns unused dict but has called
            # plugin._authenticate which has create_or_update'ed the username user in db
            if auth_modules.authenticate(username, password) is None:
                user = User.get_by_username_or_email(username)
                if user and not user.active:
                    log.warning('user %s is disabled', username)
                    msg = self.message('invalid_auth', state)
                    raise formencode.Invalid(msg,
                                             value,
                                             state,
                                             error_dict=dict(username='******',
                                                             password=msg))
                else:
                    log.warning('user %s failed to authenticate', username)
                    msg = self.message('invalid_auth', state)
                    raise formencode.Invalid(msg,
                                             value,
                                             state,
                                             error_dict=dict(username='******',
                                                             password=msg))
Ejemplo n.º 2
0
    def index(self):
        c.came_from = request.GET.get('came_from', '')
        if c.came_from:
            if not self._validate_came_from(c.came_from):
                log.error('Invalid came_from (not server-relative): %r',
                          c.came_from)
                raise HTTPBadRequest()
        else:
            c.came_from = url('home')

        if request.POST:
            # import Login Form validator class
            login_form = LoginForm()()
            try:
                # login_form will check username/password using ValidAuth and report failure to the user
                c.form_result = login_form.to_python(dict(request.POST))
                username = c.form_result['username']
                user = User.get_by_username_or_email(username)
                assert user is not None  # the same user get just passed in the form validation
            except formencode.Invalid as errors:
                defaults = errors.value
                # remove password from filling in form again
                defaults.pop('password', None)
                return htmlfill.render(render('/login.html'),
                                       defaults=errors.value,
                                       errors=errors.error_dict or {},
                                       prefix_error=False,
                                       encoding="UTF-8",
                                       force_defaults=False)
            except UserCreationError as e:
                # 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
                h.flash(e, 'error')
            else:
                # login_form already validated the password - now set the session cookie accordingly
                auth_user = log_in_user(user,
                                        c.form_result['remember'],
                                        is_external_auth=False,
                                        ip_addr=request.ip_addr)
                if auth_user:
                    raise HTTPFound(location=c.came_from)
                h.flash(_('Authentication failed.'), 'error')
        else:
            # redirect if already logged in
            if not request.authuser.is_anonymous:
                raise HTTPFound(location=c.came_from)
            # continue to show login to default user

        return render('/login.html')
Ejemplo n.º 3
0
    def index(self):
        c.came_from = safe_str(request.GET.get('came_from', ''))
        if c.came_from:
            if not self._validate_came_from(c.came_from):
                log.error('Invalid came_from (not server-relative): %r', c.came_from)
                raise HTTPBadRequest()
        else:
            c.came_from = url('home')

        ip_allowed = AuthUser.check_ip_allowed(self.authuser, self.ip_addr)

        # redirect if already logged in
        if self.authuser.is_authenticated and ip_allowed:
            raise HTTPFound(location=c.came_from)

        if request.POST:
            # import Login Form validator class
            login_form = LoginForm()
            try:
                c.form_result = login_form.to_python(dict(request.POST))
                # form checks for username/password, now we're authenticated
                username = c.form_result['username']
                user = User.get_by_username_or_email(username, case_insensitive=True)
            except formencode.Invalid as errors:
                defaults = errors.value
                # remove password from filling in form again
                del defaults['password']
                return htmlfill.render(
                    render('/login.html'),
                    defaults=errors.value,
                    errors=errors.error_dict or {},
                    prefix_error=False,
                    encoding="UTF-8",
                    force_defaults=False)
            except UserCreationError as e:
                # 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
                h.flash(e, 'error')
            else:
                log_in_user(user, c.form_result['remember'],
                    is_external_auth=False)
                raise HTTPFound(location=c.came_from)

        return render('/login.html')
Ejemplo n.º 4
0
    def index(self):
        c.came_from = safe_str(request.GET.get('came_from', ''))
        if c.came_from:
            if not self._validate_came_from(c.came_from):
                log.error('Invalid came_from (not server-relative): %r', c.came_from)
                raise HTTPBadRequest()
        else:
            c.came_from = url('home')

        ip_allowed = AuthUser.check_ip_allowed(request.authuser, request.ip_addr)

        # redirect if already logged in
        if request.authuser.is_authenticated and ip_allowed:
            raise HTTPFound(location=c.came_from)

        if request.POST:
            # import Login Form validator class
            login_form = LoginForm()()
            try:
                c.form_result = login_form.to_python(dict(request.POST))
                # form checks for username/password, now we're authenticated
                username = c.form_result['username']
                user = User.get_by_username_or_email(username, case_insensitive=True)
            except formencode.Invalid as errors:
                defaults = errors.value
                # remove password from filling in form again
                defaults.pop('password', None)
                return htmlfill.render(
                    render('/login.html'),
                    defaults=errors.value,
                    errors=errors.error_dict or {},
                    prefix_error=False,
                    encoding="UTF-8",
                    force_defaults=False)
            except UserCreationError as e:
                # 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
                h.flash(e, 'error')
            else:
                log_in_user(user, c.form_result['remember'],
                    is_external_auth=False)
                raise HTTPFound(location=c.came_from)

        return render('/login.html')
Ejemplo n.º 5
0
    def get_user(self, username=None, **kwargs):
        """
        Helper method for user fetching in plugins, by default it's using
        simple fetch by username, but this method can be customized in plugins
        eg. container auth plugin to fetch user by environ params

        :param username: username if given to fetch from database
        :param kwargs: extra arguments needed for user fetching.
        """
        user = None
        log.debug('Trying to fetch user `%s` from Kallithea database',
                  username)
        if username:
            user = User.get_by_username_or_email(username)
        else:
            log.debug('provided username:`%s` is empty skipping...', username)
        return user
Ejemplo n.º 6
0
    def get_user(self, username=None, **kwargs):
        """
        Helper method for user fetching in plugins, by default it's using
        simple fetch by username, but this method can be customized in plugins
        eg. container auth plugin to fetch user by environ params

        :param username: username if given to fetch from database
        :param kwargs: extra arguments needed for user fetching.
        """
        user = None
        log.debug('Trying to fetch user `%s` from Kallithea database',
                  username)
        if username:
            user = User.get_by_username_or_email(username)
            if user is None:
                log.debug('Fallback to fetch user in case insensitive mode')
                user = User.get_by_username(username, case_insensitive=True)
        else:
            log.debug('provided username:`%s` is empty skipping...', username)
        return user
Ejemplo n.º 7
0
        def validate_python(self, value, state):
            from kallithea.lib import auth_modules

            password = value['password']
            username = value['username']

            # authenticate returns unused dict but has called
            # plugin._authenticate which has create_or_update'ed the username user in db
            if auth_modules.authenticate(username, password) is None:
                user = User.get_by_username_or_email(username)
                if user and not user.active:
                    log.warning('user %s is disabled', username)
                    msg = M(self, 'invalid_auth', state)
                    raise formencode.Invalid(msg, value, state,
                        error_dict=dict(username='******', password=msg)
                    )
                else:
                    log.warning('user %s failed to authenticate', username)
                    msg = M(self, 'invalid_auth', state)
                    raise formencode.Invalid(msg, value, state,
                        error_dict=dict(username='******', password=msg)
                    )
Ejemplo n.º 8
0
    def _authorize(self, environ, start_response, action, repo_name, ip_addr):
        """Authenticate and authorize user.

        Since we're dealing with a VCS client and not a browser, we only
        support HTTP basic authentication, either directly via raw header
        inspection, or by using container authentication to delegate the
        authentication to the web server.

        Returns (user, None) on successful authentication and authorization.
        Returns (None, wsgi_app) to send the wsgi_app response to the client.
        """
        # Check if anonymous access is allowed.
        default_user = User.get_default_user(cache=True)
        is_default_user_allowed = (default_user.active and
            self._check_permission(action, default_user, repo_name, ip_addr))
        if is_default_user_allowed:
            return default_user, None

        if not default_user.active:
            log.debug('Anonymous access is disabled')
        else:
            log.debug('Not authorized to access this '
                      'repository as anonymous user')

        username = None
        #==============================================================
        # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE
        # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS
        #==============================================================

        # try to auth based on environ, container auth methods
        log.debug('Running PRE-AUTH for container based authentication')
        pre_auth = auth_modules.authenticate('', '', environ)
        if pre_auth is not None and pre_auth.get('username'):
            username = pre_auth['username']
        log.debug('PRE-AUTH got %s as username', username)

        # If not authenticated by the container, running basic auth
        if not username:
            self.authenticate.realm = safe_str(self.config['realm'])
            result = self.authenticate(environ)
            if isinstance(result, str):
                paste.httpheaders.AUTH_TYPE.update(environ, 'basic')
                paste.httpheaders.REMOTE_USER.update(environ, result)
                username = result
            else:
                return None, result.wsgi_application

        #==============================================================
        # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME
        #==============================================================
        try:
            user = User.get_by_username_or_email(username)
            if user is None or not user.active:
                return None, webob.exc.HTTPForbidden()
        except Exception:
            log.error(traceback.format_exc())
            return None, webob.exc.HTTPInternalServerError()

        #check permissions for this repository
        perm = self._check_permission(action, user, repo_name, ip_addr)
        if not perm:
            return None, webob.exc.HTTPForbidden()

        return user, None
Ejemplo n.º 9
0
    def _handle_request(self, environ, start_response):
        if not is_git(environ):
            return self.application(environ, start_response)
        if not self._check_ssl(environ):
            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:
            str_repo_name = self.__get_repository(environ)
            repo_name = safe_unicode(str_repo_name)
            log.debug('Extracted repo name is %s', repo_name)
        except Exception as e:
            log.error('error extracting repo_name: %r', e)
            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 = User.get_default_user(cache=True)
            username = anonymous_user.username
            if anonymous_user.active:
                # ONLY check permissions if the user is activated
                anonymous_perm = self._check_permission(action, anonymous_user,
                                                        repo_name, ip_addr)
            else:
                anonymous_perm = False

            if not anonymous_user.active or not anonymous_perm:
                if not anonymous_user.active:
                    log.debug('Anonymous access is disabled, running '
                              'authentication')

                if not anonymous_perm:
                    log.debug('Not enough credentials to access this '
                              'repository as anonymous user')

                username = None
                #==============================================================
                # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE
                # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS
                #==============================================================

                # try to auth based on environ, container auth methods
                log.debug('Running PRE-AUTH for container based authentication')
                pre_auth = auth_modules.authenticate('', '', environ)
                if pre_auth is not None and pre_auth.get('username'):
                    username = pre_auth['username']
                log.debug('PRE-AUTH got %s as username', username)

                # If not authenticated by the container, running basic auth
                if not username:
                    self.authenticate.realm = \
                        safe_str(self.config['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 = User.get_by_username_or_email(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 kallithea
        from kallithea 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
        #===================================================================
        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)
            result = app(environ, start_response)
            if action == 'push':
                result = WSGIResultCloseCallback(result,
                    lambda: self._invalidate_cache(repo_name))
            return result
        except HTTPLockedRC as e:
            _code = CONFIG.get('lock_ret_code')
            log.debug('Repository LOCKED ret code %s!', _code)
            return e(environ, start_response)
        except Exception:
            log.error(traceback.format_exc())
            return HTTPInternalServerError()(environ, start_response)