changeset 5222:6620542597d3 stable

api: check repo create permissions for update_repo and fork_repo as for create-repo Close loophole for creating repos everywhere. Tests by Thomas De Schampheleire.
author Mads Kiilerich <madski@unity3d.com>
date Tue, 07 Jul 2015 02:25:59 +0200
parents 8aad6a324739
children 0b7b52bfaf5d
files docs/api/api.rst kallithea/controllers/api/api.py kallithea/tests/api/api_base.py
diffstat 3 files changed, 75 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/docs/api/api.rst	Tue Jul 07 02:25:54 2015 +0200
+++ b/docs/api/api.rst	Tue Jul 07 02:25:59 2015 +0200
@@ -833,8 +833,9 @@
 Create a fork of the given repo. If using Celery, this will
 return success message immediately and a fork will be created
 asynchronously.
-This command can only be executed using the api_key of a user with admin rights,
-or that of a regular user with fork permission and at least read access to the repository.
+This command can only be executed using the api_key of a user with admin
+rights, or with the global fork permission, by a regular user with create
+repository permission and at least read access to the repository.
 Regular users cannot specify owner parameter.
 
 
--- a/kallithea/controllers/api/api.py	Tue Jul 07 02:25:54 2015 +0200
+++ b/kallithea/controllers/api/api.py	Tue Jul 07 02:25:59 2015 +0200
@@ -1556,6 +1556,11 @@
                                                                repo_name=repo.repo_name):
                 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
 
+            if (name != repo.repo_name and
+                not HasPermissionAnyApi('hg.create.repository')(user=apiuser)
+                ):
+                raise JSONRPCError('no permission to create (or move) repositories')
+
         updates = {
             # update function requires this.
             'repo_name': repo.repo_name
@@ -1653,6 +1658,9 @@
                 raise JSONRPCError(
                     'Only Kallithea admin can specify `owner` param'
                 )
+
+            if not HasPermissionAnyApi('hg.create.repository')(user=apiuser):
+                raise JSONRPCError('no permission to create repositories')
         else:
             raise JSONRPCError('repository `%s` does not exist' % (repoid,))
 
--- a/kallithea/tests/api/api_base.py	Tue Jul 07 02:25:54 2015 +0200
+++ b/kallithea/tests/api/api_base.py	Tue Jul 07 02:25:59 2015 +0200
@@ -1178,6 +1178,49 @@
         finally:
             fixture.destroy_repo(repo_name)
 
+    def test_api_update_repo_regular_user_change_repo_name(self):
+        repo_name = 'admin_owned'
+        new_repo_name = 'new_repo_name'
+        fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
+        RepoModel().grant_user_permission(repo=repo_name,
+                                          user=self.TEST_USER_LOGIN,
+                                          perm='repository.admin')
+        UserModel().revoke_perm('default', 'hg.create.repository')
+        UserModel().grant_perm('default', 'hg.create.none')
+        updates = {'name': new_repo_name}
+        id_, params = _build_data(self.apikey_regular, 'update_repo',
+                                  repoid=repo_name, **updates)
+        response = api_call(self, params)
+        try:
+            expected = 'no permission to create (or move) repositories'
+            self._compare_error(id_, expected, given=response.body)
+        finally:
+            fixture.destroy_repo(repo_name)
+            fixture.destroy_repo(new_repo_name)
+
+    def test_api_update_repo_regular_user_change_repo_name_allowed(self):
+        repo_name = 'admin_owned'
+        new_repo_name = 'new_repo_name'
+        repo = fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
+        RepoModel().grant_user_permission(repo=repo_name,
+                                          user=self.TEST_USER_LOGIN,
+                                          perm='repository.admin')
+        UserModel().revoke_perm('default', 'hg.create.none')
+        UserModel().grant_perm('default', 'hg.create.repository')
+        updates = {'name': new_repo_name}
+        id_, params = _build_data(self.apikey_regular, 'update_repo',
+                                  repoid=repo_name, **updates)
+        response = api_call(self, params)
+        try:
+            expected = {
+                'msg': 'updated repo ID:%s %s' % (repo.repo_id, new_repo_name),
+                'repository': repo.get_api_data()
+            }
+            self._compare_ok(id_, expected, given=response.body)
+        finally:
+            fixture.destroy_repo(repo_name)
+            fixture.destroy_repo(new_repo_name)
+
     def test_api_delete_repo(self):
         repo_name = 'api_delete_me'
         fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
@@ -1303,6 +1346,27 @@
         self._compare_error(id_, expected, given=response.body)
         fixture.destroy_repo(fork_name)
 
+    @parameterized.expand([('read', 'repository.read'),
+                           ('write', 'repository.write'),
+                           ('admin', 'repository.admin')])
+    def test_api_fork_repo_non_admin_no_create_repo_permission(self, name, perm):
+        fork_name = 'api-repo-fork'
+        # regardless of base repository permission, forking is disallowed
+        # when repository creation is disabled
+        RepoModel().grant_user_permission(repo=self.REPO,
+                                          user=self.TEST_USER_LOGIN,
+                                          perm=perm)
+        UserModel().revoke_perm('default', 'hg.create.repository')
+        UserModel().grant_perm('default', 'hg.create.none')
+        id_, params = _build_data(self.apikey_regular, 'fork_repo',
+                                  repoid=self.REPO,
+                                  fork_name=fork_name,
+        )
+        response = api_call(self, params)
+        expected = 'no permission to create repositories'
+        self._compare_error(id_, expected, given=response.body)
+        fixture.destroy_repo(fork_name)
+
     def test_api_fork_repo_unknown_owner(self):
         fork_name = 'api-repo-fork'
         owner = 'i-dont-exist'