From 6a6942568855e1b74d98d6c4868a024899f4f8a8 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Wed, 31 Mar 2021 23:07:57 +0200 Subject: [PATCH] providers/oauth2: migrate scope mapping to web Signed-off-by: Jens Langhammer --- authentik/admin/urls.py | 19 +---- authentik/admin/views/property_mappings.py | 41 ---------- authentik/core/api/propertymappings.py | 13 +-- authentik/core/models.py | 4 +- authentik/providers/oauth2/models.py | 6 +- .../oauth2/property_mapping_form.html | 14 ---- web/src/api/legacy.ts | 4 - .../PropertyMappingListPage.ts | 49 +++++++++--- .../PropertyMappingScopeForm.ts | 79 +++++++++++++++++++ 9 files changed, 126 insertions(+), 103 deletions(-) delete mode 100644 authentik/admin/views/property_mappings.py delete mode 100644 authentik/providers/oauth2/templates/providers/oauth2/property_mapping_form.html create mode 100644 web/src/pages/property-mappings/PropertyMappingScopeForm.ts diff --git a/authentik/admin/urls.py b/authentik/admin/urls.py index d1b8dc550..f0965c067 100644 --- a/authentik/admin/urls.py +++ b/authentik/admin/urls.py @@ -1,13 +1,7 @@ """authentik URL Configuration""" from django.urls import path -from authentik.admin.views import ( - policies, - property_mappings, - providers, - sources, - stages, -) +from authentik.admin.views import policies, providers, sources, stages from authentik.providers.saml.views.metadata import MetadataImportView urlpatterns = [ @@ -48,15 +42,4 @@ urlpatterns = [ stages.StageUpdateView.as_view(), name="stage-update", ), - # Property Mappings - path( - "property-mappings/create/", - property_mappings.PropertyMappingCreateView.as_view(), - name="property-mapping-create", - ), - path( - "property-mappings//update/", - property_mappings.PropertyMappingUpdateView.as_view(), - name="property-mapping-update", - ), ] diff --git a/authentik/admin/views/property_mappings.py b/authentik/admin/views/property_mappings.py deleted file mode 100644 index 99b3d51e2..000000000 --- a/authentik/admin/views/property_mappings.py +++ /dev/null @@ -1,41 +0,0 @@ -"""authentik PropertyMapping administration""" -from django.contrib.auth.mixins import LoginRequiredMixin -from django.contrib.auth.mixins import ( - PermissionRequiredMixin as DjangoPermissionRequiredMixin, -) -from django.contrib.messages.views import SuccessMessageMixin -from django.utils.translation import gettext as _ -from guardian.mixins import PermissionRequiredMixin - -from authentik.admin.views.utils import InheritanceCreateView, InheritanceUpdateView -from authentik.core.models import PropertyMapping - - -class PropertyMappingCreateView( - SuccessMessageMixin, - LoginRequiredMixin, - DjangoPermissionRequiredMixin, - InheritanceCreateView, -): - """Create new PropertyMapping""" - - model = PropertyMapping - permission_required = "authentik_core.add_propertymapping" - success_url = "/" - template_name = "generic/create.html" - success_message = _("Successfully created Property Mapping") - - -class PropertyMappingUpdateView( - SuccessMessageMixin, - LoginRequiredMixin, - PermissionRequiredMixin, - InheritanceUpdateView, -): - """Update property_mapping""" - - model = PropertyMapping - permission_required = "authentik_core.change_propertymapping" - success_url = "/" - template_name = "generic/update.html" - success_message = _("Successfully updated Property Mapping") diff --git a/authentik/core/api/propertymappings.py b/authentik/core/api/propertymappings.py index b1a32cc28..cd0cc4827 100644 --- a/authentik/core/api/propertymappings.py +++ b/authentik/core/api/propertymappings.py @@ -35,18 +35,12 @@ class PropertyMappingTestResultSerializer(PassiveSerializer): class PropertyMappingSerializer(ModelSerializer, MetaNameSerializer): """PropertyMapping Serializer""" - object_type = SerializerMethodField(method_name="get_type") + object_type = SerializerMethodField() - def get_type(self, obj): + def get_object_type(self, obj: PropertyMapping) -> str: """Get object type so that we know which API Endpoint to use to get the full object""" return obj._meta.object_name.lower().replace("propertymapping", "") - def to_representation(self, instance: PropertyMapping): - # pyright: reportGeneralTypeIssues=false - if instance.__class__ == PropertyMapping: - return super().to_representation(instance) - return instance.serializer(instance=instance).data - class Meta: model = PropertyMapping @@ -89,8 +83,7 @@ class PropertyMappingViewSet( { "name": verbose_name(subclass), "description": subclass.__doc__, - "link": reverse("authentik_admin:property-mapping-create") - + f"?type={subclass.__name__}", + "link": subclass.component, } ) return Response(TypeCreateSerializer(data, many=True).data) diff --git a/authentik/core/models.py b/authentik/core/models.py index 838598898..18bf81d9f 100644 --- a/authentik/core/models.py +++ b/authentik/core/models.py @@ -382,8 +382,8 @@ class PropertyMapping(SerializerModel, ManagedModel): objects = InheritanceManager() @property - def form(self) -> Type[ModelForm]: - """Return Form class used to edit this object""" + def component(self) -> str: + """Return component used to edit this object""" raise NotImplementedError @property diff --git a/authentik/providers/oauth2/models.py b/authentik/providers/oauth2/models.py index 1539dbf2a..d9682841a 100644 --- a/authentik/providers/oauth2/models.py +++ b/authentik/providers/oauth2/models.py @@ -112,10 +112,8 @@ class ScopeMapping(PropertyMapping): ) @property - def form(self) -> Type[ModelForm]: - from authentik.providers.oauth2.forms import ScopeMappingForm - - return ScopeMappingForm + def component(self) -> str: + return "ak-service-connection-docker-form" @property def serializer(self) -> Type[Serializer]: diff --git a/authentik/providers/oauth2/templates/providers/oauth2/property_mapping_form.html b/authentik/providers/oauth2/templates/providers/oauth2/property_mapping_form.html deleted file mode 100644 index 030095abe..000000000 --- a/authentik/providers/oauth2/templates/providers/oauth2/property_mapping_form.html +++ /dev/null @@ -1,14 +0,0 @@ -{% extends "generic/form.html" %} - -{% load i18n %} - -{% block beneath_form %} -
- -
-

- Expression using Python. See here for a list of all variables. -

-
-
-{% endblock %} diff --git a/web/src/api/legacy.ts b/web/src/api/legacy.ts index 7a04128d8..ab601baba 100644 --- a/web/src/api/legacy.ts +++ b/web/src/api/legacy.ts @@ -8,10 +8,6 @@ export class AdminURLManager { return `/administration/providers/${rest}`; } - static propertyMappings(rest: string): string { - return `/administration/property-mappings/${rest}`; - } - static stages(rest: string): string { return `/administration/stages/${rest}`; } diff --git a/web/src/pages/property-mappings/PropertyMappingListPage.ts b/web/src/pages/property-mappings/PropertyMappingListPage.ts index 2ebc9f37d..68da5e081 100644 --- a/web/src/pages/property-mappings/PropertyMappingListPage.ts +++ b/web/src/pages/property-mappings/PropertyMappingListPage.ts @@ -8,13 +8,16 @@ import "../../elements/buttons/Dropdown"; import "../../elements/buttons/SpinnerButton"; import "../../elements/forms/DeleteForm"; import "../../elements/forms/ModalForm"; +import "../../elements/forms/ProxyForm"; import "./PropertyMappingTestForm"; +import "./PropertyMappingScopeForm"; +import "./PropertyMappingLDAPForm"; import { TableColumn } from "../../elements/table/Table"; import { until } from "lit-html/directives/until"; import { PAGE_SIZE } from "../../constants"; import { PropertyMapping, PropertymappingsApi } from "authentik-api"; import { DEFAULT_CONFIG } from "../../api/Config"; -import { AdminURLManager } from "../../api/legacy"; +import { ifDefined } from "lit-html/directives/if-defined"; @customElement("ak-property-mapping-list") export class PropertyMappingListPage extends TablePage { @@ -60,12 +63,28 @@ export class PropertyMappingListPage extends TablePage { html`${item.name}`, html`${item.verboseName}`, html` - - + + + ${gettext("Update")} + + + ${gettext(`Update ${item.verboseName}`)} + + + + + ${gettext("Test")} @@ -105,12 +124,22 @@ export class PropertyMappingListPage extends TablePage { ${until(new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsAllTypes({}).then((types) => { return types.map((type) => { return html`
  • - - -
    -
    +
  • `; }); }), html``)} diff --git a/web/src/pages/property-mappings/PropertyMappingScopeForm.ts b/web/src/pages/property-mappings/PropertyMappingScopeForm.ts new file mode 100644 index 000000000..d2be12078 --- /dev/null +++ b/web/src/pages/property-mappings/PropertyMappingScopeForm.ts @@ -0,0 +1,79 @@ +import { ScopeMapping, PropertymappingsApi } from "authentik-api"; +import { gettext } from "django"; +import { customElement, property } from "lit-element"; +import { html, TemplateResult } from "lit-html"; +import { DEFAULT_CONFIG } from "../../api/Config"; +import { Form } from "../../elements/forms/Form"; +import { ifDefined } from "lit-html/directives/if-defined"; +import "../../elements/forms/HorizontalFormElement"; + +@customElement("ak-property-mapping-scope-form") +export class PropertyMappingScopeForm extends Form { + + set mappingUUID(value: string) { + new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsScopeRead({ + pmUuid: value, + }).then(mapping => { + this.mapping = mapping; + }); + } + + @property({attribute: false}) + mapping?: ScopeMapping; + + getSuccessMessage(): string { + if (this.mapping) { + return gettext("Successfully updated mapping."); + } else { + return gettext("Successfully created mapping."); + } + } + + send = (data: ScopeMapping): Promise => { + if (this.mapping) { + return new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsScopeUpdate({ + pmUuid: this.mapping.pk || "", + data: data + }); + } else { + return new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsScopeCreate({ + data: data + }); + } + }; + + renderForm(): TemplateResult { + return html`
    + + + + + +

    ${gettext("Scope which the client can specify to access these properties.")}

    +
    + + +

    ${gettext("Description shown to the user when consenting. If left empty, the user won't be informed.")}

    +
    + + + +

    + Expression using Python. See here for a list of all variables. +

    +
    +
    `; + } + +}