changeset 7692:0e3e0864f210

auth: drop api_access_controllers_whitelist and give API key auth same access as other kinds of auth All authentication methods are created equal. There is no point in discriminating api key authentication and limit it to few APIs.
author Mads Kiilerich <mads@kiilerich.com>
date Thu, 03 Jan 2019 01:16:36 +0100
parents 69421c730569
children 05dc948c9788
files development.ini docs/api/api.rst kallithea/controllers/feed.py kallithea/controllers/journal.py kallithea/lib/auth.py kallithea/lib/paster_commands/template.ini.mako kallithea/tests/functional/test_login.py
diffstat 7 files changed, 22 insertions(+), 121 deletions(-) [+]
line wrap: on
line diff
--- a/development.ini	Mon Dec 31 02:32:23 2018 +0100
+++ b/development.ini	Thu Jan 03 01:16:36 2019 +0100
@@ -153,18 +153,6 @@
 ## Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/<gistid>
 gist_alias_url =
 
-## white list of API enabled controllers. This allows to add list of
-## controllers to which access will be enabled by api_key. eg: to enable
-## api access to raw_files put `FilesController:raw`, to enable access to patches
-## add `ChangesetController:changeset_patch`. This list should be "," separated
-## Syntax is <ControllerClass>:<function>. Check debug logs for generated names
-## Recommended settings below are commented out:
-api_access_controllers_whitelist =
-#    ChangesetController:changeset_patch,
-#    ChangesetController:changeset_raw,
-#    FilesController:raw,
-#    FilesController:archivefile
-
 ## default encoding used to convert from and to unicode
 ## can be also a comma separated list of encoding in case of mixed encodings
 default_encoding = utf-8
--- a/docs/api/api.rst	Mon Dec 31 02:32:23 2018 +0100
+++ b/docs/api/api.rst	Thu Jan 03 01:16:36 2019 +0100
@@ -1238,24 +1238,8 @@
 API access for web views
 ------------------------
 
-API access can also be turned on for each web view in Kallithea that is
-decorated with the ``@LoginRequired`` decorator. Some views use
-``@LoginRequired(api_access=True)`` and are always available. By default only
-RSS/Atom feed views are enabled. Other views are
-only available if they have been whitelisted. Edit the
-``api_access_controllers_whitelist`` option in your .ini file and define views
-that should have API access enabled.
-
-For example, to enable API access to patch/diff, raw file and archive::
-
-    api_access_controllers_whitelist =
-        ChangesetController:changeset_patch,
-        ChangesetController:changeset_raw,
-        FilesController:raw,
-        FilesController:archivefile
-
-After this change, a Kallithea view can be accessed without login using
-bearer authentication, by including this header with the request::
+Kallithea HTTP entry points can also be accessed without login using bearer
+authentication by including this header with the request::
 
     Authentication: Bearer <api_key>
 
--- a/kallithea/controllers/feed.py	Mon Dec 31 02:32:23 2018 +0100
+++ b/kallithea/controllers/feed.py	Thu Jan 03 01:16:36 2019 +0100
@@ -51,7 +51,7 @@
 
 class FeedController(BaseRepoController):
 
-    @LoginRequired(api_access=True, allow_default_user=True)
+    @LoginRequired(allow_default_user=True)
     @HasRepoPermissionLevelDecorator('read')
     def _before(self, *args, **kwargs):
         super(FeedController, self)._before(*args, **kwargs)
--- a/kallithea/controllers/journal.py	Mon Dec 31 02:32:23 2018 +0100
+++ b/kallithea/controllers/journal.py	Thu Jan 03 01:16:36 2019 +0100
@@ -220,7 +220,7 @@
 
         return render('journal/journal.html')
 
-    @LoginRequired(api_access=True)
+    @LoginRequired()
     def journal_atom(self):
         """
         Produce an atom-1.0 feed via feedgenerator module
@@ -231,7 +231,7 @@
             .all()
         return self._atom_feed(following, public=False)
 
-    @LoginRequired(api_access=True)
+    @LoginRequired()
     def journal_rss(self):
         """
         Produce an rss feed via feedgenerator module
@@ -289,7 +289,7 @@
 
         return render('journal/public_journal.html')
 
-    @LoginRequired(api_access=True, allow_default_user=True)
+    @LoginRequired(allow_default_user=True)
     def public_journal_atom(self):
         """
         Produce an atom-1.0 feed via feedgenerator module
@@ -301,7 +301,7 @@
 
         return self._atom_feed(c.following)
 
-    @LoginRequired(api_access=True, allow_default_user=True)
+    @LoginRequired(allow_default_user=True)
     def public_journal_rss(self):
         """
         Produce an rss2 feed via feedgenerator module
--- a/kallithea/lib/auth.py	Mon Dec 31 02:32:23 2018 +0100
+++ b/kallithea/lib/auth.py	Thu Jan 03 01:16:36 2019 +0100
@@ -367,28 +367,6 @@
     return permissions
 
 
-def allowed_api_access(controller_name, whitelist=None, api_key=None):
-    """
-    Check if given controller_name is in whitelist API access
-    """
-    if not whitelist:
-        from kallithea import CONFIG
-        whitelist = aslist(CONFIG.get('api_access_controllers_whitelist'),
-                           sep=',')
-        log.debug('whitelist of API access is: %s', whitelist)
-    api_access_valid = controller_name in whitelist
-    if api_access_valid:
-        log.debug('controller:%s is in API whitelist', controller_name)
-    else:
-        msg = 'controller: %s is *NOT* in API whitelist' % (controller_name)
-        if api_key:
-            # if we use API key and don't have access it's a warning
-            log.warning(msg)
-        else:
-            log.debug(msg)
-    return api_access_valid
-
-
 class AuthUser(object):
     """
     Represents a Kallithea user, including various authentication and
@@ -689,13 +667,10 @@
     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).
+    Also checks that IP address is allowed.
     """
 
-    def __init__(self, api_access=False, allow_default_user=False):
-        self.api_access = api_access
+    def __init__(self, allow_default_user=False):
         self.allow_default_user = allow_default_user
 
     def __call__(self, func):
@@ -708,16 +683,9 @@
         log.debug('Checking access for user %s @ %s', user, loc)
 
         # Check if we used an API key to authenticate.
-        api_key = user.authenticating_api_key
-        if api_key is not None:
-            # Check that controller is enabled for API key usage.
-            if not self.api_access and not allowed_api_access(loc, api_key=api_key):
-                # controller does not allow API access
-                log.warning('API access to %s is not allowed', loc)
-                raise HTTPForbidden()
-
+        if user.authenticating_api_key is not None:
             log.info('user %s authenticated with API key ****%s @ %s',
-                     user, api_key[-4:], loc)
+                     user, user.authenticating_api_key[-4:], loc)
             return func(*fargs, **fkwargs)
 
         # CSRF protection: Whenever a request has ambient authority (whether
--- a/kallithea/lib/paster_commands/template.ini.mako	Mon Dec 31 02:32:23 2018 +0100
+++ b/kallithea/lib/paster_commands/template.ini.mako	Thu Jan 03 01:16:36 2019 +0100
@@ -250,18 +250,6 @@
 <%text>## Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/<gistid></%text>
 gist_alias_url =
 
-<%text>## white list of API enabled controllers. This allows to add list of</%text>
-<%text>## controllers to which access will be enabled by api_key. eg: to enable</%text>
-<%text>## api access to raw_files put `FilesController:raw`, to enable access to patches</%text>
-<%text>## add `ChangesetController:changeset_patch`. This list should be "," separated</%text>
-<%text>## Syntax is <ControllerClass>:<function>. Check debug logs for generated names</%text>
-<%text>## Recommended settings below are commented out:</%text>
-api_access_controllers_whitelist =
-#    ChangesetController:changeset_patch,
-#    ChangesetController:changeset_raw,
-#    FilesController:raw,
-#    FilesController:archivefile
-
 <%text>## default encoding used to convert from and to unicode</%text>
 <%text>## can be also a comma separated list of encoding in case of mixed encodings</%text>
 default_encoding = utf-8
--- a/kallithea/tests/functional/test_login.py	Mon Dec 31 02:32:23 2018 +0100
+++ b/kallithea/tests/functional/test_login.py	Thu Jan 03 01:16:36 2019 +0100
@@ -441,10 +441,6 @@
     # API
     #==========================================================================
 
-    def _get_api_whitelist(self, values=None):
-        config = {'api_access_controllers_whitelist': values or []}
-        return config
-
     def _api_key_test(self, api_key, status):
         """Verifies HTTP status code for accessing an auth-requiring page,
         using the given api_key URL parameter as well as using the API key
@@ -476,45 +472,22 @@
         ('none', None, 302),
         ('empty_string', '', 403),
         ('fake_number', '123456', 403),
-        ('proper_api_key', True, 403)
-    ])
-    def test_access_not_whitelisted_page_via_api_key(self, test_name, api_key, code):
-        whitelist = self._get_api_whitelist([])
-        with mock.patch('kallithea.CONFIG', whitelist):
-            assert [] == whitelist['api_access_controllers_whitelist']
-            self._api_key_test(api_key, code)
-
-    @parametrize('test_name,api_key,code', [
-        ('none', None, 302),
-        ('empty_string', '', 403),
-        ('fake_number', '123456', 403),
         ('fake_not_alnum', 'a-z', 403),
         ('fake_api_key', '0123456789abcdef0123456789ABCDEF01234567', 403),
         ('proper_api_key', True, 200)
     ])
-    def test_access_whitelisted_page_via_api_key(self, test_name, api_key, code):
-        whitelist = self._get_api_whitelist(['ChangesetController:changeset_raw'])
-        with mock.patch('kallithea.CONFIG', whitelist):
-            assert ['ChangesetController:changeset_raw'] == whitelist['api_access_controllers_whitelist']
-            self._api_key_test(api_key, code)
+    def test_access_page_via_api_key(self, test_name, api_key, code):
+        self._api_key_test(api_key, code)
 
     def test_access_page_via_extra_api_key(self):
-        whitelist = self._get_api_whitelist(['ChangesetController:changeset_raw'])
-        with mock.patch('kallithea.CONFIG', whitelist):
-            assert ['ChangesetController:changeset_raw'] == whitelist['api_access_controllers_whitelist']
-
-            new_api_key = ApiKeyModel().create(TEST_USER_ADMIN_LOGIN, u'test')
-            Session().commit()
-            self._api_key_test(new_api_key.api_key, status=200)
+        new_api_key = ApiKeyModel().create(TEST_USER_ADMIN_LOGIN, u'test')
+        Session().commit()
+        self._api_key_test(new_api_key.api_key, status=200)
 
     def test_access_page_via_expired_api_key(self):
-        whitelist = self._get_api_whitelist(['ChangesetController:changeset_raw'])
-        with mock.patch('kallithea.CONFIG', whitelist):
-            assert ['ChangesetController:changeset_raw'] == whitelist['api_access_controllers_whitelist']
-
-            new_api_key = ApiKeyModel().create(TEST_USER_ADMIN_LOGIN, u'test')
-            Session().commit()
-            # patch the API key and make it expired
-            new_api_key.expires = 0
-            Session().commit()
-            self._api_key_test(new_api_key.api_key, status=403)
+        new_api_key = ApiKeyModel().create(TEST_USER_ADMIN_LOGIN, u'test')
+        Session().commit()
+        # patch the API key and make it expired
+        new_api_key.expires = 0
+        Session().commit()
+        self._api_key_test(new_api_key.api_key, status=403)