crypto: add ?download flag
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> #861
This commit is contained in:
parent
a6c6f22221
commit
24f2932777
|
@ -3,7 +3,9 @@ import django_filters
|
|||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives.serialization import load_pem_private_key
|
||||
from cryptography.x509 import load_pem_x509_certificate
|
||||
from django.http.response import HttpResponse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import (
|
||||
|
@ -145,7 +147,16 @@ class CertificateKeyPairViewSet(ModelViewSet):
|
|||
serializer = self.get_serializer(instance)
|
||||
return Response(serializer.data)
|
||||
|
||||
@swagger_auto_schema(responses={200: CertificateDataSerializer(many=False)})
|
||||
@swagger_auto_schema(
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
name="download",
|
||||
in_=openapi.IN_QUERY,
|
||||
type=openapi.TYPE_BOOLEAN,
|
||||
)
|
||||
],
|
||||
responses={200: CertificateDataSerializer(many=False)},
|
||||
)
|
||||
@action(detail=True, pagination_class=None, filter_backends=[])
|
||||
# pylint: disable=invalid-name, unused-argument
|
||||
def view_certificate(self, request: Request, pk: str) -> Response:
|
||||
|
@ -156,11 +167,29 @@ class CertificateKeyPairViewSet(ModelViewSet):
|
|||
secret=certificate,
|
||||
type="certificate",
|
||||
).from_http(request)
|
||||
if "download" in request._request.GET:
|
||||
# Mime type from https://pki-tutorial.readthedocs.io/en/latest/mime.html
|
||||
response = HttpResponse(
|
||||
certificate.certificate_data, content_type="application/x-pem-file"
|
||||
)
|
||||
response[
|
||||
"Content-Disposition"
|
||||
] = f'attachment; filename="{certificate.name}_certificate.pem"'
|
||||
return response
|
||||
return Response(
|
||||
CertificateDataSerializer({"data": certificate.certificate_data}).data
|
||||
)
|
||||
|
||||
@swagger_auto_schema(responses={200: CertificateDataSerializer(many=False)})
|
||||
@swagger_auto_schema(
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
name="download",
|
||||
in_=openapi.IN_QUERY,
|
||||
type=openapi.TYPE_BOOLEAN,
|
||||
)
|
||||
],
|
||||
responses={200: CertificateDataSerializer(many=False)},
|
||||
)
|
||||
@action(detail=True, pagination_class=None, filter_backends=[])
|
||||
# pylint: disable=invalid-name, unused-argument
|
||||
def view_private_key(self, request: Request, pk: str) -> Response:
|
||||
|
@ -171,4 +200,13 @@ class CertificateKeyPairViewSet(ModelViewSet):
|
|||
secret=certificate,
|
||||
type="private_key",
|
||||
).from_http(request)
|
||||
if "download" in request._request.GET:
|
||||
# Mime type from https://pki-tutorial.readthedocs.io/en/latest/mime.html
|
||||
response = HttpResponse(
|
||||
certificate.key_data, content_type="application/x-pem-file"
|
||||
)
|
||||
response[
|
||||
"Content-Disposition"
|
||||
] = f'attachment; filename="{certificate.name}_private_key.pem"'
|
||||
return response
|
||||
return Response(CertificateDataSerializer({"data": certificate.key_data}).data)
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
import datetime
|
||||
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.crypto.api import CertificateKeyPairSerializer
|
||||
from authentik.crypto.builder import CertificateBuilder
|
||||
from authentik.crypto.models import CertificateKeyPair
|
||||
|
@ -47,3 +49,45 @@ class TestCrypto(TestCase):
|
|||
now = datetime.datetime.today()
|
||||
self.assertEqual(instance.name, "test-cert")
|
||||
self.assertEqual((instance.certificate.not_valid_after - now).days, 2)
|
||||
|
||||
def test_certificate_download(self):
|
||||
"""Test certificate export (download)"""
|
||||
self.client.force_login(User.objects.get(username="akadmin"))
|
||||
keypair = CertificateKeyPair.objects.first()
|
||||
response = self.client.get(
|
||||
reverse(
|
||||
"authentik_api:certificatekeypair-view-certificate",
|
||||
kwargs={"pk": keypair.pk},
|
||||
)
|
||||
)
|
||||
self.assertEqual(200, response.status_code)
|
||||
response = self.client.get(
|
||||
reverse(
|
||||
"authentik_api:certificatekeypair-view-certificate",
|
||||
kwargs={"pk": keypair.pk},
|
||||
)
|
||||
+ "?download",
|
||||
)
|
||||
self.assertEqual(200, response.status_code)
|
||||
self.assertIn("Content-Disposition", response)
|
||||
|
||||
def test_private_key_download(self):
|
||||
"""Test private_key export (download)"""
|
||||
self.client.force_login(User.objects.get(username="akadmin"))
|
||||
keypair = CertificateKeyPair.objects.first()
|
||||
response = self.client.get(
|
||||
reverse(
|
||||
"authentik_api:certificatekeypair-view-private-key",
|
||||
kwargs={"pk": keypair.pk},
|
||||
)
|
||||
)
|
||||
self.assertEqual(200, response.status_code)
|
||||
response = self.client.get(
|
||||
reverse(
|
||||
"authentik_api:certificatekeypair-view-private-key",
|
||||
kwargs={"pk": keypair.pk},
|
||||
)
|
||||
+ "?download",
|
||||
)
|
||||
self.assertEqual(200, response.status_code)
|
||||
self.assertIn("Content-Disposition", response)
|
||||
|
|
|
@ -5,6 +5,7 @@ from defusedxml.ElementTree import fromstring
|
|||
from django.http.response import HttpResponse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import CharField, FileField, ReadOnlyField
|
||||
|
@ -83,7 +84,14 @@ class SAMLProviderViewSet(ModelViewSet):
|
|||
responses={
|
||||
200: SAMLMetadataSerializer(many=False),
|
||||
404: "Provider has no application assigned",
|
||||
}
|
||||
},
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
name="download",
|
||||
in_=openapi.IN_QUERY,
|
||||
type=openapi.TYPE_BOOLEAN,
|
||||
)
|
||||
],
|
||||
)
|
||||
@action(methods=["GET"], detail=True, permission_classes=[AllowAny])
|
||||
# pylint: disable=invalid-name, unused-argument
|
||||
|
|
15
swagger.yaml
15
swagger.yaml
|
@ -2527,7 +2527,10 @@ paths:
|
|||
get:
|
||||
operationId: crypto_certificatekeypairs_view_certificate
|
||||
description: Return certificate-key pairs certificate and log access
|
||||
parameters: []
|
||||
parameters:
|
||||
- name: download
|
||||
in: query
|
||||
type: boolean
|
||||
responses:
|
||||
'200':
|
||||
description: ''
|
||||
|
@ -2555,7 +2558,10 @@ paths:
|
|||
get:
|
||||
operationId: crypto_certificatekeypairs_view_private_key
|
||||
description: Return certificate-key pairs private key and log access
|
||||
parameters: []
|
||||
parameters:
|
||||
- name: download
|
||||
in: query
|
||||
type: boolean
|
||||
responses:
|
||||
'200':
|
||||
description: ''
|
||||
|
@ -9696,7 +9702,10 @@ paths:
|
|||
get:
|
||||
operationId: providers_saml_metadata
|
||||
description: Return metadata as XML string
|
||||
parameters: []
|
||||
parameters:
|
||||
- name: download
|
||||
in: query
|
||||
type: boolean
|
||||
responses:
|
||||
'200':
|
||||
description: ''
|
||||
|
|
Reference in New Issue