fix a few major permission holes

This commit is contained in:
Ross
2023-12-04 12:19:52 +00:00
parent f346a69bb5
commit 976f57ac20
14 changed files with 77 additions and 36 deletions
+4
View File
@@ -608,6 +608,10 @@ class QuestionClone(AnatomyQuestionCreateBase):
def get_initial(self):
# print(self.request)
old_object = get_object_or_404(AnatomyQuestion, pk=self.kwargs["pk"])
if self.request.user not in old_object.get_author_objects() and not self.request.user.is_superuser:
raise PermissionDenied() # or Http404
initial_data = model_to_dict(old_object, exclude=["id"])
# We don't want to clone the exam details
+5 -1
View File
@@ -37,9 +37,13 @@ def user_is_author_or_atlas_series_checker(function):
return wrap
def user_is_author_or_atlas_editor_or_atlas_marker(function):
def user_has_case_view_access(function):
def wrap(request, *args, **kwargs):
atlas = Case.objects.get(pk=kwargs["pk"])
# If open access everyone can view
if atlas.open_access:
return function(request, *args, **kwargs)
if (
request.user in atlas.author.all()
or request.user.groups.filter(name="atlas_editor").exists()
+2 -1
View File
@@ -12,6 +12,7 @@ from .models import (
Subspecialty,
)
from django.contrib.auth.models import User
from django.db.models import Q
def get_authors(request):
@@ -118,7 +119,7 @@ class CaseFilter(django_filters.FilterSet):
):
if not request.user.groups.filter(name="atlas_editor").exists():
queryset = queryset.prefetch_related("author").filter(
author__id=request.user.id
(Q(author__id=request.user.id) | Q(open_access=True))
)
super(CaseFilter, self).__init__(
data=data, queryset=queryset, prefix=prefix, request=request
-21
View File
@@ -1,21 +0,0 @@
{% extends 'atlas/base.html' %}
{% load render_table from django_tables2 %}
{% block css %}
{% endblock %}
{% block content %}
<div id="view-filter-options">
<h3>Filter Long </h3>
<form action="" method="get">
{{ filter.form }}
<input class="btn btn-primary btn-sm mt-1 mb-1" type="submit" />
</form>
</div>
{% render_table table %}
{% endblock %}
{% block js %}
{% endblock %}
+1 -1
View File
@@ -15,7 +15,7 @@
{% block content %}
<h2>Add/Edit Condition</h2>
<p>Use this form to create or edit a condition.</p>
<p>Please check if it already exists before doing so!</p>
<p>Please check if it already <a href='{% url "atlas:condition_view" %}'>exists</a> before doing so!</p>
<form action="" method="post" enctype="multipart/form-data" id="condition-form">
{% csrf_token %}
+1
View File
@@ -4,6 +4,7 @@
<h2>Atlas</h2>
<a href="{% url 'atlas:user_collections' %}">Available collections</a><br/>
View my <a href='{% url "atlas:case_view" %}?author={{request.user.id}}'>cases</a>.<br/>
<a href="{% url 'atlas:user_uploads' %}">My uploads</a>
{% endblock %}
+1
View File
@@ -18,6 +18,7 @@
<input class="btn btn-primary btn-sm mt-1 mb-1" type="submit" />
</form>
</div>
View my <a href='{% url "atlas:case_view" %}?author={{request.user.id}}'>cases</a>.
</details>
{% render_table table %}
</div>
+15
View File
@@ -0,0 +1,15 @@
import json
import pytest
# from django.contrib.auth.models import User
from django.urls import reverse
from rich.pretty import pprint
from bs4 import BeautifulSoup
from django.contrib.auth.models import Group
+30 -10
View File
@@ -99,12 +99,11 @@ from autocomplete import HTMXAutoComplete
from .decorators import (
user_is_author_or_atlas_editor,
user_is_author_or_atlas_editor_or_atlas_marker,
user_has_case_view_access,
user_is_author_or_atlas_series_checker_or_atlas_marker,
user_is_atlas_editor,
user_is_author_or_atlas_series_checker,
user_is_atlas_marker,
user_is_author_or_atlas_editor_or_atlas_marker,
user_is_collection_author_or_atlas_editor,
)
@@ -148,9 +147,18 @@ class AuthorOrCheckerRequiredMixin(object):
raise PermissionDenied() # or Http404
return obj
class AtlasEditorRequiredMixin(object):
def get_object(self, *args, **kwargs):
obj = super().get_object(*args, **kwargs)
if (
self.request.user.groups.filter(name="atlas_editor").exists()
or self.request.user.is_superuser
):
return obj
raise PermissionDenied("You must be an atlas editor to do this.") # or Http404
@login_required
@user_is_author_or_atlas_editor_or_atlas_marker
@user_has_case_view_access
def case_detail(request, pk):
case = get_object_or_404(Case, pk=pk)
@@ -417,31 +425,31 @@ class SeriesFindingDelete(RevisionMixin, PermissionRequiredMixin, DeleteView):
return reverse("atlas:series_detail", kwargs={"pk": series_id})
class SeriesDelete(RevisionMixin, AuthorOrCheckerRequiredMixin, DeleteView):
class SeriesDelete(RevisionMixin, AtlasEditorRequiredMixin, DeleteView):
model = Series
template_name = "confirm_delete.html"
success_url = reverse_lazy("atlas:series_view")
class CaseCollectionDelete(RevisionMixin, AuthorOrCheckerRequiredMixin, DeleteView):
class CaseCollectionDelete(RevisionMixin, AtlasEditorRequiredMixin, DeleteView):
model = CaseCollection
template_name = "confirm_delete.html"
success_url = reverse_lazy("atlas:collection_view")
class ConditionDelete(RevisionMixin, AuthorOrCheckerRequiredMixin, DeleteView):
class ConditionDelete(RevisionMixin, AtlasEditorRequiredMixin, DeleteView):
model = Condition
template_name = "confirm_delete.html"
success_url = reverse_lazy("atlas:condition_view")
class FindingDelete(RevisionMixin, AuthorOrCheckerRequiredMixin, DeleteView):
class FindingDelete(RevisionMixin, AtlasEditorRequiredMixin, DeleteView):
model = Finding
template_name = "confirm_delete.html"
success_url = reverse_lazy("atlas:finding_view")
class StructureDelete(RevisionMixin, AuthorOrCheckerRequiredMixin, DeleteView):
class StructureDelete(RevisionMixin, AtlasEditorRequiredMixin, DeleteView):
model = Structure
template_name = "confirm_delete.html"
success_url = reverse_lazy("atlas:structure_view")
@@ -867,7 +875,7 @@ def add_collection_to_case_form(request, case_id):
# return reverse("atlas:case_detail", kwargs={"pk": pk})
class AtlasClone(AtlasCreateBase, CreateView):
class AtlasClone(AtlasCreateBase, AuthorOrCheckerRequiredMixin, CreateView):
"""Clones a existing atlas"""
# fields = '__all__'
@@ -877,11 +885,23 @@ class AtlasClone(AtlasCreateBase, CreateView):
def get_initial(self):
# print(self.request)
old_object = get_object_or_404(Case, pk=self.kwargs["pk"])
initial_data = model_to_dict(old_object, exclude=["id"])
if (
self.request.user.groups.filter(name="atlas_editor").exists()
or self.request.user.is_superuser
):
pass
else:
if self.request.user not in old_object.get_author_objects():
raise PermissionDenied() # or Http404
else:
pass
initial_data = model_to_dict(old_object, exclude=["id"])
return initial_data
@login_required
@user_is_author_or_atlas_editor
def atlas_scrap(request, pk):
+4
View File
@@ -2327,6 +2327,10 @@ class GenericViewBase:
class ExamCloneMixin:
def get_initial(self):
old_object = get_object_or_404(self.model, pk=self.kwargs["exam_id"])
if self.request.user not in old_object.get_author_objects() and not self.request.user.is_superuser:
raise PermissionDenied() # or Http404
initial_data = model_to_dict(old_object, exclude=["id"])
# We manually transfer the forign keys / m2m relationships
+3
View File
@@ -271,6 +271,9 @@ def long_clone(request, pk):
new_item.pk = None # autogen a new pk (item_id)
# new_item.name = "Copy of " + new_item.name #need to change uniques
if request.user not in new_item.get_author_objects() and not request.user.is_superuser:
raise PermissionDenied() # or Http404
form = LongForm(request.POST or None, instance=new_item)
series_formset = SeriesFormSet()
+2 -1
View File
@@ -519,7 +519,8 @@ def page_not_found(request, exception):
def page_forbidden(request, exception):
response = render(request, "403.html")
response = render(request, "403.html", context={"exception": exception})
response.status_code = 403
+4
View File
@@ -212,8 +212,12 @@ def rapid_clone(request, pk):
new_item.pk = None # autogen a new pk (item_id)
# new_item.name = "Copy of " + new_item.name #need to change uniques
if request.user not in new_item.get_author_objects() and not request.user.is_superuser:
raise PermissionDenied() # or Http404
form = RapidForm(request.POST or None, instance=new_item)
image_formset = ImageFormSet()
answer_formset = AnswerFormSet()
+5 -1
View File
@@ -4,7 +4,11 @@
{% load static %}
<div class="">
<h2>403 error</h2>
{% if exception and not exception.strip %}
<p>{{ exception }}</p>
{% else %}
<p>Forbidden</p>
{% endif %}
<img src="{% static 'img/x-ray-radiation-no-unauthorised.png' %}" width="500px">
Forbidden
</div>
{% endblock %}