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:
Jens Langhammer 2021-08-21 15:52:41 +02:00
parent 00a666856d
commit b4f738492d
7 changed files with 89 additions and 69 deletions

View File

@ -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:

View File

@ -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)

View File

@ -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),
]

View File

@ -75,7 +75,7 @@ class AzureADType(SourceType):
callback_view = AzureADOAuthCallback
redirect_view = AzureADOAuthRedirect
name = "Azure AD"
slug = "azure-ad"
slug = "azuread"
urls_customizable = True

View File

@ -40,6 +40,6 @@ class OpenIDConnectType(SourceType):
callback_view = OpenIDConnectOAuth2Callback
redirect_view = OpenIDConnectOAuthRedirect
name = "OpenID Connect"
slug = "openid-connect"
slug = "openidconnect"
urls_customizable = True

View File

@ -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:

View File

@ -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()}