changeset 7092:aa25ef34ebab

auth: refactor to introduce @LoginRequired(allow_default_user=True) and deprecate @NotAnonymous() It was error prone that @LoginRequired defaulted to allow anonymous users (if 'default' user is enabled). See also 245b4e3abf39. Refactor code to make it more explicit and safe by default: Deprecate @NotAnonymous by making it the default of @LoginRequired. That will make it safe by default. To preserve same functionality, set allow_default_user=True in all the cases where @LoginRequired was *not* followed by @NotAnonymous or other permission checks - that was done with some script hacks: sed -i 's/@LoginRequired(\(..*\))/@LoginRequired(\1, allow_default_user=True)/g' `hg mani` sed -i 's/@LoginRequired()/@LoginRequired(allow_default_user=True)/g' `hg mani` perl -0pi -e 's/\@LoginRequired\(allow_default_user=True\)\n\s*\@NotAnonymous\(\)/\@LoginRequired()/g' `hg mani` perl -0pi -e 's/\@LoginRequired\(allow_default_user=True\)(\n\s*\@Has(Repo)?Permission)/\@LoginRequired()\1/g' `hg mani` It has been reviewed that all uses of allow_default_user=True are in places where the there indeed wasn't any checking for default user before. These may or may not be correct, but now they are explicit and can be spotted and fixed. The few remaining uses of @NotAnonymous should probably be removed somehow.
author Mads Kiilerich <mads@kiilerich.com>
date Sun, 21 Jan 2018 02:49:15 +0100
parents 422671dd32df
children 73406e83b038
files kallithea/controllers/admin/admin.py kallithea/controllers/admin/gists.py kallithea/controllers/admin/my_account.py kallithea/controllers/admin/notifications.py kallithea/controllers/admin/repo_groups.py kallithea/controllers/admin/repos.py kallithea/controllers/admin/settings.py kallithea/controllers/admin/user_groups.py kallithea/controllers/changeset.py kallithea/controllers/forks.py kallithea/controllers/home.py kallithea/controllers/journal.py kallithea/controllers/pullrequests.py kallithea/controllers/search.py kallithea/controllers/summary.py kallithea/lib/auth.py
diffstat 16 files changed, 36 insertions(+), 56 deletions(-) [+]
line wrap: on
line diff
--- a/kallithea/controllers/admin/admin.py	Sat Dec 16 22:10:45 2017 +0100
+++ b/kallithea/controllers/admin/admin.py	Sun Jan 21 02:49:15 2018 +0100
@@ -120,7 +120,7 @@
 
 class AdminController(BaseController):
 
-    @LoginRequired()
+    @LoginRequired(allow_default_user=True)
     def _before(self, *args, **kwargs):
         super(AdminController, self)._before(*args, **kwargs)
 
--- a/kallithea/controllers/admin/gists.py	Sat Dec 16 22:10:45 2017 +0100
+++ b/kallithea/controllers/admin/gists.py	Sun Jan 21 02:49:15 2018 +0100
@@ -41,7 +41,7 @@
 from kallithea.model.db import Gist, User
 from kallithea.lib import helpers as h
 from kallithea.lib.base import BaseController, render, jsonify
-from kallithea.lib.auth import LoginRequired, NotAnonymous
+from kallithea.lib.auth import LoginRequired
 from kallithea.lib.utils2 import safe_int, safe_unicode, time_to_datetime
 from kallithea.lib.page import Page
 from sqlalchemy.sql.expression import or_
@@ -65,7 +65,7 @@
             c.lifetime_values.append(extra_values)
         c.lifetime_options = [(c.lifetime_values, _("Lifetime"))]
 
-    @LoginRequired()
+    @LoginRequired(allow_default_user=True)
     def index(self):
         not_default_user = not request.authuser.is_default_user
         c.show_private = request.GET.get('private') and not_default_user
@@ -100,7 +100,6 @@
         return render('admin/gists/index.html')
 
     @LoginRequired()
-    @NotAnonymous()
     def create(self):
         self.__load_defaults()
         gist_form = GistForm([x[0] for x in c.lifetime_values])()
@@ -143,13 +142,11 @@
         raise HTTPFound(location=url('gist', gist_id=new_gist_id))
 
     @LoginRequired()
-    @NotAnonymous()
     def new(self, format='html'):
         self.__load_defaults()
         return render('admin/gists/new.html')
 
     @LoginRequired()
-    @NotAnonymous()
     def delete(self, gist_id):
         gist = GistModel().get_gist(gist_id)
         owner = gist.owner_id == request.authuser.user_id
@@ -162,7 +159,7 @@
 
         raise HTTPFound(location=url('gists'))
 
-    @LoginRequired()
+    @LoginRequired(allow_default_user=True)
     def show(self, gist_id, revision='tip', format='html', f_path=None):
         c.gist = Gist.get_or_404(gist_id)
 
@@ -183,7 +180,6 @@
         return render('admin/gists/show.html')
 
     @LoginRequired()
-    @NotAnonymous()
     def edit(self, gist_id, format='html'):
         c.gist = Gist.get_or_404(gist_id)
 
@@ -242,7 +238,6 @@
         return rendered
 
     @LoginRequired()
-    @NotAnonymous()
     @jsonify
     def check_revision(self, gist_id):
         c.gist = Gist.get_or_404(gist_id)
--- a/kallithea/controllers/admin/my_account.py	Sat Dec 16 22:10:45 2017 +0100
+++ b/kallithea/controllers/admin/my_account.py	Sun Jan 21 02:49:15 2018 +0100
@@ -38,7 +38,7 @@
 from kallithea.config.routing import url
 from kallithea.lib import helpers as h
 from kallithea.lib import auth_modules
-from kallithea.lib.auth import LoginRequired, NotAnonymous, AuthUser
+from kallithea.lib.auth import LoginRequired, AuthUser
 from kallithea.lib.base import BaseController, render
 from kallithea.lib.utils2 import generate_api_key, safe_int
 from kallithea.model.db import Repository, UserEmailMap, User, UserFollowing
@@ -59,7 +59,6 @@
     #         path_prefix='/admin', name_prefix='admin_')
 
     @LoginRequired()
-    @NotAnonymous()
     def _before(self, *args, **kwargs):
         super(MyAccountController, self)._before(*args, **kwargs)
 
--- a/kallithea/controllers/admin/notifications.py	Sat Dec 16 22:10:45 2017 +0100
+++ b/kallithea/controllers/admin/notifications.py	Sun Jan 21 02:49:15 2018 +0100
@@ -35,7 +35,7 @@
 from kallithea.model.db import Notification
 from kallithea.model.notification import NotificationModel
 from kallithea.model.meta import Session
-from kallithea.lib.auth import LoginRequired, NotAnonymous
+from kallithea.lib.auth import LoginRequired
 from kallithea.lib.base import BaseController, render
 from kallithea.lib import helpers as h
 from kallithea.lib.page import Page
@@ -53,7 +53,6 @@
     #         path_prefix='/_admin', name_prefix='_admin_')
 
     @LoginRequired()
-    @NotAnonymous()
     def _before(self, *args, **kwargs):
         super(NotificationsController, self)._before(*args, **kwargs)
 
--- a/kallithea/controllers/admin/repo_groups.py	Sat Dec 16 22:10:45 2017 +0100
+++ b/kallithea/controllers/admin/repo_groups.py	Sun Jan 21 02:49:15 2018 +0100
@@ -58,7 +58,7 @@
 
 class RepoGroupsController(BaseController):
 
-    @LoginRequired()
+    @LoginRequired(allow_default_user=True)
     def _before(self, *args, **kwargs):
         super(RepoGroupsController, self)._before(*args, **kwargs)
 
--- a/kallithea/controllers/admin/repos.py	Sat Dec 16 22:10:45 2017 +0100
+++ b/kallithea/controllers/admin/repos.py	Sun Jan 21 02:49:15 2018 +0100
@@ -60,7 +60,7 @@
     # file has a resource setup:
     #     map.resource('repo', 'repos')
 
-    @LoginRequired()
+    @LoginRequired(allow_default_user=True)
     def _before(self, *args, **kwargs):
         super(ReposController, self)._before(*args, **kwargs)
 
@@ -169,7 +169,6 @@
             force_defaults=False)
 
     @LoginRequired()
-    @NotAnonymous()
     def repo_creating(self, repo_name):
         c.repo = repo_name
         c.task_id = request.GET.get('task_id')
@@ -178,7 +177,6 @@
         return render('admin/repos/repo_creating.html')
 
     @LoginRequired()
-    @NotAnonymous()
     @jsonify
     def repo_check(self, repo_name):
         c.repo = repo_name
--- a/kallithea/controllers/admin/settings.py	Sat Dec 16 22:10:45 2017 +0100
+++ b/kallithea/controllers/admin/settings.py	Sun Jan 21 02:49:15 2018 +0100
@@ -59,7 +59,7 @@
     #     map.resource('setting', 'settings', controller='admin/settings',
     #         path_prefix='/admin', name_prefix='admin_')
 
-    @LoginRequired()
+    @LoginRequired(allow_default_user=True)
     def _before(self, *args, **kwargs):
         super(SettingsController, self)._before(*args, **kwargs)
 
--- a/kallithea/controllers/admin/user_groups.py	Sat Dec 16 22:10:45 2017 +0100
+++ b/kallithea/controllers/admin/user_groups.py	Sun Jan 21 02:49:15 2018 +0100
@@ -63,7 +63,7 @@
 class UserGroupsController(BaseController):
     """REST Controller styled on the Atom Publishing Protocol"""
 
-    @LoginRequired()
+    @LoginRequired(allow_default_user=True)
     def _before(self, *args, **kwargs):
         super(UserGroupsController, self)._before(*args, **kwargs)
         c.available_permissions = config['available_permissions']
--- a/kallithea/controllers/changeset.py	Sat Dec 16 22:10:45 2017 +0100
+++ b/kallithea/controllers/changeset.py	Sun Jan 21 02:49:15 2018 +0100
@@ -37,8 +37,7 @@
     ChangesetDoesNotExistError, EmptyRepositoryError
 
 import kallithea.lib.helpers as h
-from kallithea.lib.auth import LoginRequired, HasRepoPermissionLevelDecorator, \
-    NotAnonymous
+from kallithea.lib.auth import LoginRequired, HasRepoPermissionLevelDecorator
 from kallithea.lib.base import BaseRepoController, render, jsonify
 from kallithea.lib.utils import action_logger
 from kallithea.lib.compat import OrderedDict
@@ -348,7 +347,6 @@
         return self._index(revision, method='download')
 
     @LoginRequired()
-    @NotAnonymous()
     @HasRepoPermissionLevelDecorator('read')
     @jsonify
     def comment(self, repo_name, revision):
@@ -399,7 +397,6 @@
         return data
 
     @LoginRequired()
-    @NotAnonymous()
     @HasRepoPermissionLevelDecorator('read')
     @jsonify
     def delete_comment(self, repo_name, comment_id):
--- a/kallithea/controllers/forks.py	Sat Dec 16 22:10:45 2017 +0100
+++ b/kallithea/controllers/forks.py	Sun Jan 21 02:49:15 2018 +0100
@@ -38,7 +38,7 @@
 
 from kallithea.config.routing import url
 from kallithea.lib.auth import LoginRequired, HasRepoPermissionLevelDecorator, \
-    NotAnonymous, HasRepoPermissionLevel, HasPermissionAnyDecorator, HasPermissionAny
+    HasRepoPermissionLevel, HasPermissionAnyDecorator, HasPermissionAny
 from kallithea.lib.base import BaseRepoController, render
 from kallithea.lib.page import Page
 from kallithea.lib.utils2 import safe_int
@@ -123,7 +123,6 @@
         return render('/forks/forks.html')
 
     @LoginRequired()
-    @NotAnonymous()
     @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
     @HasRepoPermissionLevelDecorator('read')
     def fork(self, repo_name):
@@ -141,7 +140,6 @@
             force_defaults=False)
 
     @LoginRequired()
-    @NotAnonymous()
     @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
     @HasRepoPermissionLevelDecorator('read')
     def fork_create(self, repo_name):
--- a/kallithea/controllers/home.py	Sat Dec 16 22:10:45 2017 +0100
+++ b/kallithea/controllers/home.py	Sun Jan 21 02:49:15 2018 +0100
@@ -50,7 +50,7 @@
     def about(self):
         return render('/about.html')
 
-    @LoginRequired()
+    @LoginRequired(allow_default_user=True)
     def index(self):
         c.group = None
 
@@ -63,7 +63,7 @@
 
         return render('/index.html')
 
-    @LoginRequired()
+    @LoginRequired(allow_default_user=True)
     @jsonify
     def repo_switcher_data(self):
         # wrapper for conditional cache
@@ -145,7 +145,7 @@
         }
         return data
 
-    @LoginRequired()
+    @LoginRequired(allow_default_user=True)
     @jsonify
     def users_and_groups_data(self):
         """
--- a/kallithea/controllers/journal.py	Sat Dec 16 22:10:45 2017 +0100
+++ b/kallithea/controllers/journal.py	Sun Jan 21 02:49:15 2018 +0100
@@ -46,7 +46,7 @@
 from kallithea.model.meta import Session
 from kallithea.model.repo import RepoModel
 import kallithea.lib.helpers as h
-from kallithea.lib.auth import LoginRequired, NotAnonymous
+from kallithea.lib.auth import LoginRequired
 from kallithea.lib.base import BaseController, render
 from kallithea.lib.page import Page
 from kallithea.lib.utils2 import safe_int, AttributeDict
@@ -191,7 +191,6 @@
         return feed.writeString('utf-8')
 
     @LoginRequired()
-    @NotAnonymous()
     def index(self):
         # Return a rendered template
         p = safe_int(request.GET.get('page'), 1)
@@ -223,7 +222,6 @@
         return render('journal/journal.html')
 
     @LoginRequired(api_access=True)
-    @NotAnonymous()
     def journal_atom(self):
         """
         Produce an atom-1.0 feed via feedgenerator module
@@ -235,7 +233,6 @@
         return self._atom_feed(following, public=False)
 
     @LoginRequired(api_access=True)
-    @NotAnonymous()
     def journal_rss(self):
         """
         Produce an rss feed via feedgenerator module
@@ -247,7 +244,6 @@
         return self._rss_feed(following, public=False)
 
     @LoginRequired()
-    @NotAnonymous()
     def toggle_following(self):
         user_id = request.POST.get('follows_user_id')
         if user_id:
@@ -273,7 +269,7 @@
 
         raise HTTPBadRequest()
 
-    @LoginRequired()
+    @LoginRequired(allow_default_user=True)
     def public_journal(self):
         # Return a rendered template
         p = safe_int(request.GET.get('page'), 1)
@@ -294,7 +290,7 @@
 
         return render('journal/public_journal.html')
 
-    @LoginRequired(api_access=True)
+    @LoginRequired(api_access=True, allow_default_user=True)
     def public_journal_atom(self):
         """
         Produce an atom-1.0 feed via feedgenerator module
@@ -306,7 +302,7 @@
 
         return self._atom_feed(c.following)
 
-    @LoginRequired(api_access=True)
+    @LoginRequired(api_access=True, allow_default_user=True)
     def public_journal_rss(self):
         """
         Produce an rss2 feed via feedgenerator module
--- a/kallithea/controllers/pullrequests.py	Sat Dec 16 22:10:45 2017 +0100
+++ b/kallithea/controllers/pullrequests.py	Sun Jan 21 02:49:15 2018 +0100
@@ -36,8 +36,7 @@
 from kallithea.config.routing import url
 from kallithea.lib import helpers as h
 from kallithea.lib import diffs
-from kallithea.lib.auth import LoginRequired, HasRepoPermissionLevelDecorator, \
-    NotAnonymous
+from kallithea.lib.auth import LoginRequired, HasRepoPermissionLevelDecorator
 from kallithea.lib.base import BaseRepoController, render, jsonify
 from kallithea.lib.page import Page
 from kallithea.lib.utils import action_logger
@@ -218,7 +217,6 @@
         return render('/pullrequests/pullrequest_show_all.html')
 
     @LoginRequired()
-    @NotAnonymous()
     def show_my(self):
         c.closed = request.GET.get('closed') or ''
 
@@ -244,7 +242,6 @@
         return render('/pullrequests/pullrequest_show_my.html')
 
     @LoginRequired()
-    @NotAnonymous()
     @HasRepoPermissionLevelDecorator('read')
     def index(self):
         org_repo = c.db_repo
@@ -300,7 +297,6 @@
         return render('/pullrequests/pullrequest.html')
 
     @LoginRequired()
-    @NotAnonymous()
     @HasRepoPermissionLevelDecorator('read')
     @jsonify
     def repo_info(self, repo_name):
@@ -313,7 +309,6 @@
             }
 
     @LoginRequired()
-    @NotAnonymous()
     @HasRepoPermissionLevelDecorator('read')
     def create(self, repo_name):
         repo = c.db_repo
@@ -383,7 +378,6 @@
 
     # pullrequest_post for PR editing
     @LoginRequired()
-    @NotAnonymous()
     @HasRepoPermissionLevelDecorator('read')
     def post(self, repo_name, pull_request_id):
         pull_request = PullRequest.get_or_404(pull_request_id)
@@ -440,7 +434,6 @@
         raise HTTPFound(location=pull_request.url())
 
     @LoginRequired()
-    @NotAnonymous()
     @HasRepoPermissionLevelDecorator('read')
     @jsonify
     def delete(self, repo_name, pull_request_id):
@@ -633,7 +626,6 @@
         return render('/pullrequests/pullrequest_show.html')
 
     @LoginRequired()
-    @NotAnonymous()
     @HasRepoPermissionLevelDecorator('read')
     @jsonify
     def comment(self, repo_name, pull_request_id):
@@ -718,7 +710,6 @@
         return data
 
     @LoginRequired()
-    @NotAnonymous()
     @HasRepoPermissionLevelDecorator('read')
     @jsonify
     def delete_comment(self, repo_name, comment_id):
--- a/kallithea/controllers/search.py	Sat Dec 16 22:10:45 2017 +0100
+++ b/kallithea/controllers/search.py	Sun Jan 21 02:49:15 2018 +0100
@@ -49,7 +49,7 @@
 
 class SearchController(BaseRepoController):
 
-    @LoginRequired()
+    @LoginRequired(allow_default_user=True)
     def index(self, repo_name=None):
         c.repo_name = repo_name
         c.formated_results = []
--- a/kallithea/controllers/summary.py	Sat Dec 16 22:10:45 2017 +0100
+++ b/kallithea/controllers/summary.py	Sun Jan 21 02:49:15 2018 +0100
@@ -43,8 +43,7 @@
 from kallithea.config.conf import ALL_READMES, ALL_EXTS, LANGUAGES_EXTENSIONS_MAP
 from kallithea.model.db import Statistics, CacheInvalidation, User
 from kallithea.lib.utils2 import safe_int, safe_str
-from kallithea.lib.auth import LoginRequired, HasRepoPermissionLevelDecorator, \
-    NotAnonymous
+from kallithea.lib.auth import LoginRequired, HasRepoPermissionLevelDecorator
 from kallithea.lib.base import BaseRepoController, render, jsonify
 from kallithea.lib.vcs.backends.base import EmptyChangeset
 from kallithea.lib.markup_renderer import MarkupRenderer
@@ -162,7 +161,6 @@
         return render('summary/summary.html')
 
     @LoginRequired()
-    @NotAnonymous()
     @HasRepoPermissionLevelDecorator('read')
     @jsonify
     def repo_size(self, repo_name):
--- a/kallithea/lib/auth.py	Sat Dec 16 22:10:45 2017 +0100
+++ b/kallithea/lib/auth.py	Sun Jan 21 02:49:15 2018 +0100
@@ -752,16 +752,20 @@
 
 # Use as decorator
 class LoginRequired(object):
-    """Client must be logged in as a valid User (but the "default" user,
-    if enabled, is considered valid), or we'll redirect to the login page.
+    """Client must be logged in as a valid User, or we'll redirect to the login
+    page.
+
+    If the "default" user is enabled and allow_default_user is true, that is
+    considered valid too.
 
     Also checks that IP address is allowed, and if using API key instead
     of regular cookie authentication, checks that API key access is allowed
     (based on `api_access` parameter and the API view whitelist).
     """
 
-    def __init__(self, api_access=False):
+    def __init__(self, api_access=False, allow_default_user=False):
         self.api_access = api_access
+        self.allow_default_user = allow_default_user
 
     def __call__(self, func):
         return decorator(self.__wrapper, func)
@@ -801,12 +805,17 @@
                 raise HTTPForbidden()
 
         # regular user authentication
-        if user.is_authenticated or user.is_default_user:
+        if user.is_authenticated:
             log.info('user %s authenticated with regular auth @ %s', user, loc)
             return func(*fargs, **fkwargs)
+        elif user.is_default_user:
+            if self.allow_default_user:
+                log.info('default user @ %s', loc)
+                return func(*fargs, **fkwargs)
+            log.info('default user is not accepted here @ %s', loc)
         else:
             log.warning('user %s NOT authenticated with regular auth @ %s', user, loc)
-            raise _redirect_to_login()
+        raise _redirect_to_login()
 
 
 # Use as decorator