From 7db598c04e3281c9fcf82fea4eb182ab47be41a9 Mon Sep 17 00:00:00 2001 From: Ken Sternberg <133134217+kensternberg-authentik@users.noreply.github.com> Date: Sun, 11 Feb 2024 10:57:37 -0800 Subject: [PATCH] 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 * i18n Signed-off-by: Jens Langhammer * 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 Co-authored-by: Jens Langhammer --- ...rd-authentication-method-choice.choices.ts | 23 ++++ ...ion-wizard-authentication-method-choice.ts | 10 +- ...pplication-wizard-authentication-method.ts | 1 + ...plication-wizard-authentication-for-rac.ts | 110 ++++++++++++++++++ web/src/admin/applications/wizard/types.ts | 2 + .../admin/providers/rac/RACProviderForm.ts | 5 - 6 files changed, 143 insertions(+), 8 deletions(-) create mode 100644 web/src/admin/applications/wizard/methods/rac/ak-application-wizard-authentication-for-rac.ts diff --git a/web/src/admin/applications/wizard/auth-method-choice/ak-application-wizard-authentication-method-choice.choices.ts b/web/src/admin/applications/wizard/auth-method-choice/ak-application-wizard-authentication-method-choice.choices.ts index 2c04429152..d0e2c4d0c7 100644 --- a/web/src/admin/applications/wizard/auth-method-choice/ak-application-wizard-authentication-method-choice.choices.ts +++ b/web/src/admin/applications/wizard/auth-method-choice/ak-application-wizard-authentication-method-choice.choices.ts @@ -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``, + ProviderModelEnum.RacRacprovider, + (provider: OneOfProvider) => ({ + providerModel: ProviderModelEnum.RacRacprovider, + ...(provider as RACProviderRequest), + }), + () => html`` + ], [ "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, }; } diff --git a/web/src/admin/applications/wizard/auth-method-choice/ak-application-wizard-authentication-method-choice.ts b/web/src/admin/applications/wizard/auth-method-choice/ak-application-wizard-authentication-method-choice.ts index e13e11ecae..0f107d3123 100644 --- a/web/src/admin/applications/wizard/auth-method-choice/ak-application-wizard-authentication-method-choice.ts +++ b/web/src/admin/applications/wizard/auth-method-choice/ak-application-wizard-authentication-method-choice.ts @@ -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} /> - ${type.description} + ${type.description}${type.note ? type.note() : nothing} `; } diff --git a/web/src/admin/applications/wizard/methods/ak-application-wizard-authentication-method.ts b/web/src/admin/applications/wizard/methods/ak-application-wizard-authentication-method.ts index 9b7e813bfc..9c940c9424 100644 --- a/web/src/admin/applications/wizard/methods/ak-application-wizard-authentication-method.ts +++ b/web/src/admin/applications/wizard/methods/ak-application-wizard-authentication-method.ts @@ -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"; diff --git a/web/src/admin/applications/wizard/methods/rac/ak-application-wizard-authentication-for-rac.ts b/web/src/admin/applications/wizard/methods/rac/ak-application-wizard-authentication-for-rac.ts new file mode 100644 index 0000000000..53ce353f47 --- /dev/null +++ b/web/src/admin/applications/wizard/methods/rac/ak-application-wizard-authentication-for-rac.ts @@ -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`${msg("Configure Remote Access Provider Provider")} +
+ + + + +

+ ${msg("Flow used when authorizing this provider.")} +

+
+ + + + + ${msg("Protocol settings")} +
+ + +

+ ${msg("Hold control/command to select multiple items.")} +

+
+
+
+
`; + } +} + +export default ApplicationWizardAuthenticationByRAC; diff --git a/web/src/admin/applications/wizard/types.ts b/web/src/admin/applications/wizard/types.ts index a6e86cac13..d36340c87c 100644 --- a/web/src/admin/applications/wizard/types.ts +++ b/web/src/admin/applications/wizard/types.ts @@ -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 | Partial | Partial + | Partial | Partial | Partial | Partial diff --git a/web/src/admin/providers/rac/RACProviderForm.ts b/web/src/admin/providers/rac/RACProviderForm.ts index e4f6b789f3..b4b122cba4 100644 --- a/web/src/admin/providers/rac/RACProviderForm.ts +++ b/web/src/admin/providers/rac/RACProviderForm.ts @@ -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 { @state() - endpoints?: PaginatedEndpointList; - propertyMappings?: PaginatedRACPropertyMappingList; async load(): Promise { - this.endpoints = await new RacApi(DEFAULT_CONFIG).racEndpointsList({}); this.propertyMappings = await new PropertymappingsApi( DEFAULT_CONFIG, ).propertymappingsRacList({