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:
parent
00a666856d
commit
b4f738492d
|
@ -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 = []
|
||||
for source_type in MANAGER.get():
|
||||
data.append(SourceTypeSerializer(source_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 a new issue