sources/saml: add Metadata API

This commit is contained in:
Jens Langhammer 2021-03-01 10:50:45 +01:00
parent 0478ae3da8
commit d6fd2b0afa
8 changed files with 107 additions and 4 deletions

View File

@ -57,10 +57,10 @@ class SAMLProviderViewSet(ModelViewSet):
@swagger_auto_schema(responses={200: SAMLMetadataSerializer(many=False)}) @swagger_auto_schema(responses={200: SAMLMetadataSerializer(many=False)})
@action(methods=["GET"], detail=True) @action(methods=["GET"], detail=True)
# pylint: disable=invalid-name # pylint: disable=invalid-name, unused-argument
def metadata(self, request: Request, pk: int) -> Response: def metadata(self, request: Request, pk: int) -> Response:
"""Return metadata as XML string""" """Return metadata as XML string"""
provider = get_object_or_404(SAMLProvider, pk=pk) provider = self.get_object()
try: try:
metadata = DescriptorDownloadView.get_metadata(request, provider) metadata = DescriptorDownloadView.get_metadata(request, provider)
return Response({"metadata": metadata}) return Response({"metadata": metadata})

View File

@ -1,8 +1,14 @@
"""SAMLSource API Views""" """SAMLSource API Views"""
from drf_yasg2.utils import swagger_auto_schema
from rest_framework.decorators import action
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from authentik.core.api.sources import SourceSerializer from authentik.core.api.sources import SourceSerializer
from authentik.providers.saml.api import SAMLMetadataSerializer
from authentik.sources.saml.models import SAMLSource from authentik.sources.saml.models import SAMLSource
from authentik.sources.saml.processors.metadata import MetadataProcessor
class SAMLSourceSerializer(SourceSerializer): class SAMLSourceSerializer(SourceSerializer):
@ -31,3 +37,12 @@ class SAMLSourceViewSet(ModelViewSet):
queryset = SAMLSource.objects.all() queryset = SAMLSource.objects.all()
serializer_class = SAMLSourceSerializer serializer_class = SAMLSourceSerializer
lookup_field = "slug" lookup_field = "slug"
@swagger_auto_schema(responses={200: SAMLMetadataSerializer(many=False)})
@action(methods=["GET"], detail=True)
# pylint: disable=unused-argument
def metadata(self, request: Request, slug: str) -> Response:
"""Return metadata as XML string"""
source = self.get_object()
metadata = MetadataProcessor(source, request).build_entity_descriptor()
return Response({"metadata": metadata})

View File

@ -1,6 +1,7 @@
"""authentik SAML SP Forms""" """authentik SAML SP Forms"""
from django import forms from django import forms
from django.utils.translation import gettext_lazy as _
from authentik.crypto.models import CertificateKeyPair from authentik.crypto.models import CertificateKeyPair
from authentik.flows.models import Flow, FlowDesignation from authentik.flows.models import Flow, FlowDesignation
@ -51,3 +52,7 @@ class SAMLSourceForm(forms.ModelForm):
"slo_url": forms.TextInput(), "slo_url": forms.TextInput(),
"temporary_user_delete_after": forms.TextInput(), "temporary_user_delete_after": forms.TextInput(),
} }
labels = {
"name_id_policy": _("Name ID Policy"),
"allow_idp_initiated": _("Allow IDP-initiated logins"),
}

View File

@ -0,0 +1,40 @@
# Generated by Django 3.1.7 on 2021-03-01 09:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_sources_saml", "0008_auto_20201112_2016"),
]
operations = [
migrations.AlterField(
model_name="samlsource",
name="name_id_policy",
field=models.TextField(
choices=[
("urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", "Email"),
(
"urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
"Persistent",
),
(
"urn:oasis:names:tc:SAML:2.0:nameid-format:X509SubjectName",
"X509",
),
(
"urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName",
"Windows",
),
(
"urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
"Transient",
),
],
default="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
help_text="NameID Policy sent to the IdP. Can be unset, in which case no Policy is sent.",
),
),
]

View File

@ -79,7 +79,7 @@ class SAMLSource(Source):
) )
name_id_policy = models.TextField( name_id_policy = models.TextField(
choices=SAMLNameIDPolicy.choices, choices=SAMLNameIDPolicy.choices,
default=SAMLNameIDPolicy.TRANSIENT, default=SAMLNameIDPolicy.PERSISTENT,
help_text=_( help_text=_(
"NameID Policy sent to the IdP. Can be unset, in which case no Policy is sent." "NameID Policy sent to the IdP. Can be unset, in which case no Policy is sent."
), ),

View File

@ -90,4 +90,4 @@ class MetadataProcessor:
self.http_request self.http_request
) )
return tostring(entity_descriptor).decode() return tostring(entity_descriptor, pretty_print=True).decode()

View File

@ -0,0 +1,23 @@
# Generated by Django 3.1.7 on 2021-03-01 09:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
(
"authentik_stages_authenticator_validate",
"0003_authenticatorvalidatestage_device_classes",
),
]
operations = [
migrations.AlterField(
model_name="authenticatorvalidatestage",
name="not_configured_action",
field=models.TextField(
choices=[("skip", "Skip"), ("deny", "Deny")], default="skip"
),
),
]

View File

@ -5571,6 +5571,26 @@ paths:
type: string type: string
format: slug format: slug
pattern: ^[-a-zA-Z0-9_]+$ pattern: ^[-a-zA-Z0-9_]+$
/sources/saml/{slug}/metadata/:
get:
operationId: sources_saml_metadata
description: Return metadata as XML string
parameters: []
responses:
'200':
description: SAML Provider Metadata serializer
schema:
$ref: '#/definitions/SAMLMetadata'
tags:
- sources
parameters:
- name: slug
in: path
description: Internal source name, used in URLs.
required: true
type: string
format: slug
pattern: ^[-a-zA-Z0-9_]+$
/stages/all/: /stages/all/:
get: get:
operationId: stages_all_list operationId: stages_all_list