Skip to content

Commit 8938fa5

Browse files
RynoxxBeryJu
andauthored
providers/saml: fix handle Accept: application/xml for SAML Metadata endpoint (#12483) (#12518)
* providers/saml: fix handle Accept: application/xml for SAML Metadata endpoint (#12483) * slight formatting changes Signed-off-by: Jens Langhammer <[email protected]> --------- Signed-off-by: Jens Langhammer <[email protected]> Co-authored-by: Jens Langhammer <[email protected]>
1 parent 4c8f610 commit 8938fa5

File tree

3 files changed

+50
-3
lines changed

3 files changed

+50
-3
lines changed

authentik/providers/saml/api/providers.py

+26-3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from rest_framework.fields import CharField, FileField, SerializerMethodField
1717
from rest_framework.parsers import MultiPartParser
1818
from rest_framework.permissions import AllowAny
19+
from rest_framework.renderers import BaseRenderer, JSONRenderer
1920
from rest_framework.request import Request
2021
from rest_framework.response import Response
2122
from rest_framework.serializers import PrimaryKeyRelatedField, ValidationError
@@ -38,6 +39,16 @@
3839
LOGGER = get_logger()
3940

4041

42+
class RawXMLDataRenderer(BaseRenderer):
43+
"""Renderer to allow application/xml as value for 'Accept' in the metadata endpoint."""
44+
45+
media_type = "application/xml"
46+
format = "xml"
47+
48+
def render(self, data, accepted_media_type=None, renderer_context=None):
49+
return data
50+
51+
4152
class SAMLProviderSerializer(ProviderSerializer):
4253
"""SAMLProvider Serializer"""
4354

@@ -238,9 +249,21 @@ class SAMLProviderViewSet(UsedByMixin, ModelViewSet):
238249
],
239250
description="Optionally force the metadata to only include one binding.",
240251
),
252+
# Explicitly excluded, because otherwise spectacular automatically
253+
# add it when using multiple renderer_classes
254+
OpenApiParameter(
255+
name="format",
256+
exclude=True,
257+
required=False,
258+
),
241259
],
242260
)
243-
@action(methods=["GET"], detail=True, permission_classes=[AllowAny])
261+
@action(
262+
methods=["GET"],
263+
detail=True,
264+
permission_classes=[AllowAny],
265+
renderer_classes=[JSONRenderer, RawXMLDataRenderer],
266+
)
244267
def metadata(self, request: Request, pk: int) -> Response:
245268
"""Return metadata as XML string"""
246269
# We don't use self.get_object() on purpose as this view is un-authenticated
@@ -258,9 +281,9 @@ def metadata(self, request: Request, pk: int) -> Response:
258281
f'attachment; filename="{provider.name}_authentik_meta.xml"'
259282
)
260283
return response
261-
return Response({"metadata": metadata})
284+
return Response({"metadata": metadata}, content_type="application/json")
262285
except Provider.application.RelatedObjectDoesNotExist:
263-
return Response({"metadata": ""})
286+
return Response({"metadata": ""}, content_type="application/json")
264287

265288
@permission_required(
266289
None,

authentik/providers/saml/tests/test_api.py

+21
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,22 @@ def test_metadata_download(self):
104104
)
105105
self.assertEqual(200, response.status_code)
106106
self.assertIn("Content-Disposition", response)
107+
# Test download with Accept: application/xml
108+
response = self.client.get(
109+
reverse("authentik_api:samlprovider-metadata", kwargs={"pk": provider.pk})
110+
+ "?download",
111+
HTTP_ACCEPT="application/xml",
112+
)
113+
self.assertEqual(200, response.status_code)
114+
self.assertIn("Content-Disposition", response)
115+
116+
response = self.client.get(
117+
reverse("authentik_api:samlprovider-metadata", kwargs={"pk": provider.pk})
118+
+ "?download",
119+
HTTP_ACCEPT="application/xml;charset=UTF-8",
120+
)
121+
self.assertEqual(200, response.status_code)
122+
self.assertIn("Content-Disposition", response)
107123

108124
def test_metadata_invalid(self):
109125
"""Test metadata export (invalid)"""
@@ -121,6 +137,11 @@ def test_metadata_invalid(self):
121137
reverse("authentik_api:samlprovider-metadata", kwargs={"pk": "abc"}),
122138
)
123139
self.assertEqual(404, response.status_code)
140+
response = self.client.get(
141+
reverse("authentik_api:samlprovider-metadata", kwargs={"pk": provider.pk}),
142+
HTTP_ACCEPT="application/invalid-mime-type",
143+
)
144+
self.assertEqual(406, response.status_code)
124145

125146
def test_import_success(self):
126147
"""Test metadata import (success case)"""

schema.yml

+3
Original file line numberDiff line numberDiff line change
@@ -22090,6 +22090,9 @@ paths:
2209022090
application/json:
2209122091
schema:
2209222092
$ref: '#/components/schemas/SAMLMetadata'
22093+
application/xml:
22094+
schema:
22095+
$ref: '#/components/schemas/SAMLMetadata'
2209322096
description: ''
2209422097
'404':
2209522098
description: Provider has no application assigned

0 commit comments

Comments
 (0)