crypto: add API to generate keypair

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2021-03-29 17:33:27 +02:00
parent 5d37012075
commit a445b03523
2 changed files with 83 additions and 1 deletions

View file

@ -3,14 +3,22 @@ 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.db.models import Model
from django.utils.translation import gettext_lazy as _
from drf_yasg2.utils import swagger_auto_schema
from rest_framework.decorators import action
from rest_framework.fields import CharField, DateTimeField, SerializerMethodField
from rest_framework.fields import (
CharField,
DateTimeField,
IntegerField,
SerializerMethodField,
)
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.serializers import ModelSerializer, Serializer, ValidationError
from rest_framework.viewsets import ModelViewSet
from authentik.api.decorators import permission_required
from authentik.crypto.builder import CertificateBuilder
from authentik.crypto.models import CertificateKeyPair
from authentik.events.models import Event, EventAction
@ -83,12 +91,51 @@ class CertificateDataSerializer(Serializer):
raise NotImplementedError
class CertificateGenerationSerializer(Serializer):
"""Certificate generation parameters"""
common_name = CharField()
subject_alt_name = CharField(
required=False, allow_blank=True, label=_("Subject-alt name")
)
validity_days = IntegerField(initial=365)
def create(self, validated_data: dict) -> Model:
raise NotImplementedError
def update(self, instance: Model, validated_data: dict) -> Model:
raise NotImplementedError
class CertificateKeyPairViewSet(ModelViewSet):
"""CertificateKeyPair Viewset"""
queryset = CertificateKeyPair.objects.all()
serializer_class = CertificateKeyPairSerializer
@permission_required(None, "authentik_crypto.add_certificatekeypair")
@swagger_auto_schema(
request_body=CertificateGenerationSerializer(),
responses={200: CertificateKeyPairSerializer},
)
@action(detail=False, methods=["POST"])
def generate(self, request: Request) -> Response:
"""Generate a new, self-signed certificate-key pair"""
data = CertificateGenerationSerializer(data=request.data)
if not data.is_valid():
return Response(data.errors, status=400)
builder = CertificateBuilder()
builder.common_name = data.validated_data["common_name"]
builder.build(
subject_alt_names=data.validated_data.get("subject_alt_name", "").split(
","
),
validity_days=int(data.validated_data["validity_days"]),
)
instance = builder.save()
serializer = self.get_serializer(instance)
return Response(serializer.data)
@swagger_auto_schema(responses={200: CertificateDataSerializer(many=False)})
@action(detail=True)
# pylint: disable=invalid-name, unused-argument

View file

@ -1826,6 +1826,24 @@ paths:
tags:
- crypto
parameters: []
/crypto/certificatekeypairs/generate/:
post:
operationId: crypto_certificatekeypairs_generate
description: Generate a new, self-signed certificate-key pair
parameters:
- name: data
in: body
required: true
schema:
$ref: '#/definitions/CertificateGeneration'
responses:
'200':
description: CertificateKeyPair Serializer
schema:
$ref: '#/definitions/CertificateKeyPair'
tags:
- crypto
parameters: []
/crypto/certificatekeypairs/{kp_uuid}/:
get:
operationId: crypto_certificatekeypairs_read
@ -11191,6 +11209,23 @@ definitions:
title: Private key available
type: boolean
readOnly: true
CertificateGeneration:
description: Certificate generation parameters
required:
- common_name
- validity_days
type: object
properties:
common_name:
title: Common name
type: string
minLength: 1
subject_alt_name:
title: Subject-alt name
type: string
validity_days:
title: Validity days
type: integer
CertificateData:
description: Get CertificateKeyPair's data
type: object