Exemple #1
0
    def _store_user_in_session(self, username, remember=False):
        user = User.get_by_username(username, case_insensitive=True)
        auth_user = AuthUser(user.user_id)
        auth_user.set_authenticated()
        cs = auth_user.get_cookie_store()
        session['authuser'] = cs
        user.update_lastlogin()
        Session().commit()

        # If they want to be remembered, update the cookie
        if remember:
            _year = (datetime.datetime.now() +
                     datetime.timedelta(seconds=60 * 60 * 24 * 365))
            session._set_cookie_expires(_year)

        session.save()

        log.info('user %s is now authenticated and stored in '
                 'session, session attrs %s' % (username, cs))

        # dumps session attrs back to cookie
        session._update_cookie_out()
        # we set new cookie
        headers = None
        if session.request['set_cookie']:
            # send set-cookie headers back to response to update cookie
            headers = [('Set-Cookie', session.request['cookie_out'])]
        return headers
Exemple #2
0
    def get_all_user_repos(self, user):
        """
        Gets all repositories that user have at least read access

        :param user:
        """
        from kallithea.lib.auth import AuthUser
        user = self._get_user(user)
        repos = AuthUser(user_id=user.user_id).permissions['repositories']
        access_check = lambda r: r[1] in ['repository.read',
                                          'repository.write',
                                          'repository.admin']
        repos = [x[0] for x in filter(access_check, repos.items())]
        return Repository.query().filter(Repository.repo_name.in_(repos))
Exemple #3
0
    def _check_permission(self, action, user, repo_name, ip_addr=None):
        """
        Checks permissions using action (push/pull) user and repository
        name

        :param action: push or pull action
        :param user: `User` instance
        :param repo_name: repository name
        """
        # check IP
        ip_allowed = AuthUser.check_ip_allowed(user, ip_addr)
        if ip_allowed:
            log.info('Access for IP:%s allowed', ip_addr)
        else:
            return False

        if action == 'push':
            if not HasPermissionAnyMiddleware('repository.write',
                                              'repository.admin')(user,
                                                                  repo_name):
                return False

        else:
            #any other action need at least read permission
            if not HasPermissionAnyMiddleware('repository.read',
                                              'repository.write',
                                              'repository.admin')(user,
                                                                  repo_name):
                return False

        return True
Exemple #4
0
 def _render_edit_profile(self, user):
     c.user = user
     c.active = 'profile'
     c.perm_user = AuthUser(dbuser=user)
     managed_fields = auth_modules.get_managed_fields(user)
     c.readonly = lambda n: 'readonly' if n in managed_fields else None
     return render('admin/users/user_edit.html')
    def test_inactive_user_group_does_not_affect_repo_permissions_inverse(
            self):
        self.ug1 = fixture.create_user_group('G1')
        user_group_model = UserGroupModel()
        user_group_model.add_user_to_group(self.ug1, self.u1)
        user_group_model.update(self.ug1, {'users_group_active': False})

        # note: make u2 repo owner rather than u1, because the owner always has
        # admin permissions
        self.test_repo = fixture.create_repo(name='myownrepo',
                                             repo_type='hg',
                                             cur_user=self.u2)

        # enable only write access for user group on repo
        RepoModel().grant_user_group_permission(self.test_repo,
                                                group_name=self.ug1,
                                                perm='repository.write')
        # enable admin access for default user on repo
        RepoModel().grant_user_permission(self.test_repo,
                                          user='******',
                                          perm='repository.admin')
        Session().commit()
        u1_auth = AuthUser(user_id=self.u1.user_id)
        assert u1_auth.permissions['repositories'][
            'myownrepo'] == 'repository.admin'
    def test_inactive_user_group_does_not_affect_global_permissions_inverse(
            self):
        # Add user to inactive user group, set specific permissions on user
        # group and and verify it really is inactive.
        self.ug1 = fixture.create_user_group('G1')
        user_group_model = UserGroupModel()
        user_group_model.add_user_to_group(self.ug1, self.u1)
        user_group_model.update(self.ug1, {'users_group_active': False})

        # disable fork and create on user group
        user_group_model.revoke_perm(self.ug1, perm='hg.create.repository')
        user_group_model.grant_perm(self.ug1, perm='hg.create.none')
        user_group_model.revoke_perm(self.ug1, perm='hg.fork.repository')
        user_group_model.grant_perm(self.ug1, perm='hg.fork.none')

        user_model = UserModel()
        # enable fork and create on default user
        usr = '******'
        user_model.revoke_perm(usr, 'hg.create.none')
        user_model.grant_perm(usr, 'hg.create.repository')
        user_model.revoke_perm(usr, 'hg.fork.none')
        user_model.grant_perm(usr, 'hg.fork.repository')

        Session().commit()
        u1_auth = AuthUser(user_id=self.u1.user_id)

        assert u1_auth.permissions['global'] == set([
            'hg.create.repository', 'hg.fork.repository',
            'hg.register.manual_activate', 'hg.extern_activate.auto',
            'repository.read', 'group.read', 'usergroup.read',
            'hg.create.write_on_repogroup.true'
        ])
Exemple #7
0
def _get_perms(filter_='', recursive=None, key=None, test_u1_id=None):
    test_u1 = AuthUser(user_id=test_u1_id)
    for k, v in test_u1.permissions[key].items():
        if recursive in ['all', 'repos', 'groups'] and k.startswith(filter_):
            yield k, v
        elif recursive in ['none']:
            if k == filter_:
                yield k, v
Exemple #8
0
    def test_owner_permissions_doesnot_get_overwritten_by_others(self):
        #create repo as USER,
        self.test_repo = fixture.create_repo(name='myownrepo',
                                             repo_type='hg',
                                             cur_user=self.u1)

        #he has permissions of admin as owner
        u1_auth = AuthUser(user_id=self.u1.user_id)
        self.assertEqual(u1_auth.permissions['repositories']['myownrepo'],
                         'repository.admin')
        #set his permission as user, he should still be admin
        RepoModel().grant_user_permission(self.test_repo,
                                          user=self.u1,
                                          perm='repository.none')
        Session().commit()
        u1_auth = AuthUser(user_id=self.u1.user_id)
        self.assertEqual(u1_auth.permissions['repositories']['myownrepo'],
                         'repository.admin')
Exemple #9
0
    def my_account(self):
        """
        GET /_admin/my_account Displays info about my account
        """
        # url('my_account')
        c.active = 'profile'
        self.__load_data()
        c.perm_user = AuthUser(user_id=self.authuser.user_id,
                               ip_addr=self.ip_addr)
        c.extern_type = c.user.extern_type
        c.extern_name = c.user.extern_name

        defaults = c.user.get_dict()
        update = False
        if request.POST:
            _form = UserForm(edit=True,
                             old_data={
                                 'user_id': self.authuser.user_id,
                                 'email': self.authuser.email
                             })()
            form_result = {}
            try:
                post_data = dict(request.POST)
                post_data['new_password'] = ''
                post_data['password_confirmation'] = ''
                form_result = _form.to_python(post_data)
                # skip updating those attrs for my account
                skip_attrs = [
                    'admin', 'active', 'extern_type', 'extern_name',
                    'new_password', 'password_confirmation'
                ]
                #TODO: plugin should define if username can be updated
                if c.extern_type != EXTERN_TYPE_INTERNAL:
                    # forbid updating username for external accounts
                    skip_attrs.append('username')

                UserModel().update(self.authuser.user_id,
                                   form_result,
                                   skip_attrs=skip_attrs)
                h.flash(_('Your account was updated successfully'),
                        category='success')
                Session().commit()
                update = True

            except formencode.Invalid, errors:
                return htmlfill.render(
                    render('admin/my_account/my_account.html'),
                    defaults=errors.value,
                    errors=errors.error_dict or {},
                    prefix_error=False,
                    encoding="UTF-8",
                    force_defaults=False)
            except Exception:
                log.error(traceback.format_exc())
                h.flash(_('Error occurred during update of user %s') \
                        % form_result.get('username'), category='error')
 def test_default_admin_group_perms(self):
     self.g1 = fixture.create_repo_group('test1', skip_if_exists=True)
     self.g2 = fixture.create_repo_group('test2', skip_if_exists=True)
     a1_auth = AuthUser(user_id=self.a1.user_id)
     assert a1_auth.permissions['repositories'][
         base.HG_REPO] == 'repository.admin'
     assert a1_auth.permissions['repositories_groups'].get(
         'test1') == 'group.admin'
     assert a1_auth.permissions['repositories_groups'].get(
         'test2') == 'group.admin'
    def my_account(self):
        c.active = 'profile'
        self.__load_data()
        c.perm_user = AuthUser(user_id=request.authuser.user_id)
        managed_fields = auth_modules.get_managed_fields(c.user)
        def_user_perms = User.get_default_user().AuthUser.permissions['global']
        if 'hg.register.none' in def_user_perms:
            managed_fields.extend(['username', 'firstname', 'lastname', 'email'])

        c.readonly = lambda n: 'readonly' if n in managed_fields else None

        defaults = c.user.get_dict()
        update = False
        if request.POST:
            _form = UserForm(edit=True,
                             old_data={'user_id': request.authuser.user_id,
                                       'email': request.authuser.email})()
            form_result = {}
            try:
                post_data = dict(request.POST)
                post_data['new_password'] = ''
                post_data['password_confirmation'] = ''
                form_result = _form.to_python(post_data)
                # skip updating those attrs for my account
                skip_attrs = ['admin', 'active', 'extern_type', 'extern_name',
                              'new_password', 'password_confirmation',
                             ] + managed_fields

                UserModel().update(request.authuser.user_id, form_result,
                                   skip_attrs=skip_attrs)
                h.flash(_('Your account was updated successfully'),
                        category='success')
                Session().commit()
                update = True

            except formencode.Invalid as errors:
                return htmlfill.render(
                    render('admin/my_account/my_account.html'),
                    defaults=errors.value,
                    errors=errors.error_dict or {},
                    prefix_error=False,
                    encoding="UTF-8",
                    force_defaults=False)
            except Exception:
                log.error(traceback.format_exc())
                h.flash(_('Error occurred during update of user %s') \
                        % form_result.get('username'), category='error')
        if update:
            raise HTTPFound(location='my_account')
        return htmlfill.render(
            render('admin/my_account/my_account.html'),
            defaults=defaults,
            encoding="UTF-8",
            force_defaults=False)
Exemple #12
0
    def _determine_auth_user(session_authuser, ip_addr):
        """
        Create an `AuthUser` object given the API key/bearer token
        (if any) and the value of the authuser session cookie.
        Returns None if no valid user is found (like not active or no access for IP).
        """

        # Authenticate by session cookie
        # In ancient login sessions, 'authuser' may not be a dict.
        # In that case, the user will have to log in again.
        # v0.3 and earlier included an 'is_authenticated' key; if present,
        # this must be True.
        if isinstance(session_authuser, dict) and session_authuser.get(
                'is_authenticated', True):
            return AuthUser.from_cookie(session_authuser, ip_addr=ip_addr)

        # Authenticate by auth_container plugin (if enabled)
        if any(plugin.is_container_auth
               for plugin in auth_modules.get_auth_plugins()):
            try:
                user_info = auth_modules.authenticate('', '', request.environ)
            except UserCreationError as e:
                from kallithea.lib import helpers as h
                h.flash(e, 'error', logf=log.error)
            else:
                if user_info is not None:
                    username = user_info['username']
                    user = User.get_by_username(username,
                                                case_insensitive=True)
                    return log_in_user(user,
                                       remember=False,
                                       is_external_auth=True,
                                       ip_addr=ip_addr)

        # User is default user (if active) or anonymous
        default_user = User.get_default_user()
        authuser = AuthUser.make(dbuser=default_user, ip_addr=ip_addr)
        if authuser is None:  # fall back to anonymous
            authuser = AuthUser(
                dbuser=default_user)  # TODO: somehow use .make?
        return authuser
Exemple #13
0
 def test_default_admin_perms_set(self):
     a1_auth = AuthUser(user_id=self.a1.user_id)
     perms = {
         'repositories_groups': {},
         'global': set([u'hg.admin', 'hg.create.write_on_repogroup.true']),
         'repositories': {
             u'vcs_test_hg': u'repository.admin'
         }
     }
     self.assertEqual(a1_auth.permissions['repositories'][HG_REPO],
                      perms['repositories'][HG_REPO])
     new_perm = 'repository.write'
     RepoModel().grant_user_permission(repo=HG_REPO,
                                       user=self.a1,
                                       perm=new_perm)
     Session().commit()
     # cannot really downgrade admins permissions !? they still gets set as
     # admin !
     u1_auth = AuthUser(user_id=self.a1.user_id)
     self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
                      perms['repositories'][HG_REPO])
 def test_default_group_perms(self):
     self.g1 = fixture.create_repo_group('test1', skip_if_exists=True)
     self.g2 = fixture.create_repo_group('test2', skip_if_exists=True)
     u1_auth = AuthUser(user_id=self.u1.user_id)
     assert u1_auth.permissions['repositories'][
         base.HG_REPO] == 'repository.read'
     assert u1_auth.permissions['repositories_groups'].get(
         'test1') == 'group.read'
     assert u1_auth.permissions['repositories_groups'].get(
         'test2') == 'group.read'
     assert u1_auth.permissions['global'] == set(
         Permission.DEFAULT_USER_PERMISSIONS)
    def test_owner_permissions_doesnot_get_overwritten_by_group(self):
        #create repo as USER,
        self.test_repo = fixture.create_repo(name=u'myownrepo',
                                             repo_type='hg',
                                             cur_user=self.u1)

        #he has permissions of admin as owner
        u1_auth = AuthUser(user_id=self.u1.user_id)
        assert u1_auth.permissions['repositories'][
            'myownrepo'] == 'repository.admin'
        #set his permission as user group, he should still be admin
        self.ug1 = fixture.create_user_group(u'G1')
        UserGroupModel().add_user_to_group(self.ug1, self.u1)
        RepoModel().grant_user_group_permission(self.test_repo,
                                                group_name=self.ug1,
                                                perm='repository.none')

        Session().commit()
        u1_auth = AuthUser(user_id=self.u1.user_id)
        assert u1_auth.permissions['repositories'][
            'myownrepo'] == 'repository.admin'
Exemple #16
0
    def __call__(self, environ, start_response):
        """Invoke the Controller"""
        # WSGIController.__call__ dispatches to the Controller method
        # the request is routed to. This routing information is
        # available in environ['pylons.routes_dict']
        try:
            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')

            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('authuser'))
                try:
                    auth_user = AuthUser(user_id=cookie_store.get('user_id', None),
                                         ip_addr=self.ip_addr)
                except UserCreationError, e:
                    from kallithea.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.authuser = c.authuser = auth_user
            log.info('IP: %s User: %s accessed %s' % (
               self.ip_addr, auth_user, safe_unicode(_get_access_path(environ)))
            )
            return WSGIController.__call__(self, environ, start_response)
Exemple #17
0
    def register(self):
        def_user_perms = AuthUser(
            dbuser=User.get_default_user()).permissions['global']
        c.auto_active = 'hg.register.auto_activate' in def_user_perms

        settings = Setting.get_app_settings()
        captcha_private_key = settings.get('captcha_private_key')
        c.captcha_active = bool(captcha_private_key)
        c.captcha_public_key = settings.get('captcha_public_key')

        if request.POST:
            register_form = RegisterForm()()
            try:
                form_result = register_form.to_python(dict(request.POST))
                form_result['active'] = c.auto_active

                if c.captcha_active:
                    from kallithea.lib.recaptcha import submit
                    response = submit(request.POST.get('g-recaptcha-response'),
                                      private_key=captcha_private_key,
                                      remoteip=request.ip_addr)
                    if not response.is_valid:
                        _value = form_result
                        _msg = _('Bad captcha')
                        error_dict = {'recaptcha_field': _msg}
                        raise formencode.Invalid(_msg,
                                                 _value,
                                                 None,
                                                 error_dict=error_dict)

                UserModel().create_registration(form_result)
                h.flash(_('You have successfully registered with %s') %
                        (c.site_name or 'Kallithea'),
                        category='success')
                Session().commit()
                raise HTTPFound(location=url('login_home'))

            except formencode.Invalid as errors:
                return htmlfill.render(render('/register.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')

        return render('/register.html')
    def test_propagated_permission_from_users_group(self):
        # make group
        self.ug1 = fixture.create_user_group('G1')
        UserGroupModel().add_user_to_group(self.ug1, self.u3)

        # grant perm for group this should override default permission from user
        new_perm_gr = 'repository.write'
        RepoModel().grant_user_group_permission(repo=base.HG_REPO,
                                                group_name=self.ug1,
                                                perm=new_perm_gr)
        # check perms
        u3_auth = AuthUser(user_id=self.u3.user_id)
        assert u3_auth.permissions['repositories'][base.HG_REPO] == new_perm_gr
Exemple #19
0
    def test_propagated_permission_from_users_group_lower_weight(self):
        # make group
        self.ug1 = fixture.create_user_group('G1')
        # add user to group
        UserGroupModel().add_user_to_group(self.ug1, self.u1)

        # set permission to lower
        new_perm_h = 'repository.write'
        RepoModel().grant_user_permission(repo=HG_REPO,
                                          user=self.u1,
                                          perm=new_perm_h)
        Session().commit()
        u1_auth = AuthUser(user_id=self.u1.user_id)
        self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
                         new_perm_h)

        # grant perm for group this should NOT override permission from user
        # since it's lower than granted
        new_perm_l = 'repository.read'
        RepoModel().grant_user_group_permission(repo=HG_REPO,
                                                group_name=self.ug1,
                                                perm=new_perm_l)
        # check perms
        u1_auth = AuthUser(user_id=self.u1.user_id)
        perms = {
            'repositories_groups': {},
            'global':
            set([
                u'hg.create.repository', u'repository.read',
                u'hg.register.manual_activate'
            ]),
            'repositories': {
                u'vcs_test_hg': u'repository.write'
            }
        }
        self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
                         new_perm_h)
        self.assertEqual(u1_auth.permissions['repositories_groups'],
                         perms['repositories_groups'])
Exemple #20
0
    def update(self, id):
        """PUT /users/id: Update an existing item"""
        # Forms posted to this method should contain a hidden field:
        #    <input type="hidden" name="_method" value="PUT" />
        # Or using helpers:
        #    h.form(url('update_user', id=ID),
        #           method='put')
        # url('user', id=ID)
        c.active = 'profile'
        user_model = UserModel()
        c.user = user_model.get(id)
        c.extern_type = c.user.extern_type
        c.extern_name = c.user.extern_name
        c.perm_user = AuthUser(user_id=id, ip_addr=self.ip_addr)
        _form = UserForm(edit=True,
                         old_data={
                             'user_id': id,
                             'email': c.user.email
                         })()
        form_result = {}
        try:
            form_result = _form.to_python(dict(request.POST))
            skip_attrs = ['extern_type', 'extern_name']
            #TODO: plugin should define if username can be updated
            if c.extern_type != kallithea.EXTERN_TYPE_INTERNAL:
                # forbid updating username for external accounts
                skip_attrs.append('username')

            user_model.update(id, form_result, skip_attrs=skip_attrs)
            usr = form_result['username']
            action_logger(self.authuser, 'admin_updated_user:%s' % usr, None,
                          self.ip_addr, self.sa)
            h.flash(_('User updated successfully'), category='success')
            Session().commit()
        except formencode.Invalid, errors:
            defaults = errors.value
            e = errors.error_dict or {}
            defaults.update({
                'create_repo_perm':
                user_model.has_perm(id, 'hg.create.repository'),
                'fork_repo_perm':
                user_model.has_perm(id, 'hg.fork.repository'),
                '_method':
                'put'
            })
            return htmlfill.render(render('admin/users/user_edit.html'),
                                   defaults=defaults,
                                   errors=e,
                                   prefix_error=False,
                                   encoding="UTF-8",
                                   force_defaults=False)
Exemple #21
0
    def __call__(self, environ, context):
        try:
            ip_addr = _get_ip_addr(environ)
            self._basic_security_checks()

            api_key = request.GET.get('api_key')
            try:
                # Request.authorization may raise ValueError on invalid input
                type, params = request.authorization
            except (ValueError, TypeError):
                pass
            else:
                if type.lower() == 'bearer':
                    api_key = params  # bearer token is an api key too

            if api_key is None:
                authuser = self._determine_auth_user(
                    session.get('authuser'),
                    ip_addr=ip_addr,
                )
                needs_csrf_check = request.method not in ['GET', 'HEAD']

            else:
                dbuser = User.get_by_api_key(api_key)
                if dbuser is None:
                    log.info(
                        'No db user found for authentication with API key ****%s from %s',
                        api_key[-4:], ip_addr)
                authuser = AuthUser.make(dbuser=dbuser,
                                         is_external_auth=True,
                                         ip_addr=ip_addr)
                needs_csrf_check = False  # API key provides CSRF protection

            if authuser is None:
                log.info('No valid user found')
                raise webob.exc.HTTPForbidden()

            # set globals for auth user
            request.authuser = authuser
            request.ip_addr = ip_addr
            request.needs_csrf_check = needs_csrf_check

            log.info(
                'IP: %s User: %s Request: %s',
                request.ip_addr,
                request.authuser,
                get_path_info(environ),
            )
            return super(BaseController, self).__call__(environ, context)
        except webob.exc.HTTPException as e:
            return e
Exemple #22
0
    def get_all_user_repos(self, user):
        """
        Gets all repositories that user have at least read access

        :param user:
        """
        from kallithea.lib.auth import AuthUser
        auth_user = AuthUser(dbuser=User.guess_instance(user))
        repos = [
            repo_name for repo_name, perm in
            auth_user.permissions['repositories'].items() if perm in
            ['repository.read', 'repository.write', 'repository.admin']
        ]
        return Repository.query().filter(Repository.repo_name.in_(repos))
    def test_default_perms_set(self):
        u1_auth = AuthUser(user_id=self.u1.user_id)
        perms = {
            'repositories_groups': {},
            'global':
            set([
                'hg.create.repository', 'repository.read',
                'hg.register.manual_activate'
            ]),
            'repositories': {
                HG_REPO: 'repository.read'
            }
        }
        assert u1_auth.permissions['repositories'][HG_REPO] == perms[
            'repositories'][HG_REPO]
        new_perm = 'repository.write'
        RepoModel().grant_user_permission(repo=HG_REPO,
                                          user=self.u1,
                                          perm=new_perm)
        Session().commit()

        u1_auth = AuthUser(user_id=self.u1.user_id)
        assert u1_auth.permissions['repositories'][HG_REPO] == new_perm
    def test_propagated_permission_from_users_group_by_explicit_perms_exist(
            self):
        # make group
        self.ug1 = fixture.create_user_group(u'G1')
        UserGroupModel().add_user_to_group(self.ug1, self.u1)

        # set permission to lower
        new_perm = 'repository.none'
        RepoModel().grant_user_permission(repo=HG_REPO,
                                          user=self.u1,
                                          perm=new_perm)
        Session().commit()
        u1_auth = AuthUser(user_id=self.u1.user_id)
        assert u1_auth.permissions['repositories'][HG_REPO] == new_perm

        # grant perm for group this should not override permission from user
        # since it has explicitly set
        new_perm_gr = 'repository.write'
        RepoModel().grant_user_group_permission(repo=HG_REPO,
                                                group_name=self.ug1,
                                                perm=new_perm_gr)
        # check perms
        u1_auth = AuthUser(user_id=self.u1.user_id)
        perms = {
            'repositories_groups': {},
            'global':
            set([
                'hg.create.repository', 'repository.read',
                'hg.register.manual_activate'
            ]),
            'repositories': {
                HG_REPO: 'repository.read'
            }
        }
        assert u1_auth.permissions['repositories'][HG_REPO] == new_perm
        assert u1_auth.permissions['repositories_groups'] == perms[
            'repositories_groups']
Exemple #25
0
def log_in_user(user, remember, is_external_auth):
    """
    Log a `User` in and update session and cookies. If `remember` is True,
    the session cookie is set to expire in a year; otherwise, it expires at
    the end of the browser session.

    Returns populated `AuthUser` object.
    """
    user.update_lastlogin()
    meta.Session().commit()

    auth_user = AuthUser(dbuser=user,
                         is_external_auth=is_external_auth)
    # It should not be possible to explicitly log in as the default user.
    assert not auth_user.is_default_user
    auth_user.is_authenticated = True

    # Start new session to prevent session fixation attacks.
    session.invalidate()
    session['authuser'] = cookie = auth_user.to_cookie()

    # If they want to be remembered, update the cookie.
    # NOTE: Assumes that beaker defaults to browser session cookie.
    if remember:
        t = datetime.datetime.now() + datetime.timedelta(days=365)
        session._set_cookie_expires(t)

    session.save()

    log.info('user %s is now authenticated and stored in '
             'session, session attrs %s', user.username, cookie)

    # dumps session attrs back to cookie
    session._update_cookie_out()

    return auth_user
    def test_propagated_permission_from_users_group_lower_weight(self):
        # make group
        self.ug1 = fixture.create_user_group('G1')
        # add user to group
        UserGroupModel().add_user_to_group(self.ug1, self.u1)

        # set permission to lower
        new_perm_h = 'repository.write'
        RepoModel().grant_user_permission(repo=base.HG_REPO,
                                          user=self.u1,
                                          perm=new_perm_h)
        Session().commit()
        u1_auth = AuthUser(user_id=self.u1.user_id)
        assert u1_auth.permissions['repositories'][base.HG_REPO] == new_perm_h

        # grant perm for group this should NOT override permission from user
        # since it's lower than granted
        new_perm_l = 'repository.read'
        RepoModel().grant_user_group_permission(repo=base.HG_REPO,
                                                group_name=self.ug1,
                                                perm=new_perm_l)
        # check perms
        u1_auth = AuthUser(user_id=self.u1.user_id)
        assert u1_auth.permissions['repositories'][base.HG_REPO] == new_perm_h
Exemple #27
0
    def test_default_perms_set(self):
        u1_auth = AuthUser(user_id=self.u1.user_id)
        perms = {
            'repositories_groups': {},
            'global':
            set([
                u'hg.create.repository', u'repository.read',
                u'hg.register.manual_activate'
            ]),
            'repositories': {
                u'vcs_test_hg': u'repository.read'
            }
        }
        self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
                         perms['repositories'][HG_REPO])
        new_perm = 'repository.write'
        RepoModel().grant_user_permission(repo=HG_REPO,
                                          user=self.u1,
                                          perm=new_perm)
        Session().commit()

        u1_auth = AuthUser(user_id=self.u1.user_id)
        self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
                         new_perm)
Exemple #28
0
def log_in_user(user, remember, is_external_auth):
    """
    Log a `User` in and update session and cookies. If `remember` is True,
    the session cookie is set to expire in a year; otherwise, it expires at
    the end of the browser session.

    Returns populated `AuthUser` object.
    """
    user.update_lastlogin()
    meta.Session().commit()

    auth_user = AuthUser(dbuser=user,
                         is_external_auth=is_external_auth)
    # It should not be possible to explicitly log in as the default user.
    assert not auth_user.is_default_user
    auth_user.is_authenticated = True

    # Start new session to prevent session fixation attacks.
    session.invalidate()
    session['authuser'] = cookie = auth_user.to_cookie()

    # If they want to be remembered, update the cookie.
    # NOTE: Assumes that beaker defaults to browser session cookie.
    if remember:
        t = datetime.datetime.now() + datetime.timedelta(days=365)
        session._set_cookie_expires(t)

    session.save()

    log.info('user %s is now authenticated and stored in '
             'session, session attrs %s', user.username, cookie)

    # dumps session attrs back to cookie
    session._update_cookie_out()

    return auth_user
    def test_propagated_permission_from_users_group_by_explicit_perms_exist(
            self):
        # make group
        self.ug1 = fixture.create_user_group('G1')
        UserGroupModel().add_user_to_group(self.ug1, self.u1)

        # set user permission none
        RepoModel().grant_user_permission(repo=base.HG_REPO,
                                          user=self.u1,
                                          perm='repository.none')
        Session().commit()
        u1_auth = AuthUser(user_id=self.u1.user_id)
        assert u1_auth.permissions['repositories'][
            base.HG_REPO] == 'repository.read'  # inherit from default user

        # grant perm for group this should override permission from user
        RepoModel().grant_user_group_permission(repo=base.HG_REPO,
                                                group_name=self.ug1,
                                                perm='repository.write')

        # verify that user group permissions win
        u1_auth = AuthUser(user_id=self.u1.user_id)
        assert u1_auth.permissions['repositories'][
            base.HG_REPO] == 'repository.write'
 def test_inherit_sad_permissions_from_default_user(self):
     user_model = UserModel()
     # disable fork and create on default user
     usr = '******'
     user_model.revoke_perm(usr, 'hg.create.repository')
     user_model.grant_perm(usr, 'hg.create.none')
     user_model.revoke_perm(usr, 'hg.fork.repository')
     user_model.grant_perm(usr, 'hg.fork.none')
     Session().commit()
     u1_auth = AuthUser(user_id=self.u1.user_id)
     # this user will have inherited permissions from default user
     assert u1_auth.permissions['global'] == set([
         'hg.create.none', 'hg.fork.none', 'hg.register.manual_activate',
         'hg.extern_activate.auto', 'repository.read', 'group.read',
         'usergroup.read', 'hg.create.write_on_repogroup.true'
     ])
Exemple #31
0
    def _determine_auth_user(api_key, session_authuser):
        """
        Create an `AuthUser` object given the API key (if any) and the
        value of the authuser session cookie.
        """

        # Authenticate by API key
        if api_key:
            # when using API_KEY we are sure user exists.
            return AuthUser(dbuser=User.get_by_api_key(api_key),
                            is_external_auth=True)

        # Authenticate by session cookie
        # In ancient login sessions, 'authuser' may not be a dict.
        # In that case, the user will have to log in again.
        # v0.3 and earlier included an 'is_authenticated' key; if present,
        # this must be True.
        if isinstance(session_authuser, dict) and session_authuser.get('is_authenticated', True):
            try:
                return AuthUser.from_cookie(session_authuser)
            except UserCreationError as e:
                # container auth or other auth functions that create users on
                # the fly can throw UserCreationError to signal issues with
                # user creation. Explanation should be provided in the
                # exception object.
                from kallithea.lib import helpers as h
                h.flash(e, 'error', logf=log.error)

        # Authenticate by auth_container plugin (if enabled)
        if any(
            auth_modules.importplugin(name).is_container_auth
            for name in Setting.get_auth_plugins()
        ):
            try:
                user_info = auth_modules.authenticate('', '', request.environ)
            except UserCreationError as e:
                from kallithea.lib import helpers as h
                h.flash(e, 'error', logf=log.error)
            else:
                if user_info is not None:
                    username = user_info['username']
                    user = User.get_by_username(username, case_insensitive=True)
                    return log_in_user(user, remember=False,
                                       is_external_auth=True)

        # User is anonymous
        return AuthUser()
Exemple #32
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')
Exemple #33
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')
Exemple #34
0
    def edit_perms(self, id):
        c.user = self._get_user_or_raise_if_default(id)
        c.active = 'perms'
        c.perm_user = AuthUser(dbuser=c.user)

        umodel = UserModel()
        defaults = c.user.get_dict()
        defaults.update({
            'create_repo_perm': umodel.has_perm(c.user, 'hg.create.repository'),
            'create_user_group_perm': umodel.has_perm(c.user,
                                                      'hg.usergroup.create.true'),
            'fork_repo_perm': umodel.has_perm(c.user, 'hg.fork.repository'),
        })
        return htmlfill.render(
            render('admin/users/user_edit.html'),
            defaults=defaults,
            encoding="UTF-8",
            force_defaults=False)
Exemple #35
0
    def edit(self, id, format='html'):
        """GET /users/id/edit: Form to edit an existing item"""
        # url('edit_user', id=ID)
        c.user = User.get_or_404(id)
        if c.user.username == User.DEFAULT_USER:
            h.flash(_("You can't edit this user"), category='warning')
            return redirect(url('users'))

        c.active = 'profile'
        c.extern_type = c.user.extern_type
        c.extern_name = c.user.extern_name
        c.perm_user = AuthUser(user_id=id, ip_addr=self.ip_addr)

        defaults = c.user.get_dict()
        return htmlfill.render(render('admin/users/user_edit.html'),
                               defaults=defaults,
                               encoding="UTF-8",
                               force_defaults=False)
Exemple #36
0
    def __call__(self, environ, start_response):
        """Invoke the Controller"""
        # WSGIController.__call__ dispatches to the Controller method
        # the request is routed to. This routing information is
        # available in environ['pylons.routes_dict']
        try:
            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')

            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('authuser'))
                try:
                    auth_user = AuthUser(user_id=cookie_store.get(
                        'user_id', None),
                                         ip_addr=self.ip_addr)
                except UserCreationError, e:
                    from kallithea.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.authuser = c.authuser = auth_user
            log.info('IP: %s User: %s accessed %s' %
                     (self.ip_addr, auth_user,
                      safe_unicode(_get_access_path(environ))))
            return WSGIController.__call__(self, environ, start_response)
Exemple #37
0
    def test_default_admin_group_perms(self):
        self.g1 = fixture.create_repo_group('test1', skip_if_exists=True)
        self.g2 = fixture.create_repo_group('test2', skip_if_exists=True)
        a1_auth = AuthUser(user_id=self.a1.user_id)
        perms = {
            'repositories_groups': {
                u'test1': 'group.admin',
                u'test2': 'group.admin'
            },
            'global': set(['hg.admin', 'hg.create.write_on_repogroup.true']),
            'repositories': {
                u'vcs_test_hg': 'repository.admin'
            }
        }

        self.assertEqual(a1_auth.permissions['repositories'][HG_REPO],
                         perms['repositories'][HG_REPO])
        self.assertEqual(a1_auth.permissions['repositories_groups'],
                         perms['repositories_groups'])
Exemple #38
0
    def _dispatch(self, state, remainder=None):
        """
        Parse the request body as JSON, look up the method on the
        controller and if it exists, dispatch to it.
        """
        # Since we are here we should respond as JSON
        response.content_type = 'application/json'

        environ = state.request.environ
        start = time.time()
        ip_addr = request.ip_addr = self._get_ip_addr(environ)
        self._req_id = None
        if 'CONTENT_LENGTH' not in environ:
            log.debug("No Content-Length")
            raise JSONRPCErrorResponse(retid=self._req_id,
                                       message="No Content-Length in request")
        else:
            length = environ['CONTENT_LENGTH'] or 0
            length = int(environ['CONTENT_LENGTH'])
            log.debug('Content-Length: %s', length)

        if length == 0:
            raise JSONRPCErrorResponse(retid=self._req_id,
                                       message="Content-Length is 0")

        raw_body = environ['wsgi.input'].read(length)

        try:
            json_body = json.loads(raw_body)
        except ValueError as e:
            # catch JSON errors Here
            raise JSONRPCErrorResponse(retid=self._req_id,
                                       message="JSON parse error ERR:%s RAW:%r"
                                                % (e, raw_body))

        # check AUTH based on API key
        try:
            self._req_api_key = json_body['api_key']
            self._req_id = json_body['id']
            self._req_method = json_body['method']
            self._request_params = json_body['args']
            if not isinstance(self._request_params, dict):
                self._request_params = {}

            log.debug('method: %s, params: %s',
                      self._req_method, self._request_params)
        except KeyError as e:
            raise JSONRPCErrorResponse(retid=self._req_id,
                                       message='Incorrect JSON query missing %s' % e)

        # check if we can find this session using api_key
        try:
            u = User.get_by_api_key(self._req_api_key)
            if u is None:
                raise JSONRPCErrorResponse(retid=self._req_id,
                                           message='Invalid API key')

            auth_u = AuthUser(dbuser=u)
            if not AuthUser.check_ip_allowed(auth_u, ip_addr):
                raise JSONRPCErrorResponse(retid=self._req_id,
                                           message='request from IP:%s not allowed' % (ip_addr,))
            else:
                log.info('Access for IP:%s allowed', ip_addr)

        except Exception as e:
            raise JSONRPCErrorResponse(retid=self._req_id,
                                       message='Invalid API key')

        self._error = None
        try:
            self._func = self._find_method()
        except AttributeError as e:
            raise JSONRPCErrorResponse(retid=self._req_id,
                                       message=str(e))

        # now that we have a method, add self._req_params to
        # self.kargs and dispatch control to WGIController
        argspec = inspect.getargspec(self._func)
        arglist = argspec[0][1:]
        defaults = map(type, argspec[3] or [])
        default_empty = types.NotImplementedType

        # kw arguments required by this method
        func_kwargs = dict(itertools.izip_longest(reversed(arglist), reversed(defaults),
                                                  fillvalue=default_empty))

        # this is little trick to inject logged in user for
        # perms decorators to work they expect the controller class to have
        # authuser attribute set
        request.authuser = request.user = auth_u

        # This attribute will need to be first param of a method that uses
        # api_key, which is translated to instance of user at that name
        USER_SESSION_ATTR = 'apiuser'

        # get our arglist and check if we provided them as args
        for arg, default in func_kwargs.iteritems():
            if arg == USER_SESSION_ATTR:
                # USER_SESSION_ATTR is something translated from API key and
                # this is checked before so we don't need validate it
                continue

            # skip the required param check if it's default value is
            # NotImplementedType (default_empty)
            if default == default_empty and arg not in self._request_params:
                raise JSONRPCErrorResponse(
                    retid=self._req_id,
                    message='Missing non optional `%s` arg in JSON DATA' % arg,
                )

        extra = set(self._request_params).difference(func_kwargs)
        if extra:
                raise JSONRPCErrorResponse(
                    retid=self._req_id,
                    message='Unknown %s arg in JSON DATA' %
                            ', '.join('`%s`' % arg for arg in extra),
                )

        self._rpc_args = {}
        self._rpc_args.update(self._request_params)
        self._rpc_args['action'] = self._req_method
        self._rpc_args['environ'] = environ

        log.info('IP: %s Request to %s time: %.3fs' % (
            self._get_ip_addr(environ),
            safe_unicode(_get_access_path(environ)), time.time() - start)
        )

        state.set_action(self._rpc_call, [])
        state.set_params(self._rpc_args)
        return state
Exemple #39
0
    def _handle_request(self, environ, start_response):
        start = time.time()
        ip_addr = self.ip_addr = self._get_ip_addr(environ)
        self._req_id = None
        if 'CONTENT_LENGTH' not in environ:
            log.debug("No Content-Length")
            return jsonrpc_error(retid=self._req_id,
                                 message="No Content-Length in request")
        else:
            length = environ['CONTENT_LENGTH'] or 0
            length = int(environ['CONTENT_LENGTH'])
            log.debug('Content-Length: %s', length)

        if length == 0:
            log.debug("Content-Length is 0")
            return jsonrpc_error(retid=self._req_id,
                                 message="Content-Length is 0")

        raw_body = environ['wsgi.input'].read(length)

        try:
            json_body = json.loads(raw_body)
        except ValueError as e:
            # catch JSON errors Here
            return jsonrpc_error(retid=self._req_id,
                                 message="JSON parse error ERR:%s RAW:%r"
                                 % (e, raw_body))

        # check AUTH based on API key
        try:
            self._req_api_key = json_body['api_key']
            self._req_id = json_body['id']
            self._req_method = json_body['method']
            self._request_params = json_body['args']
            if not isinstance(self._request_params, dict):
                self._request_params = {}

            log.debug(
                'method: %s, params: %s', self._req_method,
                                            self._request_params
            )
        except KeyError as e:
            return jsonrpc_error(retid=self._req_id,
                                 message='Incorrect JSON query missing %s' % e)

        # check if we can find this session using api_key
        try:
            u = User.get_by_api_key(self._req_api_key)
            if u is None:
                return jsonrpc_error(retid=self._req_id,
                                     message='Invalid API key')

            auth_u = AuthUser(dbuser=u)
            if not AuthUser.check_ip_allowed(auth_u, ip_addr):
                return jsonrpc_error(retid=self._req_id,
                        message='request from IP:%s not allowed' % (ip_addr,))
            else:
                log.info('Access for IP:%s allowed', ip_addr)

        except Exception as e:
            return jsonrpc_error(retid=self._req_id,
                                 message='Invalid API key')

        self._error = None
        try:
            self._func = self._find_method()
        except AttributeError as e:
            return jsonrpc_error(retid=self._req_id,
                                 message=str(e))

        # now that we have a method, add self._req_params to
        # self.kargs and dispatch control to WGIController
        argspec = inspect.getargspec(self._func)
        arglist = argspec[0][1:]
        defaults = map(type, argspec[3] or [])
        default_empty = types.NotImplementedType

        # kw arguments required by this method
        func_kwargs = dict(izip_longest(reversed(arglist), reversed(defaults),
                                        fillvalue=default_empty))

        # this is little trick to inject logged in user for
        # perms decorators to work they expect the controller class to have
        # authuser attribute set
        self.authuser = auth_u

        # This attribute will need to be first param of a method that uses
        # api_key, which is translated to instance of user at that name
        USER_SESSION_ATTR = 'apiuser'

        if USER_SESSION_ATTR not in arglist:
            return jsonrpc_error(
                retid=self._req_id,
                message='This method [%s] does not support '
                         'authentication (missing %s param)' % (
                                    self._func.__name__, USER_SESSION_ATTR)
            )

        # get our arglist and check if we provided them as args
        for arg, default in func_kwargs.iteritems():
            if arg == USER_SESSION_ATTR:
                # USER_SESSION_ATTR is something translated from API key and
                # this is checked before so we don't need validate it
                continue

            # skip the required param check if it's default value is
            # NotImplementedType (default_empty)
            if default == default_empty and arg not in self._request_params:
                return jsonrpc_error(
                    retid=self._req_id,
                    message=(
                        'Missing non optional `%s` arg in JSON DATA' % arg
                    )
                )

        self._rpc_args = {USER_SESSION_ATTR: u}

        self._rpc_args.update(self._request_params)

        self._rpc_args['action'] = self._req_method
        self._rpc_args['environ'] = environ
        self._rpc_args['start_response'] = start_response

        status = []
        headers = []
        exc_info = []

        def change_content(new_status, new_headers, new_exc_info=None):
            status.append(new_status)
            headers.extend(new_headers)
            exc_info.append(new_exc_info)

        output = WSGIController.__call__(self, environ, change_content)
        output = list(output)
        headers.append(('Content-Length', str(len(output[0]))))
        replace_header(headers, 'Content-Type', 'application/json')
        start_response(status[0], headers, exc_info[0])
        log.info('IP: %s Request to %s time: %.3fs' % (
            self._get_ip_addr(environ),
            safe_unicode(_get_access_path(environ)), time.time() - start)
        )
        return output