# HG changeset patch # User Mads Kiilerich # Date 2019-01-03 01:16:36 # Node ID 0e3e0864f2104bcf79eb8fc2d6378e52b79e4b91 # Parent 69421c730569ae1324d481a500570cbf667a6f71 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. diff --git a/development.ini b/development.ini --- a/development.ini +++ b/development.ini @@ -153,18 +153,6 @@ show_revision_number = false ## Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/ 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 :. 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 diff --git a/docs/api/api.rst b/docs/api/api.rst --- a/docs/api/api.rst +++ b/docs/api/api.rst @@ -1238,24 +1238,8 @@ OUTPUT:: 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 diff --git a/kallithea/controllers/feed.py b/kallithea/controllers/feed.py --- a/kallithea/controllers/feed.py +++ b/kallithea/controllers/feed.py @@ -51,7 +51,7 @@ ttl = "5" 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) diff --git a/kallithea/controllers/journal.py b/kallithea/controllers/journal.py --- a/kallithea/controllers/journal.py +++ b/kallithea/controllers/journal.py @@ -220,7 +220,7 @@ class JournalController(BaseController): 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 @@ class JournalController(BaseController): .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 @@ class JournalController(BaseController): 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 @@ class JournalController(BaseController): 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 diff --git a/kallithea/lib/auth.py b/kallithea/lib/auth.py --- a/kallithea/lib/auth.py +++ b/kallithea/lib/auth.py @@ -367,28 +367,6 @@ def _cached_perms_data(user_id, user_is_ 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 @@ class LoginRequired(object): 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 @@ class LoginRequired(object): 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 diff --git a/kallithea/lib/paster_commands/template.ini.mako b/kallithea/lib/paster_commands/template.ini.mako --- a/kallithea/lib/paster_commands/template.ini.mako +++ b/kallithea/lib/paster_commands/template.ini.mako @@ -250,18 +250,6 @@ show_revision_number = false <%text>## Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/ gist_alias_url = -<%text>## white list of API enabled controllers. This allows to add list of -<%text>## controllers to which access will be enabled by api_key. eg: to enable -<%text>## api access to raw_files put `FilesController:raw`, to enable access to patches -<%text>## add `ChangesetController:changeset_patch`. This list should be "," separated -<%text>## Syntax is :. Check debug logs for generated names -<%text>## Recommended settings below are commented out: -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>## can be also a comma separated list of encoding in case of mixed encodings default_encoding = utf-8 diff --git a/kallithea/tests/functional/test_login.py b/kallithea/tests/functional/test_login.py --- a/kallithea/tests/functional/test_login.py +++ b/kallithea/tests/functional/test_login.py @@ -441,10 +441,6 @@ class TestLoginController(TestController # 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 @@ class TestLoginController(TestController ('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)