def get_out_of_sync_autorisaties(field: str) -> List[Autorisatie]: to_delete = [] for autorisatie in Autorisatie.objects.exclude(**{field: ""}): value = getattr(autorisatie, field) if not is_local_url(value): continue parsed = urlparse(value) try: get_resource_for_path(parsed.path) except ObjectDoesNotExist: to_delete.append(autorisatie) return to_delete
def migrate_from_url(apps, _): ZaakTypenRelatie = apps.get_model('datamodel.ZaakTypenRelatie') for relation in ZaakTypenRelatie.objects.all(): zaaktype_naar = get_resource_for_path(relation.gerelateerd_zaaktype) relation.zaaktype_naar = zaaktype_naar relation.save()
def has_permission(self, request: Request, view) -> bool: from rest_framework.viewsets import ViewSetMixin if bypass_permissions(request): return True scopes_required = get_required_scopes(view) component = self.get_component(view) if not self.permission_fields: return request.jwt_auth.has_auth(scopes_required, component) main_resource = self.get_main_resource() if view.action == "create": if view.__class__ is main_resource: main_object_data = request.data else: main_object_url = request.data[view.permission_main_object] main_object_path = urlparse(main_object_url).path main_object = get_resource_for_path(main_object_path) main_object_data = self.format_data(main_object, request) fields = self.get_fields(main_object_data) return request.jwt_auth.has_auth(scopes_required, component, **fields) # detect if this is an unsupported method - if it's a viewset and the # action was not mapped, it's not supported and DRF will catch it if view.action is None and isinstance(view, ViewSetMixin): return True # by default - check if the action is allowed at all return request.jwt_auth.has_auth(scopes_required, component)
def has_permission(self, request: Request, view) -> bool: # permission checks run before the handler is determined. if there is no handler, # a "method is not allowed" must be raised, not an HTTP 403 (see #385) # this implementation works for both APIView and viewsets has_handler = hasattr(view, request.method.lower()) if not has_handler: view.http_method_not_allowed(request) # JWTs are only valid for a short amount of time self.check_jwt_expiry(request.jwt_auth.payload) from rest_framework.viewsets import ViewSetMixin if bypass_permissions(request): return True scopes_required = get_required_scopes(view) component = self.get_component(view) if not self.permission_fields: return request.jwt_auth.has_auth(scopes_required, component) main_resource = self.get_main_resource() if view.action == "create": if view.__class__ is main_resource: main_object_data = request.data else: main_object_url = request.data[view.permission_main_object] main_object_path = urlparse(main_object_url).path try: main_object = get_resource_for_path(main_object_path) except ObjectDoesNotExist: raise ValidationError({ view.permission_main_object: ValidationError( _("The object does not exist in the database"), code="object-does-not-exist", ).detail }) except DjangoValidationError as exc: err_dict = as_serializer_error( ValidationError({view.permission_main_object: exc})) raise ValidationError(err_dict) main_object_data = self.format_data(main_object, request) fields = self.get_fields(main_object_data) return request.jwt_auth.has_auth(scopes_required, component, **fields) # detect if this is an unsupported method - if it's a viewset and the # action was not mapped, it's not supported and DRF will catch it if view.action is None and isinstance(view, ViewSetMixin): return True # by default - check if the action is allowed at all return request.jwt_auth.has_auth(scopes_required, component)
def m2m_filter(queryset, name, value): parsed = urlparse(value) path = parsed.path try: object = get_resource_for_path(path) except ObjectDoesNotExist: return queryset.none() return queryset.filter(**{name: object})
def _get_obj(self, view, request): """ Overridden to ensure that the correct key is used to retrieve the url from the request data """ main_obj_path = request.data.get(self.obj_path.split(".")[0], None) main_obj_url = urlparse(main_obj_path).path main_obj = get_resource_for_path(main_obj_url) return main_obj
def get_loose_fk_object(self, authorization, local=True) -> Union[models.Model, str]: loose_fk_url = getattr(authorization, self.loose_fk_field) if local: loose_fk_object_path = urlparse(loose_fk_url).path loose_fk_object = get_resource_for_path(loose_fk_object_path) else: loose_fk_object = loose_fk_url return loose_fk_object
def filter_for_authorizations( self, scope: Scope, authorizations: models.QuerySet) -> models.QuerySet: """ Filter objects whitelisted by the authorizations. For BRC, authorizations are defined around ``Autorisatie.besluittype``, limiting scopes that apply for the ``besluittype`` at hand. This means that ``besluiten`` are included if, and only if: * the ``besluittype`` is provided in ``authorizations`` * the scopes for the ``besluittype`` in each ``authorization`` contain the required``scope`` :param scope: a (possibly complex) scope that must be granted on the authorizations :param authorizations: queryset of :class:`vng_api_common.authorizations.Autorisatie` objects :return: a queryset of filtered results according to the authorizations provided """ prefix = ("" if not self.authorizations_lookup else f"{self.authorizations_lookup}__") # keep a list of allowed besluittypen besluittypen = [] for authorization in authorizations: if scope.is_contained_in(authorization.scopes): besluittype_path = urlparse(authorization.besluittype).path besluittype = get_resource_for_path(besluittype_path) besluittypen.append(besluittype) # filtering: # * only allow the white-listed besluittypen, explicitly queryset = self.filter(**{f"{prefix}besluittype__in": besluittypen}) return queryset
def filter_for_authorizations( self, scope: Scope, authorizations: models.QuerySet) -> models.QuerySet: """ Filter objects whitelisted by the authorizations. For ZRC, authorizations are defined around ``Autorisatie.zaaktype``, with a ``max_vertrouwelijkheidaanduiding`` limiting the confidentiality level of ``zaken`` (inclusive), and scopes that apply for the ``zaaktype`` at hand. This means that ``zaken`` are included if, and only if: * the ``zaaktype`` is provided in ``authorizations`` * the scopes for the ``zaaktype`` in each ``authorization`` contain the required``scope`` * the ``zaak.vertrouwelijkheidaanduiding`` is less then or equal to the ``authorization.max_vertrouwelijkheidaanduiding`` :param scope: a (possibly complex) scope that must be granted on the authorizations :param authorizations: queryset of :class:`vng_api_common.authorizations.Autorisatie` objects :return: a queryset of filtered results according to the authorizations provided """ # keep a list of allowed zaaktypen zaaktypen = [] prefix = ("" if not self.authorizations_lookup else f"{self.authorizations_lookup}__") # annotate the queryset so we can map a string value to a logical number order_case = VertrouwelijkheidsAanduiding.get_order_expression( f"{prefix}vertrouwelijkheidaanduiding") # build the case/when to map the max_vertrouwelijkheidaanduiding based # on the ``zaaktype`` vertrouwelijkheidaanduiding_whens = [] for authorization in authorizations: # test if this authorization has the scope that's needed if not scope.is_contained_in(authorization.scopes): continue # this zaaktype is allowed zaaktype_path = urlparse(authorization.zaaktype).path zaaktype = get_resource_for_path(zaaktype_path) zaaktypen.append(zaaktype) # extract the order and map it to the database value choice_item = VertrouwelijkheidsAanduiding.get_choice( authorization.max_vertrouwelijkheidaanduiding) vertrouwelijkheidaanduiding_whens.append( When(**{f"{prefix}zaaktype": zaaktype}, then=Value(choice_item.order))) # apply the order annnotation so we can filter later annotations = {f"{prefix}_va_order": order_case} # filtering: # * only allow the white-listed zaaktypen, explicitly # * apply the filtering to limit cases within case-types to the maximal # confidentiality level filters = { f"{prefix}zaaktype__in": zaaktypen, f"{prefix}_va_order__lte": Case(*vertrouwelijkheidaanduiding_whens, output_field=IntegerField()), } # bring it all together now to build the resulting queryset queryset = self.annotate(**annotations).filter(**filters) return queryset
def resolve_io_type(self, url: str): try: return get_resource_for_path(urlparse(url).path) except InformatieObjectType.DoesNotExist: return super().load(url, model=InformatieObjectType)
def m2m_filter(queryset, name, value): object = get_resource_for_path(value) return queryset.filter(**{name: object})
def test_get_resource_for_path_with_trailing_slash(path, exc): with pytest.raises(exc): get_resource_for_path(path)
def filter_for_authorizations( self, scope: Scope, authorizations: models.QuerySet) -> models.QuerySet: """ Filter objects whitelisted by the authorizations. For DRC, authorizations are defined around ``Autorisatie.informatieobjecttype``, with a ``max_vertrouwelijkheidaanduiding`` limiting the confidentiality level of ``informatieobjecten`` (inclusive), and scopes that apply for the ``informatieobjecttype`` at hand. This means that ``informatieobjecten`` are included if, and only if: * the ``informatieobjecttype`` is provided in ``authorizations`` * the scopes for the ``informatieobjecttype`` in each ``authorization`` contain the required``scope`` * the ``informatieobjecttype.vertrouwelijkheidaanduiding`` is less then or equal to the ``authorization.max_vertrouwelijkheidaanduiding`` :param scope: a (possibly complex) scope that must be granted on the authorizations :param authorizations: queryset of :class:`vng_api_common.authorizations.Autorisatie` objects :return: a queryset of filtered results according to the authorizations provided """ # keep a list of allowed informatieobjecttypen informatieobjecttypen = [] # annotate the queryset so we can map a string value to a logical number order_case = VertrouwelijkheidsAanduiding.get_order_expression( "vertrouwelijkheidaanduiding") # build the case/when to map the max_vertrouwelijkheidaanduiding based # on the ``informatieobjecttype`` vertrouwelijkheidaanduiding_whens = [] for authorization in authorizations: # test if this authorization has the scope that's needed if not scope.is_contained_in(authorization.scopes): continue # this informatieobjecttype is allowed informatieobjecttype_path = urlparse( authorization.informatieobjecttype).path informatieobjecttype = get_resource_for_path( informatieobjecttype_path) informatieobjecttypen.append(informatieobjecttype) # extract the order and map it to the database value choice_item = VertrouwelijkheidsAanduiding.get_choice( authorization.max_vertrouwelijkheidaanduiding) vertrouwelijkheidaanduiding_whens.append( When( **{"informatieobjecttype": informatieobjecttype}, then=Value(choice_item.order), )) # apply the order annnotation so we can filter later annotations = {"_va_order": order_case} # filtering: # * only allow the white-listed informatieobjecttypen, explicitly # * apply the filtering to limit cases within case-types to the maximal # confidentiality level filters = { "informatieobjecttype__in": informatieobjecttypen, "_va_order__lte": Case(*vertrouwelijkheidaanduiding_whens, output_field=IntegerField()), } if self.authorizations_lookup: # If the current queryset is not an InformatieObjectQuerySet, first # retrieve the canonical IDs of EnkelvoudigInformatieObjects # for which the user is authorized and then return the objects # related to those EnkelvoudigInformatieObjectCanonicals model = apps.get_model("documenten", "EnkelvoudigInformatieObject") filtered = (model.objects.annotate(**annotations).filter( **filters).values("canonical")) queryset = self.filter(informatieobject__in=filtered) # bring it all together now to build the resulting queryset else: queryset = self.annotate(**annotations).filter(**filters) return queryset