web: add RAC Provider to the list of providers understood by the wizard
This commit also creates a new, simple alert that knows how to look up the enterprise requirements and chooses to fill itself in with a notice saying "A license is required for this provider," or nothing. That harmonizes the display across both wizards, and reduces the demands on the wizards themselves to "know" about enterprise features.
This commit is contained in:
parent
b93b5f28a3
commit
4864b31306
|
@ -1,3 +1,5 @@
|
||||||
|
import "@goauthentik/admin/common/ak-license-notice";
|
||||||
|
|
||||||
import { msg } from "@lit/localize";
|
import { msg } from "@lit/localize";
|
||||||
import { TemplateResult, html } from "lit";
|
import { TemplateResult, html } from "lit";
|
||||||
|
|
||||||
|
@ -8,6 +10,7 @@ import type {
|
||||||
ModelRequest,
|
ModelRequest,
|
||||||
OAuth2ProviderRequest,
|
OAuth2ProviderRequest,
|
||||||
ProxyProviderRequest,
|
ProxyProviderRequest,
|
||||||
|
RACProviderRequest,
|
||||||
RadiusProviderRequest,
|
RadiusProviderRequest,
|
||||||
SAMLProviderRequest,
|
SAMLProviderRequest,
|
||||||
SCIMProviderRequest,
|
SCIMProviderRequest,
|
||||||
|
@ -19,6 +22,9 @@ type ProviderRenderer = () => TemplateResult;
|
||||||
|
|
||||||
type ModelConverter = (provider: OneOfProvider) => ModelRequest;
|
type ModelConverter = (provider: OneOfProvider) => ModelRequest;
|
||||||
|
|
||||||
|
type ProviderNoteProvider = () => TemplateResult | undefined;
|
||||||
|
type ProviderNote = ProviderNoteProvider | undefined;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* There's an internal key and an API key because "Proxy" has three different subtypes.
|
* There's an internal key and an API key because "Proxy" has three different subtypes.
|
||||||
*/
|
*/
|
||||||
|
@ -30,12 +36,14 @@ type ProviderType = [
|
||||||
ProviderRenderer, // Function that returns the provider's wizard panel as a TemplateResult
|
ProviderRenderer, // Function that returns the provider's wizard panel as a TemplateResult
|
||||||
ProviderModelEnumType, // key used by the API to distinguish between providers
|
ProviderModelEnumType, // key used by the API to distinguish between providers
|
||||||
ModelConverter, // Handler that takes a generic provider and returns one specifically typed to its panel
|
ModelConverter, // Handler that takes a generic provider and returns one specifically typed to its panel
|
||||||
|
ProviderNote?,
|
||||||
];
|
];
|
||||||
|
|
||||||
export type LocalTypeCreate = TypeCreate & {
|
export type LocalTypeCreate = TypeCreate & {
|
||||||
formName: string;
|
formName: string;
|
||||||
modelName: ProviderModelEnumType;
|
modelName: ProviderModelEnumType;
|
||||||
converter: ModelConverter;
|
converter: ModelConverter;
|
||||||
|
note?: ProviderNote;
|
||||||
};
|
};
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
|
@ -103,6 +111,19 @@ const _providerModelsTable: ProviderType[] = [
|
||||||
mode: ProxyMode.ForwardDomain,
|
mode: ProxyMode.ForwardDomain,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"racprovider",
|
||||||
|
msg("Remote Access Provider"),
|
||||||
|
msg("Remotely access computers/servers via RDP/SSH/VNC"),
|
||||||
|
() =>
|
||||||
|
html`<ak-application-wizard-authentication-for-rac></ak-application-wizard-authentication-for-rac>`,
|
||||||
|
ProviderModelEnum.RacRacprovider,
|
||||||
|
(provider: OneOfProvider) => ({
|
||||||
|
providerModel: ProviderModelEnum.RacRacprovider,
|
||||||
|
...(provider as RACProviderRequest),
|
||||||
|
}),
|
||||||
|
() => html`<ak-license-notice></ak-license-notice>`
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"samlprovider",
|
"samlprovider",
|
||||||
msg("SAML (Security Assertion Markup Language)"),
|
msg("SAML (Security Assertion Markup Language)"),
|
||||||
|
@ -148,6 +169,7 @@ function mapProviders([
|
||||||
_,
|
_,
|
||||||
modelName,
|
modelName,
|
||||||
converter,
|
converter,
|
||||||
|
note,
|
||||||
]: ProviderType): LocalTypeCreate {
|
]: ProviderType): LocalTypeCreate {
|
||||||
return {
|
return {
|
||||||
formName,
|
formName,
|
||||||
|
@ -156,6 +178,7 @@ function mapProviders([
|
||||||
component: "",
|
component: "",
|
||||||
modelName,
|
modelName,
|
||||||
converter,
|
converter,
|
||||||
|
note,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
|
|
||||||
import { msg } from "@lit/localize";
|
import { msg } from "@lit/localize";
|
||||||
import { customElement } from "@lit/reactive-element/decorators/custom-element.js";
|
import { customElement } from "@lit/reactive-element/decorators/custom-element.js";
|
||||||
import { html } from "lit";
|
import { html, nothing } from "lit";
|
||||||
import { map } from "lit/directives/map.js";
|
import { map } from "lit/directives/map.js";
|
||||||
|
|
||||||
import BasePanel from "../BasePanel";
|
import BasePanel from "../BasePanel";
|
||||||
|
@ -48,7 +48,9 @@ export class ApplicationWizardAuthenticationMethodChoice extends BasePanel {
|
||||||
@change=${this.handleChoice}
|
@change=${this.handleChoice}
|
||||||
/>
|
/>
|
||||||
<label class="pf-c-radio__label" for="provider-${type.formName}">${type.name}</label>
|
<label class="pf-c-radio__label" for="provider-${type.formName}">${type.name}</label>
|
||||||
<span class="pf-c-radio__description">${type.description}</span>
|
<span class="pf-c-radio__description"
|
||||||
|
>${type.description}${type.note ? type.note() : nothing}</span
|
||||||
|
>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
import "@goauthentik/admin/applications/wizard/ak-wizard-title";
|
||||||
|
import "@goauthentik/admin/common/ak-flow-search/ak-flow-search";
|
||||||
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
|
import "@goauthentik/components/ak-text-input";
|
||||||
|
import "@goauthentik/elements/CodeMirror";
|
||||||
|
import "@goauthentik/elements/forms/FormGroup";
|
||||||
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
|
import YAML from "yaml";
|
||||||
|
|
||||||
|
import { msg } from "@lit/localize";
|
||||||
|
import { html } from "lit";
|
||||||
|
import { customElement, state } from "lit/decorators.js";
|
||||||
|
import { ifDefined } from "lit/directives/if-defined.js";
|
||||||
|
|
||||||
|
import {
|
||||||
|
FlowsInstancesListDesignationEnum,
|
||||||
|
PaginatedEndpointList,
|
||||||
|
PaginatedRACPropertyMappingList,
|
||||||
|
PropertymappingsApi,
|
||||||
|
RACProvider,
|
||||||
|
RacApi,
|
||||||
|
} from "@goauthentik/api";
|
||||||
|
|
||||||
|
import BaseProviderPanel from "../BaseProviderPanel";
|
||||||
|
|
||||||
|
@customElement("ak-application-wizard-authentication-by-rac")
|
||||||
|
export class ApplicationWizardAuthenticationByRAC extends BaseProviderPanel {
|
||||||
|
@state()
|
||||||
|
endpoints?: PaginatedEndpointList;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
propertyMappings?: PaginatedRACPropertyMappingList;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
new RacApi(DEFAULT_CONFIG).racEndpointsList({}).then((endpoints) => {
|
||||||
|
this.endpoints = endpoints;
|
||||||
|
});
|
||||||
|
new PropertymappingsApi(DEFAULT_CONFIG)
|
||||||
|
.propertymappingsRacList({
|
||||||
|
ordering: "name",
|
||||||
|
})
|
||||||
|
.then((propertyMappings) => {
|
||||||
|
this.propertyMappings = propertyMappings;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const provider = this.wizard.provider as RACProvider | undefined;
|
||||||
|
const selected = new Set(Array.from(provider?.propertyMappings ?? []));
|
||||||
|
const errors = this.wizard.errors.provider;
|
||||||
|
|
||||||
|
return html`<ak-wizard-title
|
||||||
|
>${msg("Configure Remote Access Provider Provider")}</ak-wizard-title
|
||||||
|
>
|
||||||
|
<form class="pf-c-form pf-m-horizontal" @input=${this.handleChange}>
|
||||||
|
<ak-text-input
|
||||||
|
name="name"
|
||||||
|
label=${msg("Name")}
|
||||||
|
value=${ifDefined(provider?.name)}
|
||||||
|
.errorMessages=${errors?.name ?? []}
|
||||||
|
required
|
||||||
|
></ak-text-input>
|
||||||
|
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
name="authorizationFlow"
|
||||||
|
label=${msg("Authorization flow")}
|
||||||
|
?required=${true}
|
||||||
|
>
|
||||||
|
<ak-flow-search
|
||||||
|
flowType=${FlowsInstancesListDesignationEnum.Authorization}
|
||||||
|
.currentFlow=${provider?.authorizationFlow}
|
||||||
|
required
|
||||||
|
></ak-flow-search>
|
||||||
|
<p class="pf-c-form__helper-text">
|
||||||
|
${msg("Flow used when authorizing this provider.")}
|
||||||
|
</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
|
||||||
|
<ak-text-input
|
||||||
|
name="connectionExpiry"
|
||||||
|
label=${msg("Connection expiry")}
|
||||||
|
required
|
||||||
|
value="${provider?.connectionExpiry ?? "hours=8"}"
|
||||||
|
help=${msg(
|
||||||
|
"Determines how long a session lasts before being disconnected and requiring re-authorization.",
|
||||||
|
)}
|
||||||
|
required
|
||||||
|
></ak-text-input>
|
||||||
|
|
||||||
|
<ak-form-group .expanded=${true}>
|
||||||
|
<span slot="header"> ${msg("Protocol settings")} </span>
|
||||||
|
<div slot="body" class="pf-c-form">
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${msg("Property mappings")}
|
||||||
|
?required=${true}
|
||||||
|
name="propertyMappings"
|
||||||
|
>
|
||||||
|
<select class="pf-c-form-control" multiple>
|
||||||
|
${this.propertyMappings?.results.map(
|
||||||
|
(mapping) =>
|
||||||
|
html`<option
|
||||||
|
value=${ifDefined(mapping.pk)}
|
||||||
|
?selected=${selected.has(mapping.pk)}
|
||||||
|
>
|
||||||
|
${mapping.name}
|
||||||
|
</option>`,
|
||||||
|
)}
|
||||||
|
</select>
|
||||||
|
<p class="pf-c-form__helper-text">
|
||||||
|
${msg("Hold control/command to select multiple items.")}
|
||||||
|
</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal label=${msg("Settings")} name="settings">
|
||||||
|
<ak-codemirror
|
||||||
|
mode="yaml"
|
||||||
|
value="${YAML.stringify(provider?.settings ?? {})}"
|
||||||
|
>
|
||||||
|
</ak-codemirror>
|
||||||
|
<p class="pf-c-form__helper-text">${msg("Connection settings.")}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
</div>
|
||||||
|
</ak-form-group>
|
||||||
|
</form>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ApplicationWizardAuthenticationByRAC;
|
|
@ -6,6 +6,7 @@ import {
|
||||||
type OAuth2ProviderRequest,
|
type OAuth2ProviderRequest,
|
||||||
type ProvidersSamlImportMetadataCreateRequest,
|
type ProvidersSamlImportMetadataCreateRequest,
|
||||||
type ProxyProviderRequest,
|
type ProxyProviderRequest,
|
||||||
|
type RACProviderRequest,
|
||||||
type RadiusProviderRequest,
|
type RadiusProviderRequest,
|
||||||
type SAMLProviderRequest,
|
type SAMLProviderRequest,
|
||||||
type SCIMProviderRequest,
|
type SCIMProviderRequest,
|
||||||
|
@ -16,6 +17,7 @@ export type OneOfProvider =
|
||||||
| Partial<SCIMProviderRequest>
|
| Partial<SCIMProviderRequest>
|
||||||
| Partial<SAMLProviderRequest>
|
| Partial<SAMLProviderRequest>
|
||||||
| Partial<ProvidersSamlImportMetadataCreateRequest>
|
| Partial<ProvidersSamlImportMetadataCreateRequest>
|
||||||
|
| Partial<RACProviderRequest>
|
||||||
| Partial<RadiusProviderRequest>
|
| Partial<RadiusProviderRequest>
|
||||||
| Partial<ProxyProviderRequest>
|
| Partial<ProxyProviderRequest>
|
||||||
| Partial<OAuth2ProviderRequest>
|
| Partial<OAuth2ProviderRequest>
|
||||||
|
|
|
@ -53,7 +53,7 @@ export class InitialProviderWizardPage extends WithLicenseSummary(WizardPage) {
|
||||||
<div class="pf-c-hint__title">${msg("Try the new application wizard")}</div>
|
<div class="pf-c-hint__title">${msg("Try the new application wizard")}</div>
|
||||||
<div class="pf-c-hint__body">
|
<div class="pf-c-hint__body">
|
||||||
${msg(
|
${msg(
|
||||||
"The new application wizard greatly simplifies the steps required to create applications and providers.",
|
"The new application wizard greatly simplifies the steps required to create applications and providers."
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div class="pf-c-hint__footer">
|
<div class="pf-c-hint__footer">
|
||||||
|
|
Reference in New Issue