web: add RAC Provider to the list of providers understood by the wizard (#8149)
* 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. * web: remove console.log() from ak-license-notice * web: fix inconsistencies in identity passing. * web: move the license summary information into a top-level context. Rather than repeatedly fetching the license summary, this commit fetches it once at the top-level and keeps it until an EVENT_REFRESH reaches the top level. This prevents the FOUC (Flash Of Unavailable Content) while loading and awaiting the end of the load. * Remove some debugging info, fix a misspelling. * web: provide a context for enterprise license status There are a few places (currently 5) in our code where we have checks for the current enterprise licensing status of our product. While not particularly heavy or onerous, there's no reason to repeat those same lines, and since our UI is always running in the context of authentik, may as well make that status a client-side context in its own right. The status will update with an EVENT_REFRESH request. A context-aware custom alert has also been provided; it draws itself (or `nothing`) depending on the state of the license, and the default message, "This feature requires an enterprise license," can be overriden with the `notice` property. These two changes reduce the amount of code needed to manage our license alerting from 67 to 38 lines code, and while removing 29 lines from a product with 54,145 lines of code (a savings of 0.05%, oh boy!) isn't a miracle, it does mean there's a single source of truth for "Is this instance enterprise-licensed?" that's easy to access and use. * web: [x] The translation files have been updated * 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. * web: fix inconsistencies in identity passing. * web: move the license summary information into a top-level context. Rather than repeatedly fetching the license summary, this commit fetches it once at the top-level and keeps it until an EVENT_REFRESH reaches the top level. This prevents the FOUC (Flash Of Unavailable Content) while loading and awaiting the end of the load. * Remove some debugging info, fix a misspelling. * remmove endpoint fetch from both rac provider forms since its not used Signed-off-by: Jens Langhammer <jens@goauthentik.io> * i18n Signed-off-by: Jens Langhammer <jens@goauthentik.io> * web: RAC updates - special case: disable RAC provider in the wizard if enterprise is not enabled - remove `settings` YAML editor from the RAC provider in the wizard --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> Co-authored-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
@ -1,3 +1,5 @@
|
||||
import "@goauthentik/admin/common/ak-license-notice";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { TemplateResult, html } from "lit";
|
||||
|
||||
@ -8,6 +10,7 @@ import type {
|
||||
ModelRequest,
|
||||
OAuth2ProviderRequest,
|
||||
ProxyProviderRequest,
|
||||
RACProviderRequest,
|
||||
RadiusProviderRequest,
|
||||
SAMLProviderRequest,
|
||||
SCIMProviderRequest,
|
||||
@ -19,6 +22,9 @@ type ProviderRenderer = () => TemplateResult;
|
||||
|
||||
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.
|
||||
*/
|
||||
@ -30,12 +36,14 @@ type ProviderType = [
|
||||
ProviderRenderer, // Function that returns the provider's wizard panel as a TemplateResult
|
||||
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
|
||||
ProviderNote?,
|
||||
];
|
||||
|
||||
export type LocalTypeCreate = TypeCreate & {
|
||||
formName: string;
|
||||
modelName: ProviderModelEnumType;
|
||||
converter: ModelConverter;
|
||||
note?: ProviderNote;
|
||||
};
|
||||
|
||||
// prettier-ignore
|
||||
@ -103,6 +111,19 @@ const _providerModelsTable: ProviderType[] = [
|
||||
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",
|
||||
msg("SAML (Security Assertion Markup Language)"),
|
||||
@ -148,6 +169,7 @@ function mapProviders([
|
||||
_,
|
||||
modelName,
|
||||
converter,
|
||||
note,
|
||||
]: ProviderType): LocalTypeCreate {
|
||||
return {
|
||||
formName,
|
||||
@ -156,6 +178,7 @@ function mapProviders([
|
||||
component: "",
|
||||
modelName,
|
||||
converter,
|
||||
note,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { WithLicenseSummary } from "@goauthentik/app/elements/Interface/licenseSummaryProvider";
|
||||
import "@goauthentik/components/ak-radio-input";
|
||||
import "@goauthentik/components/ak-switch-input";
|
||||
import "@goauthentik/components/ak-text-input";
|
||||
@ -7,7 +8,7 @@ import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
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 BasePanel from "../BasePanel";
|
||||
@ -15,7 +16,7 @@ import providerModelsList from "./ak-application-wizard-authentication-method-ch
|
||||
import type { LocalTypeCreate } from "./ak-application-wizard-authentication-method-choice.choices";
|
||||
|
||||
@customElement("ak-application-wizard-authentication-method-choice")
|
||||
export class ApplicationWizardAuthenticationMethodChoice extends BasePanel {
|
||||
export class ApplicationWizardAuthenticationMethodChoice extends WithLicenseSummary(BasePanel) {
|
||||
constructor() {
|
||||
super();
|
||||
this.handleChoice = this.handleChoice.bind(this);
|
||||
@ -43,12 +44,15 @@ export class ApplicationWizardAuthenticationMethodChoice extends BasePanel {
|
||||
type="radio"
|
||||
name="type"
|
||||
id="provider-${type.formName}"
|
||||
?disabled=${type.formName === "racprovider" && !this.hasEnterpriseLicense}
|
||||
value=${type.formName}
|
||||
?checked=${type.formName === method}
|
||||
@change=${this.handleChoice}
|
||||
/>
|
||||
<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>`;
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ import "./oauth/ak-application-wizard-authentication-by-oauth";
|
||||
import "./proxy/ak-application-wizard-authentication-for-forward-domain-proxy";
|
||||
import "./proxy/ak-application-wizard-authentication-for-reverse-proxy";
|
||||
import "./proxy/ak-application-wizard-authentication-for-single-forward-proxy";
|
||||
import "./rac/ak-application-wizard-authentication-for-rac";
|
||||
import "./radius/ak-application-wizard-authentication-by-radius";
|
||||
import "./saml/ak-application-wizard-authentication-by-saml-configuration";
|
||||
import "./scim/ak-application-wizard-authentication-by-scim";
|
||||
|
@ -0,0 +1,110 @@
|
||||
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 { 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,
|
||||
PaginatedRACPropertyMappingList,
|
||||
PropertymappingsApi,
|
||||
RACProvider,
|
||||
} from "@goauthentik/api";
|
||||
|
||||
import BaseProviderPanel from "../BaseProviderPanel";
|
||||
|
||||
@customElement("ak-application-wizard-authentication-for-rac")
|
||||
export class ApplicationWizardAuthenticationByRAC extends BaseProviderPanel {
|
||||
@state()
|
||||
propertyMappings?: PaginatedRACPropertyMappingList;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
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.",
|
||||
)}
|
||||
></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>
|
||||
</div>
|
||||
</ak-form-group>
|
||||
</form>`;
|
||||
}
|
||||
}
|
||||
|
||||
export default ApplicationWizardAuthenticationByRAC;
|
@ -6,6 +6,7 @@ import {
|
||||
type OAuth2ProviderRequest,
|
||||
type ProvidersSamlImportMetadataCreateRequest,
|
||||
type ProxyProviderRequest,
|
||||
type RACProviderRequest,
|
||||
type RadiusProviderRequest,
|
||||
type SAMLProviderRequest,
|
||||
type SCIMProviderRequest,
|
||||
@ -16,6 +17,7 @@ export type OneOfProvider =
|
||||
| Partial<SCIMProviderRequest>
|
||||
| Partial<SAMLProviderRequest>
|
||||
| Partial<ProvidersSamlImportMetadataCreateRequest>
|
||||
| Partial<RACProviderRequest>
|
||||
| Partial<RadiusProviderRequest>
|
||||
| Partial<ProxyProviderRequest>
|
||||
| Partial<OAuth2ProviderRequest>
|
||||
|
@ -18,23 +18,18 @@ import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
import {
|
||||
FlowsInstancesListDesignationEnum,
|
||||
PaginatedEndpointList,
|
||||
PaginatedRACPropertyMappingList,
|
||||
PropertymappingsApi,
|
||||
ProvidersApi,
|
||||
RACProvider,
|
||||
RacApi,
|
||||
} from "@goauthentik/api";
|
||||
|
||||
@customElement("ak-provider-rac-form")
|
||||
export class RACProviderFormPage extends ModelForm<RACProvider, number> {
|
||||
@state()
|
||||
endpoints?: PaginatedEndpointList;
|
||||
|
||||
propertyMappings?: PaginatedRACPropertyMappingList;
|
||||
|
||||
async load(): Promise<void> {
|
||||
this.endpoints = await new RacApi(DEFAULT_CONFIG).racEndpointsList({});
|
||||
this.propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsRacList({
|
||||
|
Reference in New Issue
Block a user