TT#152750 enforce perms in views and templates

Change-Id: Ifbffb02c5bc833cc4295745c7729e34fa8e0486a
pull/7/head
Victor Seva 3 years ago
parent 10ce513d20
commit 1ad5cce788

@ -1,4 +1,4 @@
# Copyright (C) 2017-2020 The Sipwise Team - http://sipwise.com
# Copyright (C) 2017-2022 The Sipwise Team - http://sipwise.com
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
@ -16,7 +16,7 @@ import django_filters
from django.http import JsonResponse
from django.shortcuts import get_object_or_404
from rest_framework import generics
from rest_framework.permissions import IsAuthenticated
from rest_framework.permissions import DjangoModelPermissions
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework_api_key.permissions import HasAPIKey
@ -37,14 +37,14 @@ class BuildReleaseFilter(django_filters.FilterSet):
class BuildReleaseList(generics.ListCreateAPIView):
permission_classes = [HasAPIKey | IsAuthenticated]
permission_classes = [HasAPIKey | DjangoModelPermissions]
queryset = models.BuildRelease.objects.all().order_by("id")
serializer_class = serializers.BuildReleaseSerializer
filter_class = BuildReleaseFilter
class BuildReleaseDetail(generics.RetrieveDestroyAPIView):
permission_classes = [HasAPIKey | IsAuthenticated]
permission_classes = [HasAPIKey | DjangoModelPermissions]
queryset = models.BuildRelease.objects.all().order_by("id")
serializer_class = serializers.BuildReleaseSerializer
@ -69,7 +69,7 @@ class BuildReleaseDetail(generics.RetrieveDestroyAPIView):
class BuildProject(APIView):
permission_classes = [HasAPIKey | IsAuthenticated]
permission_classes = [HasAPIKey | DjangoModelPermissions]
def post(self, request, release_uuid, project):
br = get_object_or_404(models.BuildRelease, uuid=release_uuid)

@ -3,10 +3,12 @@
<a class="link" name="" href=""></a>
</span>
<div class="pull-right">
{% if perms.build.can_trigger %}
<form method="POST" class="form-inline">
{% csrf_token %}
<button class="btn-default btn-info retrigger-project-url hidden">Retrigger</button>
</form>
{% endif %}
<a class="badge latest-uuid-url" href="">latest</a>
</div>
</div>

@ -16,11 +16,12 @@
<td>{{ build_release.branch }}</td>
<td>{{ build_release.start_date }}</td>
<td id="action_list">
{% if perms.build.can_trigger %}
<button type="button" id="resume"
disabled="disabled"
onclick="click_resume(event, '{{ build_release.id }}')"
class="btn btn-primary">Resume</button>
</td>
{% endif %}
</td>
</tr>
</table>

@ -7,7 +7,7 @@
{% endblock %}
{% block content %}
<div class="container">
<div class="panel panel-default">
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title"><b>{{ config.release }}</b></h2>
</div>
@ -27,7 +27,7 @@
<form method="POST" class="form-inline">
{% csrf_token %}
<button type="submit" class="btn btn-primary" id="build_button"
{% if not done %}disabled="disabled"{% endif %}>Build</button>
{% if not done or not perms.build.can_trigger %}disabled="disabled"{% endif %}>Build</button>
</form>
</td>
</tr>
@ -47,10 +47,11 @@
<td>{{ br.last_update }}</td>
<td>
<button type="button" id="refresh_{{ br.id }}"
onclick="click_refresh_projects(event, '{{ br.id }}')"
class="btn btn-primary">Refresh projects</button>
{% if perms.build.can_trigger %}onclick="click_refresh_projects(event, '{{ br.id }}')"{% endif %}
class="btn btn-primary" {% if not perms.build.can_trigger %}disabled="disabled"{% endif %}>Refresh projects</button>
<button type="button"
onclick="click_delete(event, '{{ br.id }}')" class="btn btn-danger">Delete</button>
{% if perms.build.can_trigger %}onclick="click_delete(event, '{{ br.id }}')"{% endif %}
class="btn btn-danger" {% if not perms.build.can_trigger %}disabled="disabled"{% endif %}>Delete</button>
</td>
</tr>
{% endfor %}
@ -64,7 +65,8 @@
<div class="row">
<h3 class="col-xs-10 panel-title">Projects to build</h3>
<div class="col-xs-1 hidden" id="hotfix">
<a href="{% url 'release_dashboard:hotfix_release' config.release %}" class="btn btn-primary right">Hotfixes</a>
<a href="{% url 'release_dashboard:hotfix_release' config.release %}"
class="btn btn-primary right" {% if not perms.build.can_trigger_hotfix %}disabled="disabled"{% endif %}>Hotfixes</a>
</div>
</div>
</div>

@ -14,7 +14,9 @@
# with this prograproj. If not, see <http://www.gnu.org/licenses/>.
from unittest.mock import patch
from django.contrib.auth.models import Permission
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.test import override_settings
from django.test import TestCase
from django.urls import reverse
@ -23,13 +25,26 @@ from build.models import BuildRelease
from repoapi.test.base import BaseTest
def add_perm(user, model, codename):
ct = ContentType.objects.get_for_model(model)
perm = Permission.objects.get(content_type=ct, codename=codename)
user.user_permissions.add(perm)
class TestHotfix(TestCase):
def test_no_login(self):
res = self.client.get(reverse("release_dashboard:hotfix"))
self.assertNotEqual(res.status_code, 200)
def test_login_no_perm(self):
user = User.objects.create_user(username="test")
self.client.force_login(user)
res = self.client.get(reverse("release_dashboard:hotfix"))
self.assertEqual(res.status_code, 403)
def test_login_ok(self):
user = User.objects.create_user(username="test")
add_perm(user, BuildRelease, "can_trigger_hotfix")
self.client.force_login(user)
res = self.client.get(reverse("release_dashboard:hotfix"))
self.assertEqual(res.status_code, 200)
@ -39,6 +54,7 @@ class TestHotfix(TestCase):
@patch("release_dashboard.views.get_branches")
def test_natural_sort(self, gb, gt):
user = User.objects.create_user(username="test")
add_perm(user, BuildRelease, "can_trigger_hotfix")
self.client.force_login(user)
gt.return_value = []
gb.return_value = [
@ -77,8 +93,19 @@ class TestHotfixRelease(TestCase):
)
self.assertNotEqual(res.status_code, 200)
def test_login_no_perm(self):
user = User.objects.create_user(username="test")
self.client.force_login(user)
res = self.client.get(
reverse(
"release_dashboard:hotfix_release", args=["release-mr7.5.2"]
)
)
self.assertEqual(res.status_code, 403)
def test_login_ok(self):
user = User.objects.create_user(username="test")
add_perm(user, BuildRelease, "can_trigger_hotfix")
self.client.force_login(user)
res = self.client.get(
reverse(
@ -89,6 +116,7 @@ class TestHotfixRelease(TestCase):
def test_no_mrXXX(self):
user = User.objects.create_user(username="test")
add_perm(user, BuildRelease, "can_trigger_hotfix")
self.client.force_login(user)
res = self.client.get(
reverse("release_dashboard:hotfix_release", args=["release-mr7.5"])
@ -105,6 +133,7 @@ class TestHotfixRelease(TestCase):
def test_project_ok(self):
user = User.objects.create_user(username="test")
add_perm(user, BuildRelease, "can_trigger_hotfix")
self.client.force_login(user)
res = self.client.post(
reverse(
@ -118,6 +147,7 @@ class TestHotfixRelease(TestCase):
def test_project_wrong(self):
user = User.objects.create_user(username="test")
add_perm(user, BuildRelease, "can_trigger_hotfix")
self.client.force_login(user)
res = self.client.post(
reverse(

@ -17,6 +17,8 @@ import uuid
import structlog
from django.contrib.auth.decorators import login_required
from django.contrib.auth.decorators import permission_required
from django.core.exceptions import PermissionDenied
from django.http import HttpResponseNotFound
from django.http import HttpResponseRedirect
from django.http import JsonResponse
@ -52,6 +54,8 @@ def index(request):
def build_release(request, release):
release_config = ReleaseConfig(release)
if request.method == "POST":
if not request.user.has_perm("build.can_trigger"):
raise PermissionDenied()
release_uuid = uuid.uuid4()
BuildRelease.objects.create_build_release(release_uuid, release)
return HttpResponseRedirect(
@ -77,6 +81,7 @@ def build_release(request, release):
@login_required
@require_http_methods(["POST"])
@permission_required("build.can_trigger_hotfix", raise_exception=True)
def hotfix_build(request, branch, project):
if project not in settings.RELEASE_DASHBOARD_PROJECTS:
error = "repo:%s not valid" % project
@ -104,6 +109,7 @@ def hotfix_build(request, branch, project):
@login_required
@permission_required("build.can_trigger_hotfix", raise_exception=True)
def hotfix(request):
prj_list = _projects_versions(
settings.RELEASE_DASHBOARD_PROJECTS, regex_hotfix
@ -114,6 +120,7 @@ def hotfix(request):
@login_required
@require_http_methods(["POST"])
@permission_required("build.can_trigger_hotfix", raise_exception=True)
def hotfix_release_build(request, release, project):
release_config = ReleaseConfig(release)
if project not in release_config.projects:
@ -138,6 +145,7 @@ def hotfix_release_build(request, release, project):
@login_required
@permission_required("build.can_trigger_hotfix", raise_exception=True)
def hotfix_release(request, release):
release_config = ReleaseConfig(release)
if not regex_hotfix.match(release_config.branch):
@ -164,6 +172,7 @@ def refresh_all(request):
return render(request, template, {"projects": projects})
@login_required
@require_http_methods(["POST"])
def refresh(request, project):
res = gerrit_fetch_info.delay(project)

@ -0,0 +1,86 @@
# Generated by Django 3.2.13 on 2022-06-14 16:12
from django.contrib.auth.management import create_permissions
from django.db import migrations
def add_permissions(apps, schema_editor):
"""ContentType table is populated after all the migrations applied"""
for app_config in apps.get_app_configs():
app_config.models_module = True
create_permissions(app_config, verbosity=0)
app_config.models_module = None
def reverse_func(apps, schema_editor):
add_permissions(apps, schema_editor)
Group = apps.get_model("auth", "Group")
Permission = apps.get_model("auth", "Permission")
ContentType = apps.get_model("contenttypes", "ContentType")
db_alias = schema_editor.connection.alias
dev_grp = Group.objects.using(db_alias).get(name="dev")
devops_grp = Group.objects.using(db_alias).get(name="devops")
BuildRelease = apps.get_model("build", "BuildRelease")
ct = ContentType.objects.get_for_model(BuildRelease)
# these are the wrong ones!!
devops_grp.permissions.set(
[
Permission.objects.using(db_alias).get(
content_type=ct, codename="can_trigger_hotfix"
),
]
)
dev_grp.permissions.set(
[
Permission.objects.using(db_alias).get(
content_type=ct, codename="can_trigger"
),
]
)
def forwards_func(apps, schema_editor):
add_permissions(apps, schema_editor)
Group = apps.get_model("auth", "Group")
Permission = apps.get_model("auth", "Permission")
ContentType = apps.get_model("contenttypes", "ContentType")
db_alias = schema_editor.connection.alias
dev_grp = Group.objects.using(db_alias).get(name="dev")
devops_grp = Group.objects.using(db_alias).get(name="devops")
BuildRelease = apps.get_model("build", "BuildRelease")
ct = ContentType.objects.get_for_model(BuildRelease)
perm_codenames = ["can_trigger", "can_trigger_hotfix"]
for perm in ("add", "change", "delete", "view"):
perm_codenames.append(f"{perm}_buildrelease")
perms = []
for codename in perm_codenames:
perm = Permission.objects.using(db_alias).get(
content_type=ct, codename=codename
)
perms.append(perm)
devops_grp.permissions.set(perms)
dev_grp.permissions.set(
[
Permission.objects.using(db_alias).get(
content_type=ct, codename="can_trigger_hotfix"
),
]
)
class Migration(migrations.Migration):
dependencies = [
("repoapi", "0011_ldap_groups"),
]
operations = [
migrations.RunPython(forwards_func, reverse_func),
]
Loading…
Cancel
Save