stages: source stage (#8330)
* stages: source stage Signed-off-by: Jens Langhammer <jens@goauthentik.io> * include stage name in dummy stage Signed-off-by: Jens Langhammer <jens@goauthentik.io> * use data instead of instance for login button Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make mostly work Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix ident stage Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make it work Signed-off-by: Jens Langhammer <jens@goauthentik.io> * pass more data Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix flow inspector not always loading Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix dark theme for stepper Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix inspector styling Signed-off-by: Jens Langhammer <jens@goauthentik.io> * don't skip source stage unless returning Signed-off-by: Jens Langhammer <jens@goauthentik.io> * auto open flow inspector when debug Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix lint Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fixup Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix lint Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix validation Signed-off-by: Jens Langhammer <jens@goauthentik.io> * include raw saml response in flow context Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add some tests Signed-off-by: Jens Langhammer <jens@goauthentik.io> * move Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add docs Signed-off-by: Jens Langhammer <jens@goauthentik.io> * Apply suggestions from code review Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com> Signed-off-by: Jens L. <jens@beryju.org> * fix import Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> Signed-off-by: Jens L. <jens@beryju.org> Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
This commit is contained in:
@ -15,6 +15,7 @@ import "@goauthentik/admin/stages/identification/IdentificationStageForm";
|
||||
import "@goauthentik/admin/stages/invitation/InvitationStageForm";
|
||||
import "@goauthentik/admin/stages/password/PasswordStageForm";
|
||||
import "@goauthentik/admin/stages/prompt/PromptStageForm";
|
||||
import "@goauthentik/admin/stages/source/SourceStageForm";
|
||||
import "@goauthentik/admin/stages/user_delete/UserDeleteStageForm";
|
||||
import "@goauthentik/admin/stages/user_login/UserLoginStageForm";
|
||||
import "@goauthentik/admin/stages/user_logout/UserLogoutStageForm";
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import "@goauthentik/admin/common/ak-license-notice";
|
||||
import { StageBindingForm } from "@goauthentik/admin/flows/StageBindingForm";
|
||||
import "@goauthentik/admin/stages/authenticator_duo/AuthenticatorDuoStageForm";
|
||||
import "@goauthentik/admin/stages/authenticator_sms/AuthenticatorSMSStageForm";
|
||||
@ -14,12 +15,14 @@ import "@goauthentik/admin/stages/identification/IdentificationStageForm";
|
||||
import "@goauthentik/admin/stages/invitation/InvitationStageForm";
|
||||
import "@goauthentik/admin/stages/password/PasswordStageForm";
|
||||
import "@goauthentik/admin/stages/prompt/PromptStageForm";
|
||||
import "@goauthentik/admin/stages/source/SourceStageForm";
|
||||
import "@goauthentik/admin/stages/user_delete/UserDeleteStageForm";
|
||||
import "@goauthentik/admin/stages/user_login/UserLoginStageForm";
|
||||
import "@goauthentik/admin/stages/user_logout/UserLogoutStageForm";
|
||||
import "@goauthentik/admin/stages/user_write/UserWriteStageForm";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
import { WithLicenseSummary } from "@goauthentik/elements/Interface/licenseSummaryProvider";
|
||||
import "@goauthentik/elements/forms/ProxyForm";
|
||||
import "@goauthentik/elements/wizard/FormWizardPage";
|
||||
import { FormWizardPage } from "@goauthentik/elements/wizard/FormWizardPage";
|
||||
@ -28,7 +31,7 @@ import { WizardPage } from "@goauthentik/elements/wizard/WizardPage";
|
||||
|
||||
import { msg, str } from "@lit/localize";
|
||||
import { customElement } from "@lit/reactive-element/decorators/custom-element.js";
|
||||
import { CSSResult, TemplateResult, html } from "lit";
|
||||
import { CSSResult, TemplateResult, html, nothing } from "lit";
|
||||
import { property } from "lit/decorators.js";
|
||||
|
||||
import PFButton from "@patternfly/patternfly/components/Button/button.css";
|
||||
@ -39,7 +42,7 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||
import { FlowStageBinding, Stage, StagesApi, TypeCreate } from "@goauthentik/api";
|
||||
|
||||
@customElement("ak-stage-wizard-initial")
|
||||
export class InitialStageWizardPage extends WizardPage {
|
||||
export class InitialStageWizardPage extends WithLicenseSummary(WizardPage) {
|
||||
@property({ attribute: false })
|
||||
stageTypes: TypeCreate[] = [];
|
||||
sidebarLabel = () => msg("Select type");
|
||||
@ -62,6 +65,7 @@ export class InitialStageWizardPage extends WizardPage {
|
||||
render(): TemplateResult {
|
||||
return html`<form class="pf-c-form pf-m-horizontal">
|
||||
${this.stageTypes.map((type) => {
|
||||
const requiresEnterprise = type.requiresEnterprise && !this.hasEnterpriseLicense;
|
||||
return html`<div class="pf-c-radio">
|
||||
<input
|
||||
class="pf-c-radio__input"
|
||||
@ -82,11 +86,15 @@ export class InitialStageWizardPage extends WizardPage {
|
||||
);
|
||||
this.host.isValid = true;
|
||||
}}
|
||||
?disabled=${requiresEnterprise}
|
||||
/>
|
||||
<label class="pf-c-radio__label" for=${`${type.component}-${type.modelName}`}
|
||||
>${type.name}</label
|
||||
>
|
||||
<span class="pf-c-radio__description">${type.description}</span>
|
||||
<span class="pf-c-radio__description">${type.description}${
|
||||
requiresEnterprise ? html`<ak-license-notice></ak-license-notice>` : nothing
|
||||
}</span>
|
||||
</span>
|
||||
</div>`;
|
||||
})}
|
||||
</form>`;
|
||||
|
||||
99
web/src/admin/stages/source/SourceStageForm.ts
Normal file
99
web/src/admin/stages/source/SourceStageForm.ts
Normal file
@ -0,0 +1,99 @@
|
||||
import { BaseStageForm } from "@goauthentik/admin/stages/BaseStageForm";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/SearchSelect/index";
|
||||
import "@goauthentik/elements/utils/TimeDeltaHelp";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { TemplateResult, html } from "lit";
|
||||
import { customElement } from "lit/decorators.js";
|
||||
import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
import {
|
||||
Source,
|
||||
SourceStage,
|
||||
SourcesAllListRequest,
|
||||
SourcesApi,
|
||||
StagesApi,
|
||||
} from "@goauthentik/api";
|
||||
|
||||
@customElement("ak-stage-source-form")
|
||||
export class SourceStageForm extends BaseStageForm<SourceStage> {
|
||||
loadInstance(pk: string): Promise<SourceStage> {
|
||||
return new StagesApi(DEFAULT_CONFIG).stagesSourceRetrieve({
|
||||
stageUuid: pk,
|
||||
});
|
||||
}
|
||||
|
||||
async send(data: SourceStage): Promise<SourceStage> {
|
||||
if (this.instance) {
|
||||
return new StagesApi(DEFAULT_CONFIG).stagesSourceUpdate({
|
||||
stageUuid: this.instance.pk || "",
|
||||
sourceStageRequest: data,
|
||||
});
|
||||
} else {
|
||||
return new StagesApi(DEFAULT_CONFIG).stagesSourceCreate({
|
||||
sourceStageRequest: data,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
renderForm(): TemplateResult {
|
||||
return html`
|
||||
<span> ${msg("TODO.")} </span>
|
||||
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
|
||||
<input
|
||||
type="text"
|
||||
value="${ifDefined(this.instance?.name || "")}"
|
||||
class="pf-c-form-control"
|
||||
required
|
||||
/>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal label=${msg("Source")} ?required=${true} name="source">
|
||||
<ak-search-select
|
||||
.fetchObjects=${async (query?: string): Promise<Source[]> => {
|
||||
const args: SourcesAllListRequest = {
|
||||
ordering: "name",
|
||||
};
|
||||
if (query !== undefined) {
|
||||
args.search = query;
|
||||
}
|
||||
const users = await new SourcesApi(DEFAULT_CONFIG).sourcesAllList(args);
|
||||
return users.results;
|
||||
}}
|
||||
.renderElement=${(source: Source): string => {
|
||||
return source.name;
|
||||
}}
|
||||
.renderDescription=${(source: Source): TemplateResult => {
|
||||
return html`${source.verboseName}`;
|
||||
}}
|
||||
.value=${(source: Source | undefined): string | undefined => {
|
||||
return source?.pk;
|
||||
}}
|
||||
.selected=${(source: Source): boolean => {
|
||||
return source.pk === this.instance?.source;
|
||||
}}
|
||||
>
|
||||
</ak-search-select>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${msg("Resume timeout")}
|
||||
?required=${true}
|
||||
name="resumeTimeout"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
value="${ifDefined(this.instance?.resumeTimeout || "minutes=10")}"
|
||||
class="pf-c-form-control"
|
||||
required
|
||||
/>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg(
|
||||
"Amount of time a user can take to return from the source to continue the flow.",
|
||||
)}
|
||||
</p>
|
||||
<ak-utils-time-delta-help></ak-utils-time-delta-help>
|
||||
</ak-form-element-horizontal>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@ -329,3 +329,7 @@ input[type="date"]::-webkit-calendar-picker-indicator {
|
||||
.pf-c-tree-view__content:focus-within {
|
||||
--pf-c-tree-view__node--hover--BackgroundColor: var(--ak-dark-background-light-ish);
|
||||
}
|
||||
/* stepper */
|
||||
.pf-c-progress-stepper__step-title {
|
||||
--pf-c-progress-stepper__step-title--Color: var(--ak-dark-foreground);
|
||||
}
|
||||
|
||||
@ -32,6 +32,7 @@ import PFTitle from "@patternfly/patternfly/components/Title/title.css";
|
||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||
|
||||
import {
|
||||
CapabilitiesEnum,
|
||||
ChallengeChoices,
|
||||
ChallengeTypes,
|
||||
ContextualFlowInfo,
|
||||
@ -162,7 +163,7 @@ export class FlowExecutor extends Interface implements StageHost {
|
||||
super();
|
||||
this.ws = new WebsocketClient();
|
||||
if (window.location.search.includes("inspector")) {
|
||||
this.inspectorOpen = !this.inspectorOpen;
|
||||
this.inspectorOpen = true;
|
||||
}
|
||||
this.addEventListener(EVENT_FLOW_INSPECTOR_TOGGLE, () => {
|
||||
this.inspectorOpen = !this.inspectorOpen;
|
||||
@ -213,6 +214,9 @@ export class FlowExecutor extends Interface implements StageHost {
|
||||
|
||||
async firstUpdated(): Promise<void> {
|
||||
configureSentry();
|
||||
if (this.config?.capabilities.includes(CapabilitiesEnum.CanDebug)) {
|
||||
this.inspectorOpen = true;
|
||||
}
|
||||
this.loading = true;
|
||||
try {
|
||||
const challenge = await new FlowsApi(DEFAULT_CONFIG).flowsExecutorGet({
|
||||
|
||||
@ -37,6 +37,10 @@ export class FlowInspector extends AKElement {
|
||||
PFDescriptionList,
|
||||
PFProgressStepper,
|
||||
css`
|
||||
.pf-c-drawer__body {
|
||||
min-height: 100vh;
|
||||
max-height: 100vh;
|
||||
}
|
||||
code.break {
|
||||
word-break: break-all;
|
||||
}
|
||||
@ -45,9 +49,6 @@ export class FlowInspector extends AKElement {
|
||||
overflow-x: hidden;
|
||||
white-space: break-spaces;
|
||||
}
|
||||
.pf-c-notification-drawer__body {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
@ -113,6 +114,7 @@ export class FlowInspector extends AKElement {
|
||||
return this.renderAccessDenied();
|
||||
}
|
||||
if (!this.state) {
|
||||
this.advanceHandler();
|
||||
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ import "@goauthentik/elements/EmptyState";
|
||||
import "@goauthentik/flow/FormStatic";
|
||||
import { BaseStage } from "@goauthentik/flow/stages/base";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { msg, str } from "@lit/localize";
|
||||
import { CSSResult, TemplateResult, html } from "lit";
|
||||
import { customElement } from "lit/decorators.js";
|
||||
|
||||
@ -36,6 +36,7 @@ export class DummyStage extends BaseStage<DummyChallenge, DummyChallengeResponse
|
||||
this.submitForm(e);
|
||||
}}
|
||||
>
|
||||
<p>${msg(str`Stage name: ${this.challenge.name}`)}</p>
|
||||
<div class="pf-c-form__group pf-m-action">
|
||||
<button type="submit" class="pf-c-button pf-m-primary pf-m-block">
|
||||
${msg("Continue")}
|
||||
|
||||
Reference in New Issue
Block a user