core: add API to test property mapping

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2021-03-30 17:32:57 +02:00
parent 6916c59483
commit f206baf3f0
3 changed files with 130 additions and 1 deletions

View File

@ -1,17 +1,34 @@
"""PropertyMapping API Views""" """PropertyMapping API Views"""
from json import dumps
from django.urls import reverse from django.urls import reverse
from drf_yasg.utils import swagger_auto_schema from drf_yasg.utils import swagger_auto_schema
from guardian.shortcuts import get_objects_for_user
from rest_framework import mixins from rest_framework import mixins
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.exceptions import PermissionDenied
from rest_framework.fields import CharField
from rest_framework.request import Request from rest_framework.request import Request
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.serializers import ModelSerializer, SerializerMethodField from rest_framework.serializers import ModelSerializer, SerializerMethodField
from rest_framework.viewsets import GenericViewSet from rest_framework.viewsets import GenericViewSet
from authentik.core.api.utils import MetaNameSerializer, TypeCreateSerializer from authentik.api.decorators import permission_required
from authentik.core.api.utils import (
MetaNameSerializer,
PassiveSerializer,
TypeCreateSerializer,
)
from authentik.core.models import PropertyMapping from authentik.core.models import PropertyMapping
from authentik.lib.templatetags.authentik_utils import verbose_name from authentik.lib.templatetags.authentik_utils import verbose_name
from authentik.lib.utils.reflection import all_subclasses from authentik.lib.utils.reflection import all_subclasses
from authentik.policies.api.exec import PolicyTestSerializer
class PropertyMappingTestResultSerializer(PassiveSerializer):
"""Result of a Property-mapping test"""
result = CharField(read_only=True)
class PropertyMappingSerializer(ModelSerializer, MetaNameSerializer): class PropertyMappingSerializer(ModelSerializer, MetaNameSerializer):
@ -76,3 +93,37 @@ class PropertyMappingViewSet(
} }
) )
return Response(TypeCreateSerializer(data, many=True).data) return Response(TypeCreateSerializer(data, many=True).data)
@permission_required("authentik_core.view_propertymapping")
@swagger_auto_schema(
request_body=PolicyTestSerializer(),
responses={200: PropertyMappingTestResultSerializer},
)
@action(detail=True, methods=["POST"])
# pylint: disable=unused-argument, invalid-name
def test(self, request: Request, pk: str) -> Response:
"""Test Property Mapping"""
mapping: PropertyMapping = self.get_object()
test_params = PolicyTestSerializer(data=request.data)
if not test_params.is_valid():
return Response(test_params.errors, status=400)
# User permission check, only allow mapping testing for users that are readable
users = get_objects_for_user(request.user, "authentik_core.view_user").filter(
pk=test_params.validated_data["user"].pk
)
if not users.exists():
raise PermissionDenied()
response_data = {}
try:
result = mapping.evaluate(
users.first(),
self.request,
**test_params.validated_data.get("context", {}),
)
response_data["result"] = dumps(result)
except Exception as exc: # pylint: disable=broad-except
response_data["result"] = str(exc)
response = PropertyMappingTestResultSerializer(response_data)
return Response(response.data)

View File

@ -0,0 +1,33 @@
"""Test property mappings API"""
from json import dumps
from django.urls import reverse
from rest_framework.test import APITestCase
from authentik.core.models import PropertyMapping, User
class TestPropertyMappingAPI(APITestCase):
"""Test property mappings API"""
def setUp(self) -> None:
super().setUp()
self.mapping = PropertyMapping.objects.create(
name="dummy", expression="""return {'foo': 'bar'}"""
)
self.user = User.objects.get(username="akadmin")
self.client.force_login(self.user)
def test_test_call(self):
"""Test Policy's test endpoint"""
response = self.client.post(
reverse(
"authentik_api:propertymapping-test", kwargs={"pk": self.mapping.pk}
),
data={
"user": self.user.pk,
},
)
self.assertJSONEqual(
response.content.decode(), {"result": dumps({"foo": "bar"})}
)

View File

@ -7984,6 +7984,43 @@ paths:
required: true required: true
type: string type: string
format: uuid format: uuid
/propertymappings/all/{pm_uuid}/test/:
post:
operationId: propertymappings_all_test
description: Test Property Mapping
parameters:
- name: data
in: body
required: true
schema:
$ref: '#/definitions/PolicyTest'
responses:
'200':
description: ''
schema:
$ref: '#/definitions/PropertyMappingTestResult'
'400':
description: Invalid input.
schema:
$ref: '#/definitions/ValidationError'
'403':
description: Authentication credentials were invalid, absent or insufficient.
schema:
$ref: '#/definitions/GenericError'
'404':
description: Object does not exist or caller has insufficient permissions
to access it.
schema:
$ref: '#/definitions/APIException'
tags:
- propertymappings
parameters:
- name: pm_uuid
in: path
description: A UUID string identifying this Property Mapping.
required: true
type: string
format: uuid
/propertymappings/ldap/: /propertymappings/ldap/:
get: get:
operationId: propertymappings_ldap_list operationId: propertymappings_ldap_list
@ -16843,6 +16880,14 @@ definitions:
title: Verbose name plural title: Verbose name plural
type: string type: string
readOnly: true readOnly: true
PropertyMappingTestResult:
type: object
properties:
result:
title: Result
type: string
readOnly: true
minLength: 1
LDAPPropertyMapping: LDAPPropertyMapping:
required: required:
- name - name