sources/oauth: improve UI with prefilled urls (when customizable) and hiding provider type
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
		| @ -74,6 +74,8 @@ class SourceViewSet( | ||||
|         for subclass in all_subclasses(self.queryset.model): | ||||
|             subclass: Source | ||||
|             component = "" | ||||
|             if len(subclass.__subclasses__()) > 0: | ||||
|                 continue | ||||
|             if subclass._meta.abstract: | ||||
|                 component = subclass.__bases__[0]().component | ||||
|             else: | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| """OAuth Source Serializer""" | ||||
| from django.urls.base import reverse_lazy | ||||
| from drf_spectacular.utils import extend_schema, extend_schema_field | ||||
| from drf_spectacular.types import OpenApiTypes | ||||
| from drf_spectacular.utils import OpenApiParameter, extend_schema, extend_schema_field | ||||
| from rest_framework.decorators import action | ||||
| from rest_framework.fields import BooleanField, CharField, SerializerMethodField | ||||
| from rest_framework.request import Request | ||||
| @ -12,7 +13,7 @@ from authentik.core.api.sources import SourceSerializer | ||||
| from authentik.core.api.used_by import UsedByMixin | ||||
| from authentik.core.api.utils import PassiveSerializer | ||||
| from authentik.sources.oauth.models import OAuthSource | ||||
| from authentik.sources.oauth.types.manager import MANAGER | ||||
| from authentik.sources.oauth.types.manager import MANAGER, SourceType | ||||
|  | ||||
|  | ||||
| class SourceTypeSerializer(PassiveSerializer): | ||||
| @ -100,11 +101,26 @@ class OAuthSourceViewSet(UsedByMixin, ModelViewSet): | ||||
|     ] | ||||
|     ordering = ["name"] | ||||
|  | ||||
|     @extend_schema(responses={200: SourceTypeSerializer(many=True)}) | ||||
|     @extend_schema( | ||||
|         responses={200: SourceTypeSerializer(many=True)}, | ||||
|         parameters=[ | ||||
|             OpenApiParameter( | ||||
|                 name="name", | ||||
|                 location=OpenApiParameter.QUERY, | ||||
|                 type=OpenApiTypes.STR, | ||||
|             ) | ||||
|         ], | ||||
|     ) | ||||
|     @action(detail=False, pagination_class=None, filter_backends=[]) | ||||
|     def source_types(self, request: Request) -> Response: | ||||
|         """Get all creatable source types""" | ||||
|         """Get all creatable source types. If ?name is set, only returns the type for <name>. | ||||
|         If <name> isn't found, returns the default type.""" | ||||
|         data = [] | ||||
|         if "name" in request.query_params: | ||||
|             source_type = MANAGER.find_type(request.query_params.get("name")) | ||||
|             if source_type.__class__ != SourceType: | ||||
|                 data.append(SourceTypeSerializer(source_type).data) | ||||
|         else: | ||||
|             for source_type in MANAGER.get(): | ||||
|                 data.append(SourceTypeSerializer(source_type).data) | ||||
|         return Response(data) | ||||
|  | ||||
| @ -0,0 +1,33 @@ | ||||
| # Generated by Django 3.2.5 on 2021-08-21 13:41 | ||||
| from django.apps.registry import Apps | ||||
| from django.db import migrations | ||||
| from django.db.backends.base.schema import BaseDatabaseSchemaEditor | ||||
|  | ||||
|  | ||||
| def update_provider_types(apps: Apps, schema_editor: BaseDatabaseSchemaEditor): | ||||
|     OAuthSource = apps.get_model("authentik_sources_oauth", "oauthsource") | ||||
|  | ||||
|     db_alias = schema_editor.connection.alias | ||||
|  | ||||
|     for source in OAuthSource.objects.using(db_alias).all(): | ||||
|         changed = False | ||||
|         if source.provider_type == "azure-ad": | ||||
|             source.provider_type = "azuread" | ||||
|             changed = True | ||||
|         if source.provider_type == "openid-connect": | ||||
|             source.provider_type = "openidconnect" | ||||
|             changed = True | ||||
|  | ||||
|         if changed: | ||||
|             source.save() | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
|  | ||||
|     dependencies = [ | ||||
|         ("authentik_sources_oauth", "0004_auto_20210417_1900"), | ||||
|     ] | ||||
|  | ||||
|     operations = [ | ||||
|         migrations.RunPython(update_provider_types), | ||||
|     ] | ||||
| @ -75,7 +75,7 @@ class AzureADType(SourceType): | ||||
|     callback_view = AzureADOAuthCallback | ||||
|     redirect_view = AzureADOAuthRedirect | ||||
|     name = "Azure AD" | ||||
|     slug = "azure-ad" | ||||
|     slug = "azuread" | ||||
|  | ||||
|     urls_customizable = True | ||||
|  | ||||
|  | ||||
| @ -40,6 +40,6 @@ class OpenIDConnectType(SourceType): | ||||
|     callback_view = OpenIDConnectOAuth2Callback | ||||
|     redirect_view = OpenIDConnectOAuthRedirect | ||||
|     name = "OpenID Connect" | ||||
|     slug = "openid-connect" | ||||
|     slug = "openidconnect" | ||||
|  | ||||
|     urls_customizable = True | ||||
|  | ||||
| @ -13178,7 +13178,14 @@ paths: | ||||
|   /api/v2beta/sources/oauth/source_types/: | ||||
|     get: | ||||
|       operationId: sources_oauth_source_types_list | ||||
|       description: Get all creatable source types | ||||
|       description: |- | ||||
|         Get all creatable source types. If ?name is set, only returns the type for <name>. | ||||
|         If <name> isn't found, returns the default type. | ||||
|       parameters: | ||||
|       - in: query | ||||
|         name: name | ||||
|         schema: | ||||
|           type: string | ||||
|       tags: | ||||
|       - sources | ||||
|       security: | ||||
|  | ||||
| @ -5,6 +5,7 @@ import { | ||||
|     UserMatchingModeEnum, | ||||
|     OAuthSourceRequest, | ||||
|     FlowsInstancesListDesignationEnum, | ||||
|     SourceType, | ||||
| } from "authentik-api"; | ||||
| import { t } from "@lingui/macro"; | ||||
| import { customElement, property } from "lit-element"; | ||||
| @ -25,19 +26,28 @@ export class OAuthSourceForm extends ModelForm<OAuthSource, string> { | ||||
|                 slug: pk, | ||||
|             }) | ||||
|             .then((source) => { | ||||
|                 this.showUrlOptions = first(source.type?.urlsCustomizable, false); | ||||
|                 this.providerType = source.type; | ||||
|                 return source; | ||||
|             }); | ||||
|     } | ||||
|  | ||||
|     _modelName?: string; | ||||
|  | ||||
|     @property() | ||||
|     modelName?: string; | ||||
|     set modelName(v: string | undefined) { | ||||
|         this._modelName = v; | ||||
|         new SourcesApi(DEFAULT_CONFIG).sourcesOauthSourceTypesList({ | ||||
|             name: v?.replace("oauthsource", ""), | ||||
|         }).then((type) => { | ||||
|             this.providerType = type[0]; | ||||
|         }); | ||||
|     } | ||||
|     get modelName(): string|undefined { | ||||
|         return this._modelName; | ||||
|     } | ||||
|  | ||||
|     @property({ type: Boolean }) | ||||
|     showUrlOptions = false; | ||||
|  | ||||
|     @property({ type: Boolean }) | ||||
|     showRequestTokenURL = false; | ||||
|     @property({ attribute: false }) | ||||
|     providerType?: SourceType; | ||||
|  | ||||
|     getSuccessMessage(): string { | ||||
|         if (this.instance) { | ||||
| @ -61,7 +71,7 @@ export class OAuthSourceForm extends ModelForm<OAuthSource, string> { | ||||
|     }; | ||||
|  | ||||
|     renderUrlOptions(): TemplateResult { | ||||
|         if (!this.showUrlOptions) { | ||||
|         if (!this.providerType?.urlsCustomizable) { | ||||
|             return html``; | ||||
|         } | ||||
|         return html` <ak-form-group> | ||||
| @ -74,7 +84,7 @@ export class OAuthSourceForm extends ModelForm<OAuthSource, string> { | ||||
|                 > | ||||
|                     <input | ||||
|                         type="text" | ||||
|                         value="${first(this.instance?.authorizationUrl, "")}" | ||||
|                         value="${first(this.instance?.authorizationUrl, this.providerType.authorizationUrl)}" | ||||
|                         class="pf-c-form-control" | ||||
|                         required | ||||
|                     /> | ||||
| @ -89,7 +99,7 @@ export class OAuthSourceForm extends ModelForm<OAuthSource, string> { | ||||
|                 > | ||||
|                     <input | ||||
|                         type="text" | ||||
|                         value="${first(this.instance?.accessTokenUrl, "")}" | ||||
|                         value="${first(this.instance?.accessTokenUrl, this.providerType.accessTokenUrl)}" | ||||
|                         class="pf-c-form-control" | ||||
|                         required | ||||
|                     /> | ||||
| @ -104,7 +114,7 @@ export class OAuthSourceForm extends ModelForm<OAuthSource, string> { | ||||
|                 > | ||||
|                     <input | ||||
|                         type="text" | ||||
|                         value="${first(this.instance?.profileUrl, "")}" | ||||
|                         value="${first(this.instance?.profileUrl, this.providerType.profileUrl)}" | ||||
|                         class="pf-c-form-control" | ||||
|                         required | ||||
|                     /> | ||||
| @ -112,7 +122,7 @@ export class OAuthSourceForm extends ModelForm<OAuthSource, string> { | ||||
|                         ${t`URL used by authentik to get user information.`} | ||||
|                     </p> | ||||
|                 </ak-form-element-horizontal> | ||||
|                 ${this.showRequestTokenURL | ||||
|                 ${this.providerType.requestTokenUrl | ||||
|                     ? html`<ak-form-element-horizontal | ||||
|                           label=${t`Request token URL`} | ||||
|                           name="requestTokenUrl" | ||||
| @ -226,54 +236,6 @@ export class OAuthSourceForm extends ModelForm<OAuthSource, string> { | ||||
|                     > | ||||
|                         <input type="text" value="" class="pf-c-form-control" required /> | ||||
|                     </ak-form-element-horizontal> | ||||
|                     <ak-form-element-horizontal label=${t`Provider type`} name="providerType"> | ||||
|                         <select | ||||
|                             class="pf-c-form-control" | ||||
|                             @change=${(ev: Event) => { | ||||
|                                 const el = ev.target as HTMLSelectElement; | ||||
|                                 const selected = el.selectedOptions[0]; | ||||
|                                 this.showUrlOptions = "data-urls-custom" in selected.attributes; | ||||
|                                 this.showRequestTokenURL = | ||||
|                                     "data-request-token" in selected.attributes; | ||||
|                                 if (!this.instance) { | ||||
|                                     this.instance = {} as OAuthSource; | ||||
|                                 } | ||||
|                                 this.instance.providerType = selected.value; | ||||
|                             }} | ||||
|                         > | ||||
|                             ${until( | ||||
|                                 new SourcesApi(DEFAULT_CONFIG) | ||||
|                                     .sourcesOauthSourceTypesList() | ||||
|                                     .then((types) => { | ||||
|                                         return types.map((type) => { | ||||
|                                             let selected = | ||||
|                                                 this.instance?.providerType === type.slug; | ||||
|                                             const modelSlug = this.modelName | ||||
|                                                 ?.replace("oauthsource", "") | ||||
|                                                 .replace("-", ""); | ||||
|                                             const typeSlug = type.slug.replace("-", ""); | ||||
|                                             if (!this.instance?.pk) { | ||||
|                                                 if (modelSlug === typeSlug) { | ||||
|                                                     selected = true; | ||||
|                                                     this.showUrlOptions = type.urlsCustomizable; | ||||
|                                                     this.showRequestTokenURL = | ||||
|                                                         type.requestTokenUrl !== null; | ||||
|                                                 } | ||||
|                                             } | ||||
|                                             return html`<option | ||||
|                                                 ?data-urls-custom=${type.urlsCustomizable} | ||||
|                                                 ?data-request-token=${type.requestTokenUrl} | ||||
|                                                 value=${type.slug} | ||||
|                                                 ?selected=${selected} | ||||
|                                             > | ||||
|                                                 ${type.name} | ||||
|                                             </option>`; | ||||
|                                         }); | ||||
|                                     }), | ||||
|                                 html`<option>${t`Loading...`}</option>`, | ||||
|                             )} | ||||
|                         </select> | ||||
|                     </ak-form-element-horizontal> | ||||
|                 </div> | ||||
|             </ak-form-group> | ||||
|             ${this.renderUrlOptions()} | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Jens Langhammer
					Jens Langhammer