providers: add preview for mappings (#4254)
* preview Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * web/admin: show provider page on application page Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * use oauth2 end session url instead of direct interface Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * dont show provider page on application page for now Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * add UI for preview Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * translate and release notes Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix lint Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * separate saml api files Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * add api tests Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
@ -192,7 +192,7 @@ export class ApplicationForm extends ModelForm<Application, string> {
|
||||
<input
|
||||
type="checkbox"
|
||||
class="pf-c-check__input"
|
||||
?checked=${first(this.instance?.openInNewTab, true)}
|
||||
?checked=${first(this.instance?.openInNewTab, false)}
|
||||
/>
|
||||
<label class="pf-c-check__label"> ${t`Open in new tab`} </label>
|
||||
</div>
|
||||
|
||||
@ -122,8 +122,13 @@ export class ApplicationViewPage extends AKElement {
|
||||
<dd class="pf-c-description-list__description">
|
||||
<div class="pf-c-description-list__text">
|
||||
<a
|
||||
href="#/core/providers/${this.application
|
||||
.providerObj?.pk}"
|
||||
href=${`#/core/applications/${
|
||||
this.application.slug
|
||||
};${encodeURIComponent(
|
||||
JSON.stringify({
|
||||
page: "page-provider",
|
||||
}),
|
||||
)}`}
|
||||
>
|
||||
${this.application.providerObj?.name}
|
||||
(${this.application.providerObj?.verboseName})
|
||||
|
||||
@ -8,8 +8,6 @@ import "@goauthentik/elements/EmptyState";
|
||||
import "@goauthentik/elements/PageHeader";
|
||||
import "@goauthentik/elements/buttons/SpinnerButton";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
import { CSSResult, TemplateResult, html } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
import { ifDefined } from "lit/directives/if-defined.js";
|
||||
@ -70,25 +68,6 @@ export class ProviderViewPage extends AKElement {
|
||||
description=${ifDefined(this.provider?.verboseName)}
|
||||
>
|
||||
</ak-page-header>
|
||||
<ak-tabs>
|
||||
<section slot="page-overview" data-tab-title="${t`Overview`}">
|
||||
${this.renderProvider()}
|
||||
</section>
|
||||
<section
|
||||
slot="page-changelog"
|
||||
data-tab-title="${t`Changelog`}"
|
||||
class="pf-c-page__main-section pf-m-no-padding-mobile"
|
||||
>
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-card__body">
|
||||
<ak-object-changelog
|
||||
targetModelPk=${this.provider?.pk || ""}
|
||||
targetModelName=${this.provider?.metaModelName || ""}
|
||||
>
|
||||
</ak-object-changelog>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</ak-tabs>`;
|
||||
${this.renderProvider()}`;
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,13 +80,33 @@ export class LDAPProviderViewPage extends AKElement {
|
||||
if (!this.provider) {
|
||||
return html``;
|
||||
}
|
||||
return html`${
|
||||
this.provider?.assignedApplicationName
|
||||
? html``
|
||||
: html`<div slot="header" class="pf-c-banner pf-m-warning">
|
||||
${t`Warning: Provider is not used by an Application.`}
|
||||
</div>`
|
||||
return html` <ak-tabs>
|
||||
<section slot="page-overview" data-tab-title="${t`Overview`}">
|
||||
${this.renderTabOverview()}
|
||||
</section>
|
||||
<section
|
||||
slot="page-changelog"
|
||||
data-tab-title="${t`Changelog`}"
|
||||
class="pf-c-page__main-section pf-m-no-padding-mobile"
|
||||
>
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-card__body">
|
||||
<ak-object-changelog
|
||||
targetModelPk=${this.provider?.pk || ""}
|
||||
targetModelName=${this.provider?.metaModelName || ""}
|
||||
>
|
||||
</ak-object-changelog>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</ak-tabs>`;
|
||||
}
|
||||
|
||||
renderTabOverview(): TemplateResult {
|
||||
if (!this.provider) {
|
||||
return html``;
|
||||
}
|
||||
return html`
|
||||
${
|
||||
this.provider?.outpostSet.length < 1
|
||||
? html`<div slot="header" class="pf-c-banner pf-m-warning">
|
||||
|
||||
@ -16,6 +16,7 @@ import { t } from "@lingui/macro";
|
||||
|
||||
import { CSSResult, TemplateResult, html } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
import { until } from "lit/directives/until.js";
|
||||
|
||||
import AKGlobal from "@goauthentik/common/styles/authentik.css";
|
||||
import PFBanner from "@patternfly/patternfly/components/Banner/banner.css";
|
||||
@ -79,6 +80,35 @@ export class OAuth2ProviderViewPage extends AKElement {
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
if (!this.provider) {
|
||||
return html``;
|
||||
}
|
||||
return html` <ak-tabs>
|
||||
<section slot="page-overview" data-tab-title="${t`Overview`}">
|
||||
${this.renderTabOverview()}
|
||||
</section>
|
||||
<section slot="page-preview" data-tab-title="${t`Preview`}">
|
||||
${this.renderTabPreview()}
|
||||
</section>
|
||||
<section
|
||||
slot="page-changelog"
|
||||
data-tab-title="${t`Changelog`}"
|
||||
class="pf-c-page__main-section pf-m-no-padding-mobile"
|
||||
>
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-card__body">
|
||||
<ak-object-changelog
|
||||
targetModelPk=${this.provider?.pk || ""}
|
||||
targetModelName=${this.provider?.metaModelName || ""}
|
||||
>
|
||||
</ak-object-changelog>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</ak-tabs>`;
|
||||
}
|
||||
|
||||
renderTabOverview(): TemplateResult {
|
||||
if (!this.provider) {
|
||||
return html``;
|
||||
}
|
||||
@ -277,4 +307,30 @@ export class OAuth2ProviderViewPage extends AKElement {
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
renderTabPreview(): TemplateResult {
|
||||
if (!this.provider) {
|
||||
return html``;
|
||||
}
|
||||
return html` <div
|
||||
class="pf-c-page__main-section pf-m-no-padding-mobile pf-l-grid pf-m-gutter"
|
||||
>
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-card__title">
|
||||
${t`Example JWT payload (for currently authenticated user)`}
|
||||
</div>
|
||||
<div class="pf-c-card__body">
|
||||
${until(
|
||||
new ProvidersApi(DEFAULT_CONFIG)
|
||||
.providersOauth2PreviewUserRetrieve({
|
||||
id: this.provider?.pk,
|
||||
})
|
||||
.then((data) => {
|
||||
return html`<pre>${JSON.stringify(data.preview, null, 4)}</pre>`;
|
||||
}),
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,6 +171,32 @@ export class ProxyProviderViewPage extends AKElement {
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
if (!this.provider) {
|
||||
return html``;
|
||||
}
|
||||
return html` <ak-tabs>
|
||||
<section slot="page-overview" data-tab-title="${t`Overview`}">
|
||||
${this.renderTabOverview()}
|
||||
</section>
|
||||
<section
|
||||
slot="page-changelog"
|
||||
data-tab-title="${t`Changelog`}"
|
||||
class="pf-c-page__main-section pf-m-no-padding-mobile"
|
||||
>
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-card__body">
|
||||
<ak-object-changelog
|
||||
targetModelPk=${this.provider?.pk || ""}
|
||||
targetModelName=${this.provider?.metaModelName || ""}
|
||||
>
|
||||
</ak-object-changelog>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</ak-tabs>`;
|
||||
}
|
||||
|
||||
renderTabOverview(): TemplateResult {
|
||||
if (!this.provider) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
@ -25,12 +25,21 @@ import PFContent from "@patternfly/patternfly/components/Content/content.css";
|
||||
import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css";
|
||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
||||
import PFList from "@patternfly/patternfly/components/List/List.css";
|
||||
import PFPage from "@patternfly/patternfly/components/Page/page.css";
|
||||
import PFGrid from "@patternfly/patternfly/layouts/Grid/grid.css";
|
||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||
|
||||
import { CryptoApi, ProvidersApi, SAMLProvider } from "@goauthentik/api";
|
||||
|
||||
interface SAMLPreviewAttribute {
|
||||
attributes: {
|
||||
Name: string;
|
||||
Value: string[];
|
||||
}[];
|
||||
nameID: string;
|
||||
}
|
||||
|
||||
@customElement("ak-provider-saml-view")
|
||||
export class SAMLProviderViewPage extends AKElement {
|
||||
@property()
|
||||
@ -58,6 +67,7 @@ export class SAMLProviderViewPage extends AKElement {
|
||||
PFGrid,
|
||||
PFContent,
|
||||
PFCard,
|
||||
PFList,
|
||||
PFDescriptionList,
|
||||
PFForm,
|
||||
PFFormControl,
|
||||
@ -134,6 +144,36 @@ export class SAMLProviderViewPage extends AKElement {
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
if (!this.provider) {
|
||||
return html``;
|
||||
}
|
||||
return html` <ak-tabs>
|
||||
<section slot="page-overview" data-tab-title="${t`Overview`}">
|
||||
${this.renderTabOverview()}
|
||||
</section>
|
||||
${this.renderTabMetadata()}
|
||||
<section slot="page-preview" data-tab-title="${t`Preview`}">
|
||||
${this.renderTabPreview()}
|
||||
</section>
|
||||
<section
|
||||
slot="page-changelog"
|
||||
data-tab-title="${t`Changelog`}"
|
||||
class="pf-c-page__main-section pf-m-no-padding-mobile"
|
||||
>
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-card__body">
|
||||
<ak-object-changelog
|
||||
targetModelPk=${this.provider?.pk || ""}
|
||||
targetModelName=${this.provider?.metaModelName || ""}
|
||||
>
|
||||
</ak-object-changelog>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</ak-tabs>`;
|
||||
}
|
||||
|
||||
renderTabOverview(): TemplateResult {
|
||||
if (!this.provider) {
|
||||
return html``;
|
||||
}
|
||||
@ -220,104 +260,184 @@ export class SAMLProviderViewPage extends AKElement {
|
||||
${
|
||||
this.provider.assignedApplicationName
|
||||
? html` <div class="pf-c-card pf-l-grid__item pf-m-12-col">
|
||||
<div class="pf-c-card__title">${t`SAML Configuration`}</div>
|
||||
<div class="pf-c-card__body">
|
||||
<form class="pf-c-form">
|
||||
<div class="pf-c-form__group">
|
||||
<label class="pf-c-form__label">
|
||||
<span class="pf-c-form__label-text"
|
||||
>${t`EntityID/Issuer`}</span
|
||||
>
|
||||
</label>
|
||||
<input
|
||||
class="pf-c-form-control"
|
||||
readonly
|
||||
type="text"
|
||||
value="${ifDefined(this.provider?.issuer)}"
|
||||
/>
|
||||
</div>
|
||||
<div class="pf-c-form__group">
|
||||
<label class="pf-c-form__label">
|
||||
<span class="pf-c-form__label-text"
|
||||
>${t`SSO URL (Post)`}</span
|
||||
>
|
||||
</label>
|
||||
<input
|
||||
class="pf-c-form-control"
|
||||
readonly
|
||||
type="text"
|
||||
value="${ifDefined(this.provider.urlSsoPost)}"
|
||||
/>
|
||||
</div>
|
||||
<div class="pf-c-form__group">
|
||||
<label class="pf-c-form__label">
|
||||
<span class="pf-c-form__label-text"
|
||||
>${t`SSO URL (Redirect)`}</span
|
||||
>
|
||||
</label>
|
||||
<input
|
||||
class="pf-c-form-control"
|
||||
readonly
|
||||
type="text"
|
||||
value="${ifDefined(this.provider.urlSsoRedirect)}"
|
||||
/>
|
||||
</div>
|
||||
<div class="pf-c-form__group">
|
||||
<label class="pf-c-form__label">
|
||||
<span class="pf-c-form__label-text"
|
||||
>${t`SSO URL (IdP-initiated Login)`}</span
|
||||
>
|
||||
</label>
|
||||
<input
|
||||
class="pf-c-form-control"
|
||||
readonly
|
||||
type="text"
|
||||
value="${ifDefined(this.provider.urlSsoInit)}"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="pf-c-card__title">${t`SAML Configuration`}</div>
|
||||
<div class="pf-c-card__body">
|
||||
<form class="pf-c-form">
|
||||
<div class="pf-c-form__group">
|
||||
<label class="pf-c-form__label">
|
||||
<span class="pf-c-form__label-text"
|
||||
>${t`EntityID/Issuer`}</span
|
||||
>
|
||||
</label>
|
||||
<input
|
||||
class="pf-c-form-control"
|
||||
readonly
|
||||
type="text"
|
||||
value="${ifDefined(this.provider?.issuer)}"
|
||||
/>
|
||||
</div>
|
||||
<div class="pf-c-form__group">
|
||||
<label class="pf-c-form__label">
|
||||
<span class="pf-c-form__label-text"
|
||||
>${t`SSO URL (Post)`}</span
|
||||
>
|
||||
</label>
|
||||
<input
|
||||
class="pf-c-form-control"
|
||||
readonly
|
||||
type="text"
|
||||
value="${ifDefined(this.provider.urlSsoPost)}"
|
||||
/>
|
||||
</div>
|
||||
<div class="pf-c-form__group">
|
||||
<label class="pf-c-form__label">
|
||||
<span class="pf-c-form__label-text"
|
||||
>${t`SSO URL (Redirect)`}</span
|
||||
>
|
||||
</label>
|
||||
<input
|
||||
class="pf-c-form-control"
|
||||
readonly
|
||||
type="text"
|
||||
value="${ifDefined(this.provider.urlSsoRedirect)}"
|
||||
/>
|
||||
</div>
|
||||
<div class="pf-c-form__group">
|
||||
<label class="pf-c-form__label">
|
||||
<span class="pf-c-form__label-text"
|
||||
>${t`SSO URL (IdP-initiated Login)`}</span
|
||||
>
|
||||
</label>
|
||||
<input
|
||||
class="pf-c-form-control"
|
||||
readonly
|
||||
type="text"
|
||||
value="${ifDefined(this.provider.urlSsoInit)}"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="pf-c-card pf-l-grid__item pf-m-12-col">
|
||||
<div class="pf-c-card__title">${t`SAML Metadata`}</div>
|
||||
<div class="pf-c-card__body">
|
||||
${until(
|
||||
new ProvidersApi(DEFAULT_CONFIG)
|
||||
.providersSamlMetadataRetrieve({
|
||||
id: this.provider.pk || 0,
|
||||
})
|
||||
.then((m) => {
|
||||
return html`<ak-codemirror
|
||||
mode="xml"
|
||||
?readOnly=${true}
|
||||
value="${ifDefined(m.metadata)}"
|
||||
></ak-codemirror>`;
|
||||
}),
|
||||
)}
|
||||
</div>
|
||||
<div class="pf-c-card__footer">
|
||||
<a
|
||||
class="pf-c-button pf-m-primary"
|
||||
target="_blank"
|
||||
href=${this.provider.urlDownloadMetadata}
|
||||
>
|
||||
${t`Download`}
|
||||
</a>
|
||||
<ak-action-button
|
||||
class="pf-m-secondary"
|
||||
.apiRequest=${() => {
|
||||
return navigator.clipboard.writeText(
|
||||
this.provider?.urlDownloadMetadata || "",
|
||||
);
|
||||
}}
|
||||
>
|
||||
${t`Copy download URL`}
|
||||
</ak-action-button>
|
||||
</div>
|
||||
</div>`
|
||||
</div>`
|
||||
: html``
|
||||
}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
renderTabMetadata(): TemplateResult {
|
||||
if (!this.provider) {
|
||||
return html``;
|
||||
}
|
||||
return html`
|
||||
${this.provider.assignedApplicationName
|
||||
? html` <section slot="page-metadata" data-tab-title="${t`Metadata`}">
|
||||
<div
|
||||
class="pf-c-page__main-section pf-m-no-padding-mobile pf-l-grid pf-m-gutter"
|
||||
>
|
||||
<div class="pf-c-card pf-l-grid__item pf-m-12-col">
|
||||
<div class="pf-c-card__title">${t`SAML Metadata`}</div>
|
||||
<div class="pf-c-card__body">
|
||||
<a
|
||||
class="pf-c-button pf-m-primary"
|
||||
target="_blank"
|
||||
href=${this.provider.urlDownloadMetadata}
|
||||
>
|
||||
${t`Download`}
|
||||
</a>
|
||||
<ak-action-button
|
||||
class="pf-m-secondary"
|
||||
.apiRequest=${() => {
|
||||
return navigator.clipboard.writeText(
|
||||
this.provider?.urlDownloadMetadata || "",
|
||||
);
|
||||
}}
|
||||
>
|
||||
${t`Copy download URL`}
|
||||
</ak-action-button>
|
||||
</div>
|
||||
<div class="pf-c-card__footer">
|
||||
${until(
|
||||
new ProvidersApi(DEFAULT_CONFIG)
|
||||
.providersSamlMetadataRetrieve({
|
||||
id: this.provider.pk || 0,
|
||||
})
|
||||
.then((m) => {
|
||||
return html`<ak-codemirror
|
||||
mode="xml"
|
||||
?readOnly=${true}
|
||||
value="${ifDefined(m.metadata)}"
|
||||
></ak-codemirror>`;
|
||||
}),
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>`
|
||||
: html``}
|
||||
`;
|
||||
}
|
||||
|
||||
renderTabPreview(): TemplateResult {
|
||||
if (!this.provider) {
|
||||
return html``;
|
||||
}
|
||||
return html` <div
|
||||
class="pf-c-page__main-section pf-m-no-padding-mobile pf-l-grid pf-m-gutter"
|
||||
>
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-card__title">${t`Example SAML attributes`}</div>
|
||||
${until(
|
||||
new ProvidersApi(DEFAULT_CONFIG)
|
||||
.providersSamlPreviewUserRetrieve({
|
||||
id: this.provider?.pk,
|
||||
})
|
||||
.then((data) => {
|
||||
const d = data.preview as SAMLPreviewAttribute;
|
||||
return html`
|
||||
<div class="pf-c-card__body">
|
||||
<dl class="pf-c-description-list pf-m-2-col-on-lg">
|
||||
<div class="pf-c-description-list__group">
|
||||
<dt class="pf-c-description-list__term">
|
||||
<span class="pf-c-description-list__text"
|
||||
>${t`NameID attribute`}</span
|
||||
>
|
||||
</dt>
|
||||
<dd class="pf-c-description-list__description">
|
||||
<div class="pf-c-description-list__text">
|
||||
${d.nameID}
|
||||
</div>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="pf-c-card__body">
|
||||
<dl class="pf-c-description-list pf-m-2-col-on-lg">
|
||||
${d.attributes.map((attr) => {
|
||||
return html` <div class="pf-c-description-list__group">
|
||||
<dt class="pf-c-description-list__term">
|
||||
<span class="pf-c-description-list__text"
|
||||
>${attr.Name}</span
|
||||
>
|
||||
</dt>
|
||||
<dd class="pf-c-description-list__description">
|
||||
<div class="pf-c-description-list__text">
|
||||
<ul class="pf-c-list">
|
||||
${attr.Value.map((value) => {
|
||||
return html`
|
||||
<li><pre>${value}</pre></li>
|
||||
`;
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
</dd>
|
||||
</div>`;
|
||||
})}
|
||||
</dl>
|
||||
</div>
|
||||
`;
|
||||
}),
|
||||
)}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user