From 6690c75ba19e09e897c62dfb9750f481fd645c10 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Feb 10 2020 10:03:48 +0000 Subject: [PATCH 1/2] Hide the SSH clone URL if the user is not in one of the group with ssh access Some deployment of pagure have it set up in such a way that only the members of certain groups can commit via SSH. For this reason, there is not need to display the ssh url since they cannot use it. Fixes https://pagure.io/pagure-dist-git/issue/97 Signed-off-by: Pierre-Yves Chibon --- diff --git a/doc/configuration.rst b/doc/configuration.rst index 86a27f9..23118f2 100644 --- a/doc/configuration.rst +++ b/doc/configuration.rst @@ -818,6 +818,22 @@ the default branch of the repo will be the default target of all pull requests. Defaults to: ``False``. + +SSH_ACCESS_GROUPS +~~~~~~~~~~~~~~~~~ + +Some instances of pagure are deployed in such a way that only the members of +certain groups are allowed to commit via ssh. This configuration key allows +to specify which groups have commit access and thus let pagure hide the ssh +URL from the drop-down "Clone" menu for all the person who are not in one of +these groups. +If this configuration key is not defined or left empty, it is assume that there +is no such group restriction and everyone can commit via ssh (default behavior). + + +Defaults to: ``[]`` + + SMTP configuration ~~~~~~~~~~~~~~~~~~ diff --git a/pagure/templates/repo_master.html b/pagure/templates/repo_master.html index a9c75cf..d46652d 100644 --- a/pagure/templates/repo_master.html +++ b/pagure/templates/repo_master.html @@ -6,6 +6,8 @@ You need to upload SSH key to be able to clone over SSH + {% elif not (current_user | user_group_can_ssh_commit) %} + Only members of the {{ config["SSH_ACCESS_GROUPS"] | join(", ") }} group(s) can clone via ssh {% elif repo.read_only %} The permissions on this repository are being updated. Cloning over SSH is disabled. diff --git a/pagure/ui/filters.py b/pagure/ui/filters.py index 4a0b822..933f0bb 100644 --- a/pagure/ui/filters.py +++ b/pagure/ui/filters.py @@ -813,6 +813,24 @@ def user_can_clone_ssh(username): return always_render or has_ssh_keys +@UI_NS.app_template_filter("user_group_can_ssh_commit") +def user_group_can_ssh_commit(username): + """ Returns whether the user is in a group that has ssh access. """ + ssh_access_groups = pagure_config.get("SSH_ACCESS_GROUPS") or [] + if not ssh_access_groups: + # ssh access is not restricted to one or more groups + return True + + user_obj = pagure.lib.query.search_user(flask.g.session, username=username) + if not user_obj: + # user not found + return False + + user_grps = set(user_obj.groups) + req_grps = set(pagure_config.get("SSH_ACCESS_GROUPS")) + return len(user_grps.intersection(req_grps)) > 0 + + @UI_NS.app_template_filter("git_url_ssh") def get_git_url_ssh(complement=""): """ Return the GIT SSH URL to be displayed in the UI based on the diff --git a/tests/test_pagure_flask_ui_repo.py b/tests/test_pagure_flask_ui_repo.py index 15a573b..7a83290 100644 --- a/tests/test_pagure_flask_ui_repo.py +++ b/tests/test_pagure_flask_ui_repo.py @@ -6611,5 +6611,130 @@ class PagureFlaskRepoTestRegenerateGittests(tests.Modeltests): self.assertEqual(upgit.call_count, 1) +class PagureFlaskRepoTestGitSSHURL(tests.Modeltests): + """ Tests the display of the SSH url in the UI """ + + def setUp(self): + """ Set up the environnment, ran before every tests. """ + super(PagureFlaskRepoTestGitSSHURL, self).setUp() + + tests.create_projects(self.session) + tests.create_projects_git(os.path.join(self.path, "repos")) + pingou = pagure.lib.query.get_user(self.session, "pingou") + + # Make the repo not read-only + repo = pagure.lib.query._get_project(self.session, "test") + pagure.lib.query.update_read_only_mode( + self.session, repo, read_only=False + ) + self.session.commit() + + # Add a group and make pingou a member of it + item = pagure.lib.model.PagureGroup( + group_name="packager", + group_type="user", + display_name="User group", + user_id=1, # pingou + ) + self.session.add(item) + self.session.commit() + + pagure.lib.query.add_user_to_group( + self.session, pingou.username, item, pingou.username, True + ) + + # Add a SSH key for pingou so that he is allowed to push via ssh + msg = pagure.lib.query.add_sshkey_to_project_or_user( + session=self.session, + user=pingou, + ssh_key="ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAzBMSIlvPRaEiLOTVInErkRIw9CzQQcnslDekAn1jFnGf+SNa1acvbTiATbCX71AA03giKrPxPH79dxcC7aDXerc6zRcKjJs6MAL9PrCjnbyxCKXRNNZU5U9X/DLaaL1b3caB+WD6OoorhS3LTEtKPX8xyjOzhf3OQSzNjhJp5Q==", + pushaccess=True, + creator=pingou, + ) + self.session.commit() + self.assertEqual(msg, "SSH key added") + + def test_logged_out(self): + """ Test the default behavior with the user logged out. """ + + output = self.app.get("/test") + self.assertEqual(output.status_code, 200) + output_text = output.get_data(as_text=True) + self.assertIn("Source Code", output_text) + self.assertIn( + '
' + "GIT
", + output_text, + ) + self.assertNotIn( + '
' + "SSH
", + output_text, + ) + + def test_logged_in(self): + """ Test the default behavior with the user logged in. """ + user = tests.FakeUser(username="pingou") + with tests.user_set(self.app.application, user): + output = self.app.get("/test") + self.assertEqual(output.status_code, 200) + output_text = output.get_data(as_text=True) + self.assertIn("Source Code", output_text) + self.assertIn( + '
' + "GIT
", + output_text, + ) + self.assertIn( + '
' + "SSH
", + output_text, + ) + + @patch.dict("pagure.config.config", {"SSH_ACCESS_GROUPS": ["packager"]}) + def test_ssh_restricted_user_member(self): + """ Test when ssh is restricted and the user has access. """ + user = tests.FakeUser(username="pingou") + with tests.user_set(self.app.application, user): + output = self.app.get("/test") + self.assertEqual(output.status_code, 200) + output_text = output.get_data(as_text=True) + self.assertIn("Source Code", output_text) + self.assertIn( + '
' + "GIT
", + output_text, + ) + self.assertIn( + '
' + "SSH
", + output_text, + ) + + @patch.dict("pagure.config.config", {"SSH_ACCESS_GROUPS": ["invalid"]}) + def test_ssh_restricted_user_non_member(self): + """ Test when ssh is restricted and the user does not have access. """ + user = tests.FakeUser(username="pingou") + with tests.user_set(self.app.application, user): + output = self.app.get("/test") + self.assertEqual(output.status_code, 200) + output_text = output.get_data(as_text=True) + self.assertIn("Source Code", output_text) + self.assertIn( + '
' + "GIT
", + output_text, + ) + self.assertIn( + "Only members of the invalid group(s) can clone via ssh", + output_text, + ) + self.assertNotIn( + '
' + "SSH
", + output_text, + ) + + if __name__ == "__main__": unittest.main(verbosity=2) From 5405a22371e1c8f69da8c0628e098789f52a0481 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Feb 10 2020 10:03:48 +0000 Subject: [PATCH 2/2] Drop un-used import Signed-off-by: Pierre-Yves Chibon --- diff --git a/tests/test_pagure_utils.py b/tests/test_pagure_utils.py index 4cb04fd..dd33fde 100644 --- a/tests/test_pagure_utils.py +++ b/tests/test_pagure_utils.py @@ -18,7 +18,6 @@ import os import mock import munch import pygit2 -import werkzeug sys.path.insert( 0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")