Almost there!
This commit is contained in:
@ -36,7 +36,7 @@ export type LocalTypeCreate = TypeCreate & {
|
||||
export const providerModelsList: LocalTypeCreate[] = [
|
||||
{
|
||||
formName: "oauth2provider",
|
||||
name: msg("OAuth2/OIDC (Open Authorization/OpenID Connect)"),
|
||||
name: msg("OAuth2/OpenID Provider"),
|
||||
description: msg("Modern applications, APIs and Single-page applications."),
|
||||
renderer: () =>
|
||||
html`<ak-application-wizard-authentication-by-oauth></ak-application-wizard-authentication-by-oauth>`,
|
||||
@ -50,7 +50,7 @@ export const providerModelsList: LocalTypeCreate[] = [
|
||||
},
|
||||
{
|
||||
formName: "ldapprovider",
|
||||
name: msg("LDAP (Lightweight Directory Access Protocol)"),
|
||||
name: msg("LDAP Provider"),
|
||||
description: msg(
|
||||
"Provide an LDAP interface for applications and users to authenticate against.",
|
||||
),
|
||||
@ -127,7 +127,7 @@ export const providerModelsList: LocalTypeCreate[] = [
|
||||
},
|
||||
{
|
||||
formName: "samlprovider",
|
||||
name: msg("SAML (Security Assertion Markup Language)"),
|
||||
name: msg("SAML Provider"),
|
||||
description: msg("Configure SAML provider manually"),
|
||||
renderer: () =>
|
||||
html`<ak-application-wizard-authentication-by-saml-configuration></ak-application-wizard-authentication-by-saml-configuration>`,
|
||||
@ -141,7 +141,7 @@ export const providerModelsList: LocalTypeCreate[] = [
|
||||
},
|
||||
{
|
||||
formName: "radiusprovider",
|
||||
name: msg("RADIUS (Remote Authentication Dial-In User Service)"),
|
||||
name: msg("Radius Provider"),
|
||||
description: msg("Configure RADIUS provider manually"),
|
||||
renderer: () =>
|
||||
html`<ak-application-wizard-authentication-by-radius></ak-application-wizard-authentication-by-radius>`,
|
||||
@ -155,7 +155,7 @@ export const providerModelsList: LocalTypeCreate[] = [
|
||||
},
|
||||
{
|
||||
formName: "scimprovider",
|
||||
name: msg("SCIM (System for Cross-domain Identity Management)"),
|
||||
name: msg("SCIM Provider"),
|
||||
description: msg("Configure SCIM provider manually"),
|
||||
renderer: () =>
|
||||
html`<ak-application-wizard-authentication-by-scim></ak-application-wizard-authentication-by-scim>`,
|
||||
|
||||
@ -35,6 +35,7 @@ export class ApplicationWizardAuthenticationMethodChoice extends WithLicenseSumm
|
||||
? html`<form class="pf-c-form pf-m-horizontal">
|
||||
<ak-wizard-page-type-create
|
||||
.types=${typesForWizard}
|
||||
name="selectProviderType"
|
||||
layout=${TypeCreateWizardPageLayouts.grid}
|
||||
.selectedType=${selectedTypes.length > 0 ? selectedTypes[0] : undefined}
|
||||
@select=${(ev: CustomEvent<LocalTypeCreate>) => {
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
import { renderForm } from "@goauthentik/admin/providers/oauth2/OAuth2ProviderFormForm.js";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { customElement, state } from "@lit/reactive-element/decorators.js";
|
||||
import { html } from "lit";
|
||||
|
||||
import { SourcesApi } from "@goauthentik/api";
|
||||
import { type OAuth2Provider, type PaginatedOAuthSourceList } from "@goauthentik/api";
|
||||
@ -34,7 +36,15 @@ export class ApplicationWizardAuthenticationByOauth extends BaseProviderPanel {
|
||||
const showClientSecretCallback = (show: boolean) => {
|
||||
this.showClientSecret = show;
|
||||
};
|
||||
return renderForm(provider ?? {}, errors, this.showClientSecret, showClientSecretCallback);
|
||||
return html` <ak-wizard-title>${msg("Configure LDAP Provider")}</ak-wizard-title>
|
||||
<form class="pf-c-form pf-m-horizontal" @input=${this.handleChange}>
|
||||
${renderForm(
|
||||
provider ?? {},
|
||||
errors,
|
||||
this.showClientSecret,
|
||||
showClientSecretCallback,
|
||||
)}
|
||||
</form>`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import AkCryptoCertificateSearch from "@goauthentik/admin/common/ak-crypto-certificate-search";
|
||||
import { renderForm } from "@goauthentik/admin/providers/saml/SAMLProviderFormForm.js";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { customElement, state } from "@lit/reactive-element/decorators.js";
|
||||
|
||||
@ -1,21 +1,8 @@
|
||||
import "@goauthentik/admin/applications/wizard/ak-wizard-title";
|
||||
import "@goauthentik/admin/common/ak-core-group-search";
|
||||
import "@goauthentik/admin/common/ak-crypto-certificate-search";
|
||||
import "@goauthentik/admin/common/ak-flow-search/ak-branded-flow-search";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/components/ak-multi-select";
|
||||
import "@goauthentik/components/ak-switch-input";
|
||||
import "@goauthentik/components/ak-text-input";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { customElement, state } from "@lit/reactive-element/decorators.js";
|
||||
import { html } from "lit";
|
||||
import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
import { PaginatedSCIMMappingList, PropertymappingsApi, type SCIMProvider } from "@goauthentik/api";
|
||||
import { PaginatedSCIMMappingList, type SCIMProvider } from "@goauthentik/api";
|
||||
|
||||
import BaseProviderPanel from "../BaseProviderPanel";
|
||||
|
||||
@ -26,125 +13,15 @@ export class ApplicationWizardAuthenticationBySCIM extends BaseProviderPanel {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
new PropertymappingsApi(DEFAULT_CONFIG)
|
||||
.propertymappingsProviderScimList({
|
||||
ordering: "managed",
|
||||
})
|
||||
.then((propertyMappings: PaginatedSCIMMappingList) => {
|
||||
this.propertyMappings = propertyMappings;
|
||||
});
|
||||
}
|
||||
|
||||
propertyMappingConfiguration(provider?: SCIMProvider) {
|
||||
const propertyMappings = this.propertyMappings?.results ?? [];
|
||||
|
||||
const configuredMappings = (providerMappings: string[]) =>
|
||||
propertyMappings.map((pm) => pm.pk).filter((pmpk) => providerMappings.includes(pmpk));
|
||||
|
||||
const managedMappings = (key: string) =>
|
||||
propertyMappings
|
||||
.filter((pm) => pm.managed === `goauthentik.io/providers/scim/${key}`)
|
||||
.map((pm) => pm.pk);
|
||||
|
||||
const pmUserValues = provider?.propertyMappings
|
||||
? configuredMappings(provider?.propertyMappings ?? [])
|
||||
: managedMappings("user");
|
||||
|
||||
const pmGroupValues = provider?.propertyMappingsGroup
|
||||
? configuredMappings(provider?.propertyMappingsGroup ?? [])
|
||||
: managedMappings("group");
|
||||
|
||||
const propertyPairs = propertyMappings.map((pm) => [pm.pk, pm.name]);
|
||||
|
||||
return { pmUserValues, pmGroupValues, propertyPairs };
|
||||
}
|
||||
|
||||
render() {
|
||||
const provider = this.wizard.provider as SCIMProvider | undefined;
|
||||
const errors = this.wizard.errors.provider;
|
||||
|
||||
const { pmUserValues, pmGroupValues, propertyPairs } =
|
||||
this.propertyMappingConfiguration(provider);
|
||||
|
||||
return html`<ak-wizard-title>${msg("Configure SCIM 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-group expanded>
|
||||
<span slot="header"> ${msg("Protocol settings")} </span>
|
||||
<div slot="body" class="pf-c-form">
|
||||
<ak-text-input
|
||||
name="url"
|
||||
label=${msg("URL")}
|
||||
value="${first(provider?.url, "")}"
|
||||
required
|
||||
help=${msg("SCIM base url, usually ends in /v2.")}
|
||||
.errorMessages=${errors?.url ?? []}
|
||||
>
|
||||
</ak-text-input>
|
||||
<ak-text-input
|
||||
name="token"
|
||||
label=${msg("Token")}
|
||||
value="${first(provider?.token, "")}"
|
||||
.errorMessages=${errors?.token ?? []}
|
||||
required
|
||||
help=${msg(
|
||||
"Token to authenticate with. Currently only bearer authentication is supported.",
|
||||
)}
|
||||
>
|
||||
</ak-text-input>
|
||||
</div>
|
||||
</ak-form-group>
|
||||
<ak-form-group expanded>
|
||||
<span slot="header">${msg("User filtering")}</span>
|
||||
<div slot="body" class="pf-c-form">
|
||||
<ak-switch-input
|
||||
name="excludeUsersServiceAccount"
|
||||
?checked=${first(provider?.excludeUsersServiceAccount, true)}
|
||||
label=${msg("Exclude service accounts")}
|
||||
></ak-switch-input>
|
||||
<ak-form-element-horizontal label=${msg("Group")} name="filterGroup">
|
||||
<ak-core-group-search
|
||||
.group=${provider?.filterGroup}
|
||||
></ak-core-group-search>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg("Only sync users within the selected group.")}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
</div>
|
||||
</ak-form-group>
|
||||
<ak-form-group ?expanded=${true}>
|
||||
<span slot="header"> ${msg("Attribute mapping")} </span>
|
||||
<div slot="body" class="pf-c-form">
|
||||
<ak-multi-select
|
||||
label=${msg("User Property Mappings")}
|
||||
name="propertyMappings"
|
||||
.options=${propertyPairs}
|
||||
.values=${pmUserValues}
|
||||
.richhelp=${html`
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg("Property mappings used for user mapping.")}
|
||||
</p>
|
||||
`}
|
||||
></ak-multi-select>
|
||||
<ak-multi-select
|
||||
label=${msg("Group Property Mappings")}
|
||||
name="propertyMappingsGroup"
|
||||
.options=${propertyPairs}
|
||||
.values=${pmGroupValues}
|
||||
.richhelp=${html`
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg("Property mappings used for group creation.")}
|
||||
</p>
|
||||
`}
|
||||
></ak-multi-select>
|
||||
</div>
|
||||
</ak-form-group>
|
||||
${renderForm(
|
||||
(this.wizard.provider as SCIMProvider) ?? {},
|
||||
this.wizard.errors.provider,
|
||||
)}
|
||||
</form>`;
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,7 +102,7 @@ export class ProxyProviderFormPage extends BaseProviderForm<ProxyProvider> {
|
||||
|
||||
// prettier-ignore
|
||||
return html`
|
||||
<ak-toggle-group value=${this.mode} @ak-toggle=${setMode}>
|
||||
<ak-toggle-group value=${this.mode} @ak-toggle=${setMode} data-ouid-component-name="proxy-type-toggle">
|
||||
<option value=${ProxyMode.Proxy}>${msg("Proxy")}</option>
|
||||
<option value=${ProxyMode.ForwardSingle}>${msg("Forward auth (single application)")}</option>
|
||||
<option value=${ProxyMode.ForwardDomain}>${msg("Forward auth (domain level)")}</option>
|
||||
|
||||
@ -1,53 +1,11 @@
|
||||
import { BaseProviderForm } from "@goauthentik/admin/providers/BaseProviderForm";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/Radio";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
||||
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 {
|
||||
CoreApi,
|
||||
CoreGroupsListRequest,
|
||||
Group,
|
||||
PropertymappingsApi,
|
||||
ProvidersApi,
|
||||
SCIMMapping,
|
||||
SCIMProvider,
|
||||
} from "@goauthentik/api";
|
||||
import { ProvidersApi, SCIMProvider } from "@goauthentik/api";
|
||||
|
||||
export async function scimPropertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsProviderScimList({
|
||||
ordering: "managed",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map((m) => [m.pk, m.name, m.name, m]),
|
||||
};
|
||||
}
|
||||
|
||||
export function makeSCIMPropertyMappingsSelector(
|
||||
instanceMappings: string[] | undefined,
|
||||
defaultSelected: string,
|
||||
) {
|
||||
const localMappings = instanceMappings ? new Set(instanceMappings) : undefined;
|
||||
return localMappings
|
||||
? ([pk, _]: DualSelectPair) => localMappings.has(pk)
|
||||
: ([_0, _1, _2, mapping]: DualSelectPair<SCIMMapping>) =>
|
||||
mapping?.managed === defaultSelected;
|
||||
}
|
||||
import { renderForm } from "./SCIMProviderFormForm.js";
|
||||
|
||||
@customElement("ak-provider-scim-form")
|
||||
export class SCIMProviderFormPage extends BaseProviderForm<SCIMProvider> {
|
||||
@ -70,156 +28,8 @@ export class SCIMProviderFormPage extends BaseProviderForm<SCIMProvider> {
|
||||
}
|
||||
}
|
||||
|
||||
renderForm(): TemplateResult {
|
||||
return html` <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-group .expanded=${true}>
|
||||
<span slot="header"> ${msg("Protocol settings")} </span>
|
||||
<div slot="body" class="pf-c-form">
|
||||
<ak-form-element-horizontal label=${msg("URL")} ?required=${true} name="url">
|
||||
<input
|
||||
type="text"
|
||||
value="${first(this.instance?.url, "")}"
|
||||
class="pf-c-form-control"
|
||||
required
|
||||
/>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg("SCIM base url, usually ends in /v2.")}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal name="verifyCertificates">
|
||||
<label class="pf-c-switch">
|
||||
<input
|
||||
class="pf-c-switch__input"
|
||||
type="checkbox"
|
||||
?checked=${first(this.instance?.verifyCertificates, true)}
|
||||
/>
|
||||
<span class="pf-c-switch__toggle">
|
||||
<span class="pf-c-switch__toggle-icon">
|
||||
<i class="fas fa-check" aria-hidden="true"></i>
|
||||
</span>
|
||||
</span>
|
||||
<span class="pf-c-switch__label"
|
||||
>${msg("Verify SCIM server's certificates")}</span
|
||||
>
|
||||
</label>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${msg("Token")}
|
||||
?required=${true}
|
||||
name="token"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
value="${first(this.instance?.token, "")}"
|
||||
class="pf-c-form-control"
|
||||
required
|
||||
/>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg(
|
||||
"Token to authenticate with. Currently only bearer authentication is supported.",
|
||||
)}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
</div>
|
||||
</ak-form-group>
|
||||
<ak-form-group ?expanded=${true}>
|
||||
<span slot="header">${msg("User filtering")}</span>
|
||||
<div slot="body" class="pf-c-form">
|
||||
<ak-form-element-horizontal name="excludeUsersServiceAccount">
|
||||
<label class="pf-c-switch">
|
||||
<input
|
||||
class="pf-c-switch__input"
|
||||
type="checkbox"
|
||||
?checked=${first(this.instance?.excludeUsersServiceAccount, true)}
|
||||
/>
|
||||
<span class="pf-c-switch__toggle">
|
||||
<span class="pf-c-switch__toggle-icon">
|
||||
<i class="fas fa-check" aria-hidden="true"></i>
|
||||
</span>
|
||||
</span>
|
||||
<span class="pf-c-switch__label"
|
||||
>${msg("Exclude service accounts")}</span
|
||||
>
|
||||
</label>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal label=${msg("Group")} name="filterGroup">
|
||||
<ak-search-select
|
||||
.fetchObjects=${async (query?: string): Promise<Group[]> => {
|
||||
const args: CoreGroupsListRequest = {
|
||||
ordering: "name",
|
||||
includeUsers: false,
|
||||
};
|
||||
if (query !== undefined) {
|
||||
args.search = query;
|
||||
}
|
||||
const groups = await new CoreApi(DEFAULT_CONFIG).coreGroupsList(
|
||||
args,
|
||||
);
|
||||
return groups.results;
|
||||
}}
|
||||
.renderElement=${(group: Group): string => {
|
||||
return group.name;
|
||||
}}
|
||||
.value=${(group: Group | undefined): string | undefined => {
|
||||
return group ? group.pk : undefined;
|
||||
}}
|
||||
.selected=${(group: Group): boolean => {
|
||||
return group.pk === this.instance?.filterGroup;
|
||||
}}
|
||||
?blankable=${true}
|
||||
>
|
||||
</ak-search-select>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg("Only sync users within the selected group.")}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
</div>
|
||||
</ak-form-group>
|
||||
<ak-form-group ?expanded=${true}>
|
||||
<span slot="header"> ${msg("Attribute mapping")} </span>
|
||||
<div slot="body" class="pf-c-form">
|
||||
<ak-form-element-horizontal
|
||||
label=${msg("User Property Mappings")}
|
||||
name="propertyMappings">
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${scimPropertyMappingsProvider}
|
||||
.selector=${makeSCIMPropertyMappingsSelector(
|
||||
this.instance?.propertyMappings,
|
||||
"goauthentik.io/providers/scim/user",
|
||||
)}
|
||||
available-label=${msg("Available User Property Mappings")}
|
||||
selected-label=${msg("Selected User Property Mappings")}
|
||||
></ak-dual-select-dynamic-selected>
|
||||
</select>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg("Property mappings used to user mapping.")}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${msg("Group Property Mappings")}
|
||||
name="propertyMappingsGroup">
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${scimPropertyMappingsProvider}
|
||||
.selector=${makeSCIMPropertyMappingsSelector(
|
||||
this.instance?.propertyMappingsGroup,
|
||||
"goauthentik.io/providers/scim/group",
|
||||
)}
|
||||
available-label=${msg("Available Group Property Mappings")}
|
||||
selected-label=${msg("Selected Group Property Mappings")}
|
||||
></ak-dual-select-dynamic-selected>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg("Property mappings used to group creation.")}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
</div>
|
||||
</ak-form-group>`;
|
||||
renderForm() {
|
||||
return renderForm(this.instance ?? {}, []);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
196
web/src/admin/providers/scim/SCIMProviderFormForm.ts
Normal file
196
web/src/admin/providers/scim/SCIMProviderFormForm.ts
Normal file
@ -0,0 +1,196 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/Radio";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { html } from "lit";
|
||||
import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
import {
|
||||
CoreApi,
|
||||
CoreGroupsListRequest,
|
||||
Group,
|
||||
PropertymappingsApi,
|
||||
SCIMMapping,
|
||||
SCIMProvider,
|
||||
} from "@goauthentik/api";
|
||||
|
||||
export async function scimPropertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsProviderScimList({
|
||||
ordering: "managed",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map((m) => [m.pk, m.name, m.name, m]),
|
||||
};
|
||||
}
|
||||
|
||||
export function makeSCIMPropertyMappingsSelector(
|
||||
instanceMappings: string[] | undefined,
|
||||
defaultSelected: string,
|
||||
) {
|
||||
const localMappings = instanceMappings ? new Set(instanceMappings) : undefined;
|
||||
return localMappings
|
||||
? ([pk, _]: DualSelectPair) => localMappings.has(pk)
|
||||
: ([_0, _1, _2, mapping]: DualSelectPair<SCIMMapping>) =>
|
||||
mapping?.managed === defaultSelected;
|
||||
}
|
||||
|
||||
export function renderForm(provider?: Partial<SCIMProvider>, errors: ValidationError = {}) {
|
||||
return html`
|
||||
<ak-form-element-horizontal label=${msg("Name")} required name="name">
|
||||
<input
|
||||
type="text"
|
||||
value="${ifDefined(provider?.name)}"
|
||||
class="pf-c-form-control"
|
||||
required
|
||||
/>
|
||||
</ak-form-element-horizontal>
|
||||
|
||||
<ak-form-group expanded>
|
||||
<span slot="header"> ${msg("Protocol settings")} </span>
|
||||
<div slot="body" class="pf-c-form">
|
||||
<ak-form-element-horizontal label=${msg("URL")} required name="url">
|
||||
<input
|
||||
type="text"
|
||||
value="${first(provider?.url, "")}"
|
||||
class="pf-c-form-control"
|
||||
required
|
||||
/>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg("SCIM base url, usually ends in /v2.")}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal name="verifyCertificates">
|
||||
<label class="pf-c-switch">
|
||||
<input
|
||||
class="pf-c-switch__input"
|
||||
type="checkbox"
|
||||
?checked=${first(provider?.verifyCertificates, true)}
|
||||
/>
|
||||
<span class="pf-c-switch__toggle">
|
||||
<span class="pf-c-switch__toggle-icon">
|
||||
<i class="fas fa-check" aria-hidden="true"></i>
|
||||
</span>
|
||||
</span>
|
||||
<span class="pf-c-switch__label"
|
||||
>${msg("Verify SCIM server's certificates")}</span
|
||||
>
|
||||
</label>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal label=${msg("Token")} required name="token">
|
||||
<input
|
||||
type="text"
|
||||
value="${first(provider?.token, "")}"
|
||||
class="pf-c-form-control"
|
||||
required
|
||||
/>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg(
|
||||
"Token to authenticate with. Currently only bearer authentication is supported.",
|
||||
)}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
</div>
|
||||
</ak-form-group>
|
||||
<ak-form-group expanded>
|
||||
<span slot="header">${msg("User filtering")}</span>
|
||||
<div slot="body" class="pf-c-form">
|
||||
<ak-form-element-horizontal name="excludeUsersServiceAccount">
|
||||
<label class="pf-c-switch">
|
||||
<input
|
||||
class="pf-c-switch__input"
|
||||
type="checkbox"
|
||||
?checked=${first(provider?.excludeUsersServiceAccount, true)}
|
||||
/>
|
||||
<span class="pf-c-switch__toggle">
|
||||
<span class="pf-c-switch__toggle-icon">
|
||||
<i class="fas fa-check" aria-hidden="true"></i>
|
||||
</span>
|
||||
</span>
|
||||
<span class="pf-c-switch__label">${msg("Exclude service accounts")}</span>
|
||||
</label>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal label=${msg("Group")} name="filterGroup">
|
||||
<ak-search-select
|
||||
.fetchObjects=${async (query?: string): Promise<Group[]> => {
|
||||
const args: CoreGroupsListRequest = {
|
||||
ordering: "name",
|
||||
includeUsers: false,
|
||||
};
|
||||
if (query !== undefined) {
|
||||
args.search = query;
|
||||
}
|
||||
const groups = await new CoreApi(DEFAULT_CONFIG).coreGroupsList(args);
|
||||
return groups.results;
|
||||
}}
|
||||
.renderElement=${(group: Group): string => {
|
||||
return group.name;
|
||||
}}
|
||||
.value=${(group: Group | undefined): string | undefined => {
|
||||
return group ? group.pk : undefined;
|
||||
}}
|
||||
.selected=${(group: Group): boolean => {
|
||||
return group.pk === provider?.filterGroup;
|
||||
}}
|
||||
blankable
|
||||
>
|
||||
</ak-search-select>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg("Only sync users within the selected group.")}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
</div>
|
||||
</ak-form-group>
|
||||
|
||||
<ak-form-group expanded>
|
||||
<span slot="header"> ${msg("Attribute mapping")} </span>
|
||||
<div slot="body" class="pf-c-form">
|
||||
<ak-form-element-horizontal
|
||||
label=${msg("User Property Mappings")}
|
||||
name="propertyMappings"
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${scimPropertyMappingsProvider}
|
||||
.selector=${makeSCIMPropertyMappingsSelector(
|
||||
provider?.propertyMappings,
|
||||
"goauthentik.io/providers/scim/user",
|
||||
)}
|
||||
available-label=${msg("Available User Property Mappings")}
|
||||
selected-label=${msg("Selected User Property Mappings")}
|
||||
></ak-dual-select-dynamic-selected>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg("Property mappings used to user mapping.")}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${msg("Group Property Mappings")}
|
||||
name="propertyMappingsGroup"
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${scimPropertyMappingsProvider}
|
||||
.selector=${makeSCIMPropertyMappingsSelector(
|
||||
provider?.propertyMappingsGroup,
|
||||
"goauthentik.io/providers/scim/group",
|
||||
)}
|
||||
available-label=${msg("Available Group Property Mappings")}
|
||||
selected-label=${msg("Selected Group Property Mappings")}
|
||||
></ak-dual-select-dynamic-selected>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg("Property mappings used to group creation.")}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
</div>
|
||||
</ak-form-group>
|
||||
`;
|
||||
}
|
||||
@ -2,6 +2,11 @@ import { browser } from "@wdio/globals";
|
||||
import { match } from "ts-pattern";
|
||||
import { Key } from "webdriverio";
|
||||
|
||||
export async function doBlur(el: WebdriverIO.Element | ChainablePromiseElement) {
|
||||
const element = await el;
|
||||
browser.execute((element) => element.blur());
|
||||
}
|
||||
|
||||
export async function setSearchSelect(name: string, value: string) {
|
||||
const control = await (async () => {
|
||||
try {
|
||||
@ -38,12 +43,14 @@ export async function setSearchSelect(name: string, value: string) {
|
||||
}
|
||||
await (await button).click();
|
||||
await browser.keys(Key.Tab);
|
||||
await doBlur(control);
|
||||
}
|
||||
|
||||
export async function setTextInput(name: string, value: string) {
|
||||
const control = await $(`input[name="${name}"]`);
|
||||
await control.scrollIntoView();
|
||||
await control.setValue(value);
|
||||
await doBlur(control);
|
||||
}
|
||||
|
||||
export async function setRadio(name: string, value: string) {
|
||||
@ -52,6 +59,7 @@ export async function setRadio(name: string, value: string) {
|
||||
const item = await control.$(`label.*=${value}`).parentElement();
|
||||
await item.scrollIntoView();
|
||||
await item.click();
|
||||
await doBlur(control);
|
||||
}
|
||||
|
||||
export async function setTypeCreate(name: string, value: string | RegExp) {
|
||||
@ -73,6 +81,7 @@ export async function setTypeCreate(name: string, value: string | RegExp) {
|
||||
|
||||
await card.scrollIntoView();
|
||||
await card.click();
|
||||
await doBlur(control);
|
||||
}
|
||||
|
||||
export async function setFormGroup(name: string | RegExp, setting: "open" | "closed") {
|
||||
@ -95,6 +104,7 @@ export async function setFormGroup(name: string | RegExp, setting: "open" | "clo
|
||||
.with(["false", "open"], async () => await toggle.click())
|
||||
.with(["true", "closed"], async () => await toggle.click())
|
||||
.otherwise(async () => {});
|
||||
await doBlur(formGroup);
|
||||
}
|
||||
|
||||
export async function clickButton(name: string, ctx?: WebdriverIO.Element) {
|
||||
@ -110,4 +120,30 @@ export async function clickButton(name: string, ctx?: WebdriverIO.Element) {
|
||||
}
|
||||
await button.scrollIntoView();
|
||||
await button.click();
|
||||
await doBlur(button);
|
||||
}
|
||||
|
||||
const tap = <T>(a: T): T => {
|
||||
console.log(a);
|
||||
return a;
|
||||
};
|
||||
|
||||
export async function clickToggleGroup(name: string, value: string | RegExp) {
|
||||
const comparator =
|
||||
typeof name === "string"
|
||||
? (sample) => tap(sample) === tap(value)
|
||||
: (sample) => value.test(sample);
|
||||
|
||||
const button = await (async () => {
|
||||
for await (const button of $(`[data-ouid-component-name=${name}]`).$$(
|
||||
".pf-c-toggle-group__button",
|
||||
)) {
|
||||
if (comparator(await button.$(".pf-c-toggle-group__text").getText())) {
|
||||
return button;
|
||||
}
|
||||
}
|
||||
})();
|
||||
await button.scrollIntoView();
|
||||
await button.click();
|
||||
await doBlur(button);
|
||||
}
|
||||
|
||||
@ -9,29 +9,42 @@ import ApplicationWizardView from "../pageobjects/application-wizard.page.js";
|
||||
import ApplicationsListPage from "../pageobjects/applications-list.page.js";
|
||||
import { randomId } from "../utils/index.js";
|
||||
import { login } from "../utils/login.js";
|
||||
import { type TestSequence } from "./shared-sequences";
|
||||
import {
|
||||
simpleForwardAuthDomainProxyProviderForm,
|
||||
simpleForwardAuthProxyProviderForm,
|
||||
simpleLDAPProviderForm,
|
||||
simpleOAuth2ProviderForm,
|
||||
simpleProxyProviderForm,
|
||||
simpleRadiusProviderForm,
|
||||
simpleSAMLProviderForm,
|
||||
simpleSCIMProviderForm,
|
||||
} from "./shared-sequences.js";
|
||||
|
||||
async function reachTheProvider(title: string) {
|
||||
const newPrefix = randomId();
|
||||
const SUCCESS_MESSAGE = "Your application has been saved";
|
||||
|
||||
async function reachTheApplicationsPage() {
|
||||
await ApplicationsListPage.logout();
|
||||
await login();
|
||||
await ApplicationsListPage.open();
|
||||
await ApplicationsListPage.pause("ak-page-header");
|
||||
await expect(await ApplicationsListPage.pageHeader()).toBeDisplayed();
|
||||
await expect(await ApplicationsListPage.pageHeader()).toHaveText("Applications");
|
||||
}
|
||||
|
||||
async function fillOutTheApplication(title: string) {
|
||||
const newPrefix = randomId();
|
||||
|
||||
await (await ApplicationsListPage.startWizardButton()).click();
|
||||
await (await ApplicationWizardView.wizardTitle()).waitForDisplayed();
|
||||
await expect(await ApplicationWizardView.wizardTitle()).toHaveText("New application");
|
||||
|
||||
await (await ApplicationWizardView.app.name()).setValue(`${title} - ${newPrefix}`);
|
||||
await (await ApplicationWizardView.app.uiSettings()).scrollIntoView();
|
||||
await (await ApplicationWizardView.app.uiSettings()).click();
|
||||
await (await ApplicationWizardView.app.launchUrl()).scrollIntoView();
|
||||
await (await ApplicationWizardView.app.launchUrl()).setValue("http://example.goauthentik.io");
|
||||
|
||||
await (await ApplicationWizardView.nextButton()).click();
|
||||
return await ApplicationWizardView.pause();
|
||||
await ApplicationWizardView.pause();
|
||||
}
|
||||
|
||||
async function getCommitMessage() {
|
||||
@ -39,136 +52,45 @@ async function getCommitMessage() {
|
||||
return await ApplicationWizardView.successMessage();
|
||||
}
|
||||
|
||||
const SUCCESS_MESSAGE = "Your application has been saved";
|
||||
const EXPLICIT_CONSENT = "default-provider-authorization-explicit-consent";
|
||||
async function fillOutTheProviderAndCommit(provider: TestSequence) {
|
||||
// The wizard automagically provides a name. If it doesn't, that's a bug.
|
||||
const wizardProvider = provider.filter((p) => p.length < 2 || p[1] !== "name");
|
||||
await $("ak-wizard-page-type-create").waitForDisplayed();
|
||||
for await (const field of wizardProvider) {
|
||||
const thefunc = field[0];
|
||||
const args = field.slice(1);
|
||||
console.log(`Running ${args.join(", ")}`);
|
||||
// @ts-expect-error "This is a pretty alien call; I'm not surprised Typescript hates it."
|
||||
await thefunc.apply($, args);
|
||||
await browser.pause(1000);
|
||||
}
|
||||
|
||||
describe("Configure Applications with the Application Wizard", () => {
|
||||
it("Should configure a simple LDAP Application", async () => {
|
||||
await reachTheProvider("New LDAP Application");
|
||||
await $("ak-wizard-frame").$("footer button.pf-m-primary").click();
|
||||
await ApplicationWizardView.pause();
|
||||
await expect(await getCommitMessage()).toHaveText(SUCCESS_MESSAGE);
|
||||
}
|
||||
|
||||
await (await ApplicationWizardView.providerList()).waitForDisplayed();
|
||||
await (await ApplicationWizardView.ldapProvider).scrollIntoView();
|
||||
await (await ApplicationWizardView.ldapProvider).click();
|
||||
await (await ApplicationWizardView.nextButton()).click();
|
||||
await ApplicationWizardView.pause();
|
||||
|
||||
await ApplicationWizardView.ldap.setBindFlow("default-authentication-flow");
|
||||
await (await ApplicationWizardView.nextButton()).click();
|
||||
await ApplicationWizardView.pause();
|
||||
|
||||
await expect(await getCommitMessage()).toHaveText(SUCCESS_MESSAGE);
|
||||
async function itShouldConfigureApplicationsViaTheWizard(name: string, provider: TestSequence) {
|
||||
it(`Should successfully configure an application with a ${name} provider`, async () => {
|
||||
await reachTheApplicationsPage();
|
||||
await fillOutTheApplication(name);
|
||||
await fillOutTheProviderAndCommit(provider);
|
||||
});
|
||||
}
|
||||
|
||||
it("Should configure a simple Oauth2 Application", async () => {
|
||||
await reachTheProvider("New Oauth2 Application");
|
||||
const providers = [
|
||||
["LDAP", simpleLDAPProviderForm],
|
||||
["OAuth2", simpleOAuth2ProviderForm],
|
||||
["Radius", simpleRadiusProviderForm],
|
||||
["SAML", simpleSAMLProviderForm],
|
||||
["SCIM", simpleSCIMProviderForm],
|
||||
["Proxy", simpleProxyProviderForm],
|
||||
["Forward Auth (single application)", simpleForwardAuthProxyProviderForm],
|
||||
["Forward Auth (domain level)", simpleForwardAuthDomainProxyProviderForm],
|
||||
];
|
||||
|
||||
await (await ApplicationWizardView.providerList()).waitForDisplayed();
|
||||
await (await ApplicationWizardView.oauth2Provider).scrollIntoView();
|
||||
await (await ApplicationWizardView.oauth2Provider).click();
|
||||
|
||||
await (await ApplicationWizardView.nextButton()).click();
|
||||
await ApplicationWizardView.pause();
|
||||
|
||||
await ApplicationWizardView.oauth.setAuthorizationFlow(EXPLICIT_CONSENT);
|
||||
await (await ApplicationWizardView.nextButton()).click();
|
||||
await ApplicationWizardView.pause();
|
||||
|
||||
await expect(await getCommitMessage()).toHaveText(SUCCESS_MESSAGE);
|
||||
});
|
||||
|
||||
it("Should configure a simple SAML Application", async () => {
|
||||
await reachTheProvider("New SAML Application");
|
||||
|
||||
await (await ApplicationWizardView.providerList()).waitForDisplayed();
|
||||
await (await ApplicationWizardView.samlProvider).scrollIntoView();
|
||||
await (await ApplicationWizardView.samlProvider).click();
|
||||
|
||||
await (await ApplicationWizardView.nextButton()).click();
|
||||
await ApplicationWizardView.pause();
|
||||
|
||||
await ApplicationWizardView.saml.setAuthorizationFlow(EXPLICIT_CONSENT);
|
||||
await ApplicationWizardView.saml.acsUrl.setValue("http://example.com:8000/");
|
||||
await (await ApplicationWizardView.nextButton()).click();
|
||||
await ApplicationWizardView.pause();
|
||||
|
||||
await expect(await getCommitMessage()).toHaveText(SUCCESS_MESSAGE);
|
||||
});
|
||||
|
||||
it("Should configure a simple SCIM Application", async () => {
|
||||
await reachTheProvider("New SCIM Application");
|
||||
|
||||
await (await ApplicationWizardView.providerList()).waitForDisplayed();
|
||||
await (await ApplicationWizardView.scimProvider).scrollIntoView();
|
||||
await (await ApplicationWizardView.scimProvider).click();
|
||||
|
||||
await (await ApplicationWizardView.nextButton()).click();
|
||||
await ApplicationWizardView.pause();
|
||||
|
||||
await ApplicationWizardView.scim.url.setValue("http://example.com:8000/");
|
||||
await ApplicationWizardView.scim.token.setValue("a-very-basic-token");
|
||||
await (await ApplicationWizardView.nextButton()).click();
|
||||
await ApplicationWizardView.pause();
|
||||
|
||||
await expect(await getCommitMessage()).toHaveText(SUCCESS_MESSAGE);
|
||||
});
|
||||
|
||||
it("Should configure a simple Radius Application", async () => {
|
||||
await reachTheProvider("New Radius Application");
|
||||
|
||||
await (await ApplicationWizardView.providerList()).waitForDisplayed();
|
||||
await (await ApplicationWizardView.radiusProvider).scrollIntoView();
|
||||
await (await ApplicationWizardView.radiusProvider).click();
|
||||
|
||||
await (await ApplicationWizardView.nextButton()).click();
|
||||
await ApplicationWizardView.pause();
|
||||
|
||||
await ApplicationWizardView.radius.setAuthenticationFlow("default-authentication-flow");
|
||||
await (await ApplicationWizardView.nextButton()).click();
|
||||
await ApplicationWizardView.pause();
|
||||
|
||||
await expect(await getCommitMessage()).toHaveText(SUCCESS_MESSAGE);
|
||||
});
|
||||
|
||||
it("Should configure a simple Transparent Proxy Application", async () => {
|
||||
await reachTheProvider("New Transparent Proxy Application");
|
||||
|
||||
await (await ApplicationWizardView.providerList()).waitForDisplayed();
|
||||
await (await ApplicationWizardView.proxyProviderProxy).scrollIntoView();
|
||||
await (await ApplicationWizardView.proxyProviderProxy).click();
|
||||
await (await ApplicationWizardView.nextButton()).click();
|
||||
await ApplicationWizardView.pause();
|
||||
|
||||
await ApplicationWizardView.transparentProxy.setAuthorizationFlow(EXPLICIT_CONSENT);
|
||||
await ApplicationWizardView.transparentProxy.externalHost.setValue(
|
||||
"http://external.example.com",
|
||||
);
|
||||
await ApplicationWizardView.transparentProxy.internalHost.setValue(
|
||||
"http://internal.example.com",
|
||||
);
|
||||
|
||||
await (await ApplicationWizardView.nextButton()).click();
|
||||
await ApplicationWizardView.pause();
|
||||
|
||||
await expect(await getCommitMessage()).toHaveText(SUCCESS_MESSAGE);
|
||||
});
|
||||
|
||||
it("Should configure a simple Forward Proxy Application", async () => {
|
||||
await reachTheProvider("New Forward Proxy Application");
|
||||
|
||||
await (await ApplicationWizardView.providerList()).waitForDisplayed();
|
||||
await (await ApplicationWizardView.proxyProviderForwardsingle).scrollIntoView();
|
||||
await (await ApplicationWizardView.proxyProviderForwardsingle).click();
|
||||
await (await ApplicationWizardView.nextButton()).click();
|
||||
await ApplicationWizardView.pause();
|
||||
|
||||
await ApplicationWizardView.forwardProxy.setAuthorizationFlow(EXPLICIT_CONSENT);
|
||||
await ApplicationWizardView.forwardProxy.externalHost.setValue(
|
||||
"http://external.example.com",
|
||||
);
|
||||
|
||||
await (await ApplicationWizardView.nextButton()).click();
|
||||
await ApplicationWizardView.pause();
|
||||
|
||||
await expect(await getCommitMessage()).toHaveText(SUCCESS_MESSAGE);
|
||||
});
|
||||
describe("Configuring Applications Via the Wizard", () => {
|
||||
for (const [name, provider] of providers) {
|
||||
itShouldConfigureApplicationsViaTheWizard(name, provider());
|
||||
}
|
||||
});
|
||||
|
||||
@ -3,10 +3,16 @@ import { expect } from "@wdio/globals";
|
||||
import ProviderWizardView from "../pageobjects/provider-wizard.page.js";
|
||||
import ProvidersListPage from "../pageobjects/providers-list.page.js";
|
||||
import { login } from "../utils/login.js";
|
||||
import { type TestSequence } from "./shared-sequences";
|
||||
import {
|
||||
simpleForwardAuthDomainProxyProviderForm,
|
||||
simpleForwardAuthProxyProviderForm,
|
||||
simpleLDAPProviderForm,
|
||||
simpleOAuth2ProviderForm,
|
||||
simpleProxyProviderForm,
|
||||
simpleRadiusProviderForm,
|
||||
simpleSAMLProviderForm,
|
||||
simpleSCIMProviderForm,
|
||||
} from "./shared-sequences.js";
|
||||
|
||||
async function reachTheProvider() {
|
||||
@ -36,56 +42,39 @@ const hasProviderSuccessMessage = async () =>
|
||||
{ timeout: 1000, timeoutMsg: "Expected to see provider success message." },
|
||||
);
|
||||
|
||||
type FieldDesc = [(..._: unknown) => Promise<void>, ...unknown];
|
||||
|
||||
async function fillOutFields(fields: FieldDesc[]) {
|
||||
async function fillOutFields(fields: TestSequence) {
|
||||
for (const field of fields) {
|
||||
const thefunc = field[0];
|
||||
const args = field.slice(1);
|
||||
// @ts-expect-error "This is a pretty alien call; I'm not surprised Typescript hates it."
|
||||
await thefunc.apply($, args);
|
||||
}
|
||||
}
|
||||
|
||||
describe("Configure Oauth2 Providers", () => {
|
||||
it("Should configure a simple OAuth2 Provider", async () => {
|
||||
async function itShouldConfigureASimpleProvider(name: string, provider: TestSequence) {
|
||||
it(`Should successfully configure a ${name} provider`, async () => {
|
||||
await reachTheProvider();
|
||||
await $("ak-wizard-page-type-create").waitForDisplayed();
|
||||
await fillOutFields(simpleOAuth2ProviderForm());
|
||||
await fillOutFields(provider);
|
||||
await ProviderWizardView.pause();
|
||||
await ProviderWizardView.nextButton.click();
|
||||
await hasProviderSuccessMessage();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe("Configure LDAP Providers", () => {
|
||||
it("Should configure a simple LDAP Provider", async () => {
|
||||
await reachTheProvider();
|
||||
await $("ak-wizard-page-type-create").waitForDisplayed();
|
||||
await fillOutFields(simpleLDAPProviderForm());
|
||||
await ProviderWizardView.pause();
|
||||
await ProviderWizardView.nextButton.click();
|
||||
await hasProviderSuccessMessage();
|
||||
});
|
||||
});
|
||||
describe("Configuring Providers", () => {
|
||||
const providers = [
|
||||
["LDAP", simpleLDAPProviderForm],
|
||||
["OAuth2", simpleOAuth2ProviderForm],
|
||||
["Radius", simpleRadiusProviderForm],
|
||||
["SAML", simpleSAMLProviderForm],
|
||||
["SCIM", simpleSCIMProviderForm],
|
||||
["Proxy", simpleProxyProviderForm],
|
||||
["Forward Auth (single application)", simpleForwardAuthProxyProviderForm],
|
||||
["Forward Auth (domain level)", simpleForwardAuthDomainProxyProviderForm],
|
||||
];
|
||||
|
||||
describe("Configure Radius Providers", () => {
|
||||
it("Should configure a simple Radius Provider", async () => {
|
||||
await reachTheProvider();
|
||||
await $("ak-wizard-page-type-create").waitForDisplayed();
|
||||
await fillOutFields(simpleRadiusProviderForm());
|
||||
await ProviderWizardView.pause();
|
||||
await ProviderWizardView.nextButton.click();
|
||||
await hasProviderSuccessMessage();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Configure SAML Providers", () => {
|
||||
it("Should configure a simple Radius Provider", async () => {
|
||||
await reachTheProvider();
|
||||
await $("ak-wizard-page-type-create").waitForDisplayed();
|
||||
await fillOutFields(simpleRadiusProviderForm());
|
||||
await ProviderWizardView.pause();
|
||||
await ProviderWizardView.nextButton.click();
|
||||
await hasProviderSuccessMessage();
|
||||
});
|
||||
for (const [name, provider] of providers) {
|
||||
itShouldConfigureASimpleProvider(name, provider());
|
||||
}
|
||||
});
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import {
|
||||
clickButton,
|
||||
clickToggleGroup,
|
||||
setFormGroup,
|
||||
setSearchSelect,
|
||||
setTextInput,
|
||||
@ -10,14 +11,26 @@ import { randomId } from "../utils/index.js";
|
||||
|
||||
const newObjectName = (prefix: string) => `${prefix} - ${randomId()}`;
|
||||
|
||||
export const simpleOAuth2ProviderForm = () => [
|
||||
export type TestInteraction =
|
||||
| [typeof clickButton, ...Parameters<typeof clickButton>]
|
||||
| [typeof clickToggleGroup, ...Parameters<typeof clickToggleGroup>]
|
||||
| [typeof setFormGroup, ...Parameters<typeof setFormGroup>]
|
||||
| [typeof setSearchSelect, ...Parameters<typeof setSearchSelect>]
|
||||
| [typeof setTextInput, ...Parameters<typeof setTextInput>]
|
||||
| [typeof setTypeCreate, ...Parameters<typeof setTypeCreate>];
|
||||
|
||||
export type TestSequence = TestInteraction[];
|
||||
|
||||
export type TestProvider = () => TestSequence;
|
||||
|
||||
export const simpleOAuth2ProviderForm: TestProvider = () => [
|
||||
[setTypeCreate, "selectProviderType", "OAuth2/OpenID Provider"],
|
||||
[clickButton, "Next"],
|
||||
[setTextInput, "name", newObjectName("New Oauth2 Provider")],
|
||||
[setSearchSelect, "authorizationFlow", "default-provider-authorization-explicit-consent"],
|
||||
];
|
||||
|
||||
export const simpleLDAPProviderForm = () => [
|
||||
export const simpleLDAPProviderForm: TestProvider = () => [
|
||||
[setTypeCreate, "selectProviderType", "LDAP Provider"],
|
||||
[clickButton, "Next"],
|
||||
[setTextInput, "name", newObjectName("New LDAP Provider")],
|
||||
@ -27,9 +40,54 @@ export const simpleLDAPProviderForm = () => [
|
||||
[setSearchSelect, "invalidationFlow", "default-invalidation-flow"],
|
||||
];
|
||||
|
||||
export const simpleRadiusProviderForm = () => [
|
||||
export const simpleRadiusProviderForm: TestProvider = () => [
|
||||
[setTypeCreate, "selectProviderType", "Radius Provider"],
|
||||
[clickButton, "Next"],
|
||||
[setTextInput, "name", newObjectName("New Radius Provider")],
|
||||
[setSearchSelect, "authorizationFlow", "default-authentication-flow"],
|
||||
];
|
||||
|
||||
export const simpleSAMLProviderForm: TestProvider = () => [
|
||||
[setTypeCreate, "selectProviderType", "SAML Provider"],
|
||||
[clickButton, "Next"],
|
||||
[setTextInput, "name", newObjectName("New SAML Provider")],
|
||||
[setSearchSelect, "authorizationFlow", "default-provider-authorization-explicit-consent"],
|
||||
[setTextInput, "acsUrl", "http://example.com:8000/"],
|
||||
];
|
||||
|
||||
export const simpleSCIMProviderForm: TestProvider = () => [
|
||||
[setTypeCreate, "selectProviderType", "SCIM Provider"],
|
||||
[clickButton, "Next"],
|
||||
[setTextInput, "name", newObjectName("New SCIM Provider")],
|
||||
[setTextInput, "url", "http://example.com:8000/"],
|
||||
[setTextInput, "token", "insert-real-token-here"],
|
||||
];
|
||||
|
||||
export const simpleProxyProviderForm: TestProvider = () => [
|
||||
[setTypeCreate, "selectProviderType", "Proxy Provider"],
|
||||
[clickButton, "Next"],
|
||||
[setTextInput, "name", newObjectName("New Proxy Provider")],
|
||||
[setSearchSelect, "authorizationFlow", "default-provider-authorization-explicit-consent"],
|
||||
[clickToggleGroup, "proxy-type-toggle", "Proxy"],
|
||||
[setTextInput, "externalHost", "http://example.com:8000/"],
|
||||
[setTextInput, "internalHost", "http://example.com:8001/"],
|
||||
];
|
||||
|
||||
export const simpleForwardAuthProxyProviderForm: TestProvider = () => [
|
||||
[setTypeCreate, "selectProviderType", "Proxy Provider"],
|
||||
[clickButton, "Next"],
|
||||
[setTextInput, "name", newObjectName("New Forward Auth Provider")],
|
||||
[setSearchSelect, "authorizationFlow", "default-provider-authorization-explicit-consent"],
|
||||
[clickToggleGroup, "proxy-type-toggle", "Forward auth (single application)"],
|
||||
[setTextInput, "externalHost", "http://example.com:8000/"],
|
||||
];
|
||||
|
||||
export const simpleForwardAuthDomainProxyProviderForm: TestProvider = () => [
|
||||
[setTypeCreate, "selectProviderType", "Proxy Provider"],
|
||||
[clickButton, "Next"],
|
||||
[setTextInput, "name", newObjectName("New Forward Auth Domain Level Provider")],
|
||||
[setSearchSelect, "authorizationFlow", "default-provider-authorization-explicit-consent"],
|
||||
[clickToggleGroup, "proxy-type-toggle", "Forward auth (domain level)"],
|
||||
[setTextInput, "externalHost", "http://example.com:8000/"],
|
||||
[setTextInput, "cookieDomain", "somedomain.tld"],
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user