core: add providers/types endpoint
This commit is contained in:
		| @ -1,10 +1,21 @@ | |||||||
| """Provider API Views""" | """Provider API Views""" | ||||||
|  | from django.shortcuts import reverse | ||||||
|  | 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 ReadOnlyField | from rest_framework.fields import ReadOnlyField | ||||||
| from rest_framework.serializers import ModelSerializer, SerializerMethodField | from rest_framework.request import Request | ||||||
|  | from rest_framework.response import Response | ||||||
|  | from rest_framework.serializers import ( | ||||||
|  |     ModelSerializer, | ||||||
|  |     SerializerMethodField, | ||||||
|  | ) | ||||||
| from rest_framework.viewsets import ModelViewSet | from rest_framework.viewsets import ModelViewSet | ||||||
|  |  | ||||||
| from authentik.core.api.utils import MetaNameSerializer | from authentik.core.api.utils import MetaNameSerializer, TypeCreateSerializer | ||||||
| from authentik.core.models import Provider | from authentik.core.models import Provider | ||||||
|  | from authentik.lib.templatetags.authentik_utils import verbose_name | ||||||
|  | from authentik.lib.utils.reflection import all_subclasses | ||||||
|  |  | ||||||
|  |  | ||||||
| class ProviderSerializer(ModelSerializer, MetaNameSerializer): | class ProviderSerializer(ModelSerializer, MetaNameSerializer): | ||||||
| @ -51,3 +62,27 @@ class ProviderViewSet(ModelViewSet): | |||||||
|  |  | ||||||
|     def get_queryset(self): |     def get_queryset(self): | ||||||
|         return Provider.objects.select_subclasses() |         return Provider.objects.select_subclasses() | ||||||
|  |  | ||||||
|  |     @swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)}) | ||||||
|  |     @action(detail=False) | ||||||
|  |     # pylint: disable=unused-argument | ||||||
|  |     def types(self, request: Request) -> Response: | ||||||
|  |         """Get all creatable provider types""" | ||||||
|  |         data = [] | ||||||
|  |         for subclass in all_subclasses(self.queryset.model): | ||||||
|  |             data.append( | ||||||
|  |                 { | ||||||
|  |                     "name": verbose_name(subclass), | ||||||
|  |                     "description": subclass.__doc__, | ||||||
|  |                     "link": reverse("authentik_admin:provider-create") | ||||||
|  |                     + f"?type={subclass.__name__}", | ||||||
|  |                 } | ||||||
|  |             ) | ||||||
|  |         data.append( | ||||||
|  |             { | ||||||
|  |                 "name": _("SAML Provider from Metadata"), | ||||||
|  |                 "description": _("Create a SAML Provider by importing its Metadata."), | ||||||
|  |                 "link": reverse("authentik_admin:provider-saml-from-metadata"), | ||||||
|  |             } | ||||||
|  |         ) | ||||||
|  |         return Response(TypeCreateSerializer(data, many=True).data) | ||||||
|  | |||||||
| @ -1,5 +1,6 @@ | |||||||
| """API Utilities""" | """API Utilities""" | ||||||
| from django.db.models import Model | from django.db.models import Model | ||||||
|  | from rest_framework.fields import CharField | ||||||
| from rest_framework.serializers import Serializer, SerializerMethodField | from rest_framework.serializers import Serializer, SerializerMethodField | ||||||
|  |  | ||||||
|  |  | ||||||
| @ -22,3 +23,11 @@ class MetaNameSerializer(Serializer): | |||||||
|     def get_verbose_name_plural(self, obj: Model) -> str: |     def get_verbose_name_plural(self, obj: Model) -> str: | ||||||
|         """Return object's plural verbose_name""" |         """Return object's plural verbose_name""" | ||||||
|         return obj._meta.verbose_name_plural |         return obj._meta.verbose_name_plural | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class TypeCreateSerializer(Serializer): | ||||||
|  |     """Types of an object that can be created""" | ||||||
|  |  | ||||||
|  |     name = CharField(read_only=True) | ||||||
|  |     description = CharField(read_only=True) | ||||||
|  |     link = CharField(read_only=True) | ||||||
|  | |||||||
							
								
								
									
										60
									
								
								swagger.yaml
									
									
									
									
									
								
							
							
						
						
									
										60
									
								
								swagger.yaml
									
									
									
									
									
								
							| @ -4312,6 +4312,47 @@ paths: | |||||||
|       tags: |       tags: | ||||||
|         - providers |         - providers | ||||||
|     parameters: [] |     parameters: [] | ||||||
|  |   /providers/all/types/: | ||||||
|  |     get: | ||||||
|  |       operationId: providers_all_types | ||||||
|  |       description: Get all creatable provider types | ||||||
|  |       parameters: | ||||||
|  |         - name: application__isnull | ||||||
|  |           in: query | ||||||
|  |           description: '' | ||||||
|  |           required: false | ||||||
|  |           type: string | ||||||
|  |         - name: ordering | ||||||
|  |           in: query | ||||||
|  |           description: Which field to use when ordering the results. | ||||||
|  |           required: false | ||||||
|  |           type: string | ||||||
|  |         - name: search | ||||||
|  |           in: query | ||||||
|  |           description: A search term. | ||||||
|  |           required: false | ||||||
|  |           type: string | ||||||
|  |         - name: page | ||||||
|  |           in: query | ||||||
|  |           description: A page number within the paginated result set. | ||||||
|  |           required: false | ||||||
|  |           type: integer | ||||||
|  |         - name: page_size | ||||||
|  |           in: query | ||||||
|  |           description: Number of results to return per page. | ||||||
|  |           required: false | ||||||
|  |           type: integer | ||||||
|  |       responses: | ||||||
|  |         '200': | ||||||
|  |           description: '' | ||||||
|  |           schema: | ||||||
|  |             description: '' | ||||||
|  |             type: array | ||||||
|  |             items: | ||||||
|  |               $ref: '#/definitions/TypeCreate' | ||||||
|  |       tags: | ||||||
|  |         - providers | ||||||
|  |     parameters: [] | ||||||
|   /providers/all/{id}/: |   /providers/all/{id}/: | ||||||
|     get: |     get: | ||||||
|       operationId: providers_all_read |       operationId: providers_all_read | ||||||
| @ -9005,6 +9046,25 @@ definitions: | |||||||
|         title: Verbose name plural |         title: Verbose name plural | ||||||
|         type: string |         type: string | ||||||
|         readOnly: true |         readOnly: true | ||||||
|  |   TypeCreate: | ||||||
|  |     description: '' | ||||||
|  |     type: object | ||||||
|  |     properties: | ||||||
|  |       name: | ||||||
|  |         title: Name | ||||||
|  |         type: string | ||||||
|  |         readOnly: true | ||||||
|  |         minLength: 1 | ||||||
|  |       description: | ||||||
|  |         title: Description | ||||||
|  |         type: string | ||||||
|  |         readOnly: true | ||||||
|  |         minLength: 1 | ||||||
|  |       link: | ||||||
|  |         title: Link | ||||||
|  |         type: string | ||||||
|  |         readOnly: true | ||||||
|  |         minLength: 1 | ||||||
|   OAuth2Provider: |   OAuth2Provider: | ||||||
|     description: OAuth2Provider Serializer |     description: OAuth2Provider Serializer | ||||||
|     required: |     required: | ||||||
|  | |||||||
| @ -1,5 +1,11 @@ | |||||||
| import { BaseInheritanceModel, DefaultClient, AKResponse, QueryArguments } from "./Client"; | import { BaseInheritanceModel, DefaultClient, AKResponse, QueryArguments } from "./Client"; | ||||||
|  |  | ||||||
|  | export interface TypeCreate { | ||||||
|  |     name: string; | ||||||
|  |     description: string; | ||||||
|  |     link: string; | ||||||
|  | } | ||||||
|  |  | ||||||
| export class Provider implements BaseInheritanceModel { | export class Provider implements BaseInheritanceModel { | ||||||
|     pk: number; |     pk: number; | ||||||
|     name: string; |     name: string; | ||||||
| @ -24,6 +30,10 @@ export class Provider implements BaseInheritanceModel { | |||||||
|         return DefaultClient.fetch<AKResponse<Provider>>(["providers", "all"], filter); |         return DefaultClient.fetch<AKResponse<Provider>>(["providers", "all"], filter); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     static getTypes(): Promise<TypeCreate[]> { | ||||||
|  |         return DefaultClient.fetch<TypeCreate[]>(["providers", "all", "types"]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     static adminUrl(rest: string): string { |     static adminUrl(rest: string): string { | ||||||
|         return `/administration/providers/${rest}`; |         return `/administration/providers/${rest}`; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -8,6 +8,7 @@ import "../../elements/buttons/ModalButton"; | |||||||
| import "../../elements/buttons/SpinnerButton"; | import "../../elements/buttons/SpinnerButton"; | ||||||
| import "../../elements/buttons/Dropdown"; | import "../../elements/buttons/Dropdown"; | ||||||
| import { TableColumn } from "../../elements/table/Table"; | import { TableColumn } from "../../elements/table/Table"; | ||||||
|  | import { until } from "lit-html/directives/until"; | ||||||
|  |  | ||||||
| @customElement("ak-provider-list") | @customElement("ak-provider-list") | ||||||
| export class ProviderListPage extends TablePage<Provider> { | export class ProviderListPage extends TablePage<Provider> { | ||||||
| @ -81,46 +82,18 @@ export class ProviderListPage extends TablePage<Provider> { | |||||||
|                 <i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i> |                 <i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i> | ||||||
|             </button> |             </button> | ||||||
|             <ul class="pf-c-dropdown__menu" hidden> |             <ul class="pf-c-dropdown__menu" hidden> | ||||||
|                 <li> |                 ${until(Provider.getTypes().then((types) => { | ||||||
|                     <ak-modal-button href="${Provider.adminUrl("/create/?type=OAuth2Provider")}"> |                     return types.map((type) => { | ||||||
|                         <button slot="trigger" class="pf-c-dropdown__menu-item">${gettext("OAuth2/OpenID Provider")}<br> |                         return html`<li> | ||||||
|                             <small> |                             <ak-modal-button href="${type.link}"> | ||||||
|                                 ${gettext("OAuth2 Provider for generic OAuth and OpenID Connect Applications.")} |                                 <button slot="trigger" class="pf-c-dropdown__menu-item">${type.name}<br> | ||||||
|                             </small> |                                     <small>${type.description}</small> | ||||||
|                         </button> |                                 </button> | ||||||
|                         <div slot="modal"></div> |                                 <div slot="modal"></div> | ||||||
|                     </ak-modal-button> |                             </ak-modal-button> | ||||||
|                 </li> |                         </li>`; | ||||||
|                 <li> |                     }) | ||||||
|                     <ak-modal-button href="${Provider.adminUrl("/create/?type=ProxyProvider")}"> |                 }), html`<ak-spinner></ak-spinner>`)} | ||||||
|                         <button slot="trigger" class="pf-c-dropdown__menu-item">${gettext("Proxy Provider")}<br> |  | ||||||
|                             <small> |  | ||||||
|                                 ${gettext("Protect applications that don't support any of the other Protocols by using a Reverse-Proxy.")} |  | ||||||
|                             </small> |  | ||||||
|                         </button> |  | ||||||
|                         <div slot="modal"></div> |  | ||||||
|                     </ak-modal-button> |  | ||||||
|                 </li> |  | ||||||
|                 <li> |  | ||||||
|                     <ak-modal-button href="${Provider.adminUrl("/create/?type=SAMLProvider")}"> |  | ||||||
|                         <button slot="trigger" class="pf-c-dropdown__menu-item">${gettext("SAML Provider")}<br> |  | ||||||
|                             <small> |  | ||||||
|                                 ${gettext("SAML 2.0 Endpoint for applications which support SAML.")} |  | ||||||
|                             </small> |  | ||||||
|                         </button> |  | ||||||
|                         <div slot="modal"></div> |  | ||||||
|                     </ak-modal-button> |  | ||||||
|                 </li> |  | ||||||
|                 <li> |  | ||||||
|                     <ak-modal-button href="${Provider.adminUrl("/create/saml/from-metadata/")}"> |  | ||||||
|                         <button slot="trigger" class="pf-c-dropdown__menu-item">${gettext("SAML Provider from Metadata")}<br> |  | ||||||
|                             <small> |  | ||||||
|                                 ${gettext("Create a SAML Provider by importing its Metadata.")} |  | ||||||
|                             </small> |  | ||||||
|                         </button> |  | ||||||
|                         <div slot="modal"></div> |  | ||||||
|                     </ak-modal-button> |  | ||||||
|                 </li> |  | ||||||
|             </ul> |             </ul> | ||||||
|         </ak-dropdown> |         </ak-dropdown> | ||||||
|         ${super.renderToolbar()}`; |         ${super.renderToolbar()}`; | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Jens Langhammer
					Jens Langhammer