Skip to content

Commit 00b1064

Browse files
author
Bart van der Schoor
committed
WIP [#912] Harden access control on case-details/documents
1 parent 0b2e772 commit 00b1064

File tree

6 files changed

+127
-6
lines changed

6 files changed

+127
-6
lines changed

src/open_inwoner/accounts/urls.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787
path("themes/", MyCategoriesView.as_view(), name="my_themes"),
8888
path("cases/", CasesListView.as_view(), name="my_cases"),
8989
path(
90-
"cases/document/<str:object_id>/",
90+
"cases/<str:object_id>/document/<str:info_id>/",
9191
CasesDocumentDownloadView.as_view(),
9292
name="case_document_download",
9393
),

src/open_inwoner/accounts/views/cases.py

+24-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from zgw_consumers.concurrent import parallel
1818

1919
from open_inwoner.openzaak.cases import (
20+
fetch_case_roles_for_bsn,
2021
fetch_case_types,
2122
fetch_cases,
2223
fetch_single_case,
@@ -26,6 +27,7 @@
2627
InformatieObject,
2728
create_document_content_stream,
2829
fetch_case_information_objects,
30+
fetch_case_information_objects_for_case_and_info,
2931
fetch_single_information_object,
3032
fetch_single_information_object_uuid,
3133
)
@@ -174,6 +176,10 @@ def get_context_data(self, **kwargs):
174176
case = fetch_single_case(case_uuid)
175177

176178
if case:
179+
# check if we have a role this case
180+
if not fetch_case_roles_for_bsn(case.url, self.request.user.bsn):
181+
raise PermissionDenied()
182+
177183
documents = self.get_case_document_files(case)
178184

179185
statuses = fetch_status_history(case.url)
@@ -243,7 +249,8 @@ def get_case_document_files(self, case) -> List[SimpleFile]:
243249
url=reverse(
244250
"accounts:case_document_download",
245251
kwargs={
246-
"object_id": info_obj.uuid,
252+
"object_id": case.uuid,
253+
"info_id": info_obj.uuid,
247254
},
248255
),
249256
)
@@ -273,12 +280,27 @@ def handle_no_permission(self):
273280
return super().handle_no_permission()
274281

275282
def get(self, *args, **kwargs):
276-
info_object_uuid = kwargs["object_id"]
283+
case_uuid = kwargs["object_id"]
284+
case = fetch_single_case(case_uuid)
285+
if not case:
286+
raise Http404
287+
288+
# check if we have a role this case
289+
if not fetch_case_roles_for_bsn(case.url, self.request.user.bsn):
290+
raise PermissionDenied()
277291

292+
info_object_uuid = kwargs["info_id"]
278293
info_object = fetch_single_information_object_uuid(info_object_uuid)
279294
if not info_object:
280295
raise Http404
281296

297+
# check if this info_object belongs to this case
298+
if not fetch_case_information_objects_for_case_and_info(
299+
case.url, info_object.url
300+
):
301+
raise PermissionDenied()
302+
303+
# check if this info_object should be visible
282304
config = OpenZaakConfig.get_solo()
283305
if not filter_info_object_visibility(
284306
info_object, config.document_max_confidentiality

src/open_inwoner/openzaak/cases.py

+29-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from zds_client import ClientError
88
from zgw_consumers.api_models.base import factory
99
from zgw_consumers.api_models.catalogi import ZGWModel
10-
from zgw_consumers.api_models.zaken import Zaak
10+
from zgw_consumers.api_models.zaken import Rol, Zaak
1111
from zgw_consumers.service import get_paginated_results
1212

1313
from .clients import build_client
@@ -152,3 +152,31 @@ def fetch_single_case_type(case_type_url: str) -> Optional[ZaakType]:
152152
case_type = factory(ZaakType, response)
153153

154154
return case_type
155+
156+
157+
def fetch_case_roles_for_bsn(case_url: str, bsn: str) -> List[Rol]:
158+
client = build_client("zaak")
159+
160+
if client is None:
161+
return []
162+
163+
try:
164+
response = client.list(
165+
"rol",
166+
request_kwargs={
167+
"params": {
168+
"zaak": case_url,
169+
"betrokkeneIdentificatie__natuurlijkPersoon__inpBsn": bsn,
170+
}
171+
},
172+
)
173+
except RequestException as e:
174+
logger.exception("exception while making request", exc_info=e)
175+
return []
176+
except ClientError as e:
177+
logger.exception("exception while making request", exc_info=e)
178+
return []
179+
180+
roles = factory(Rol, response["results"])
181+
182+
return roles

src/open_inwoner/openzaak/info_objects.py

+30
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,36 @@ def fetch_case_information_objects(case_url: str) -> List[ZaakInformatieObject]:
7979
return case_info_objects
8080

8181

82+
def fetch_case_information_objects_for_case_and_info(
83+
case_url: str, info_object_url: str
84+
) -> List[ZaakInformatieObject]:
85+
client = build_client("zaak")
86+
87+
if client is None:
88+
return []
89+
90+
try:
91+
response = client.list(
92+
"zaakinformatieobject",
93+
request_kwargs={
94+
"params": {
95+
"zaak": case_url,
96+
"informatieobject": info_object_url,
97+
},
98+
},
99+
)
100+
except RequestException as e:
101+
logger.exception("exception while making request", exc_info=e)
102+
return []
103+
except ClientError as e:
104+
logger.exception("exception while making request", exc_info=e)
105+
return []
106+
107+
case_info_objects = factory(ZaakInformatieObject, response)
108+
109+
return case_info_objects
110+
111+
82112
def fetch_single_information_object(info_object_url: str) -> Optional[InformatieObject]:
83113
client = build_client("document")
84114

src/open_inwoner/openzaak/tests/test_documents.py

+26-1
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111
from open_inwoner.accounts.tests.factories import UserFactory
1212

1313
from ...accounts.views.cases import SimpleFile
14+
from ...utils.test import paginated_response
1415
from ..models import OpenZaakConfig
1516
from .factories import ServiceFactory
1617

18+
ZAKEN_ROOT = "https://zaken.nl/api/v1/"
1719
CATALOGI_ROOT = "https://catalogi.nl/api/v1/"
1820
DOCUMENTEN_ROOT = "https://documenten.nl/api/v1/"
1921

@@ -40,6 +42,24 @@ def setUpTestData(self):
4042
)
4143
self.config.save()
4244

45+
self.zaak = generate_oas_component(
46+
"zrc",
47+
"schemas/Zaak",
48+
uuid="d8bbdeb7-770f-4ca9-b1ea-77b4730bf67d",
49+
url=f"{ZAKEN_ROOT}zaken/d8bbdeb7-770f-4ca9-b1ea-77b4730bf67d",
50+
zaaktype=f"{CATALOGI_ROOT}zaaktypen/53340e34-7581-4b04-884f",
51+
identificatie="ZAAK-2022-0000000024",
52+
omschrijving="Zaak naar aanleiding van ingezonden formulier",
53+
startdatum="2022-01-02",
54+
einddatum=None,
55+
status=f"{ZAKEN_ROOT}statussen/3da89990-c7fc-476a-ad13-c9023450083c",
56+
)
57+
self.role = generate_oas_component(
58+
"zrc",
59+
"schemas/Rol",
60+
url=f"{ZAKEN_ROOT}rollen/f33153aa-ad2c-4a07-ae75-15add5891",
61+
betrokkene_identificatie="foo",
62+
)
4363
self.informatie_object_content = "my document content".encode("utf8")
4464
self.informatie_object = generate_oas_component(
4565
"drc",
@@ -60,7 +80,8 @@ def setUpTestData(self):
6080
url=reverse(
6181
"accounts:case_document_download",
6282
kwargs={
63-
"object_id": self.informatie_object["uuid"],
83+
"object_id": self.zaak["uuid"],
84+
"info_id": self.informatie_object["uuid"],
6485
},
6586
),
6687
)
@@ -69,6 +90,10 @@ def _setUpMocks(self, m):
6990
mock_service_oas_get(m, DOCUMENTEN_ROOT, "drc")
7091
m.get(self.informatie_object["url"], json=self.informatie_object)
7192
m.get(self.informatie_object["inhoud"], content=self.informatie_object_content)
93+
m.get(
94+
f"{ZAKEN_ROOT}rollen?zaak={self.zaak['url']}&betrokkeneIdentificatie__natuurlijkPersoon__inpBsn={self.user.bsn}",
95+
json=paginated_response([self.role]),
96+
)
7297

7398
def test_document_content_is_retrieved_when_user_logged_in_via_digid(self, m):
7499
self._setUpMocks(m)

src/open_inwoner/openzaak/tests/test_statuses.py

+17-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import requests_mock
88
from django_webtest import WebTest
9+
from furl import furl
910
from zgw_consumers.api_models.base import factory
1011
from zgw_consumers.api_models.catalogi import StatusType
1112
from zgw_consumers.api_models.constants import VertrouwelijkheidsAanduidingen
@@ -58,6 +59,7 @@ def setUpTestData(self):
5859
self.zaak = generate_oas_component(
5960
"zrc",
6061
"schemas/Zaak",
62+
uuid="d8bbdeb7-770f-4ca9-b1ea-77b4730bf67d",
6163
url=f"{ZAKEN_ROOT}zaken/d8bbdeb7-770f-4ca9-b1ea-77b4730bf67d",
6264
zaaktype=f"{CATALOGI_ROOT}zaaktypen/53340e34-7581-4b04-884f",
6365
identificatie="ZAAK-2022-0000000024",
@@ -126,6 +128,12 @@ def setUpTestData(self):
126128
volgnummer=2,
127129
is_eindstatus=False,
128130
)
131+
self.role = generate_oas_component(
132+
"zrc",
133+
"schemas/Rol",
134+
url=f"{ZAKEN_ROOT}rollen/f33153aa-ad2c-4a07-ae75-15add5891",
135+
betrokkene_identificatie="foo",
136+
)
129137
self.zaak_informatie_object = generate_oas_component(
130138
"zrc",
131139
"schemas/ZaakInformatieObject",
@@ -185,7 +193,8 @@ def setUpTestData(self):
185193
url=reverse(
186194
"accounts:case_document_download",
187195
kwargs={
188-
"object_id": self.informatie_object["uuid"],
196+
"object_id": self.zaak["uuid"],
197+
"info_id": self.informatie_object["uuid"],
189198
},
190199
),
191200
)
@@ -206,6 +215,10 @@ def _setUpMocks(self, m):
206215
f"{ZAKEN_ROOT}statussen?zaak={self.zaak['url']}",
207216
json=paginated_response([self.status1, self.status2]),
208217
)
218+
m.get(
219+
f"{ZAKEN_ROOT}rollen?zaak={self.zaak['url']}&betrokkeneIdentificatie__natuurlijkPersoon__inpBsn={self.user.bsn}",
220+
json=paginated_response([self.role]),
221+
)
209222
m.get(f"{CATALOGI_ROOT}zaaktypen/53340e34-7581-4b04-884f", json=self.zaaktype)
210223
m.get(
211224
f"{CATALOGI_ROOT}statustypen?zaaktype={self.zaaktype['url']}",
@@ -324,6 +337,9 @@ def test_anonymous_user_has_no_access_to_status_page(self, m):
324337
f"{reverse('login')}?next={reverse('accounts:case_status', kwargs={'object_id': 'd8bbdeb7-770f-4ca9-b1ea-77b4730bf67d'})}",
325338
)
326339

340+
def test_access_with_role(self, m):
341+
self.fail("implement me")
342+
327343
def test_no_data_is_retrieved_when_http_404(self, m):
328344
mock_service_oas_get(m, ZAKEN_ROOT, "zrc")
329345
mock_service_oas_get(m, CATALOGI_ROOT, "ztc")

0 commit comments

Comments
 (0)