web/admin: migrate provider forms
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
7a0ebbdc53
commit
4e3701ca8d
24
swagger.yaml
24
swagger.yaml
|
@ -14652,7 +14652,6 @@ definitions:
|
||||||
Provider:
|
Provider:
|
||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
- application
|
|
||||||
- authorization_flow
|
- authorization_flow
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
@ -14664,9 +14663,6 @@ definitions:
|
||||||
title: Name
|
title: Name
|
||||||
type: string
|
type: string
|
||||||
minLength: 1
|
minLength: 1
|
||||||
application:
|
|
||||||
title: Application
|
|
||||||
type: string
|
|
||||||
authorization_flow:
|
authorization_flow:
|
||||||
title: Authorization flow
|
title: Authorization flow
|
||||||
description: Flow used when authorizing this provider.
|
description: Flow used when authorizing this provider.
|
||||||
|
@ -15456,7 +15452,6 @@ definitions:
|
||||||
OAuth2Provider:
|
OAuth2Provider:
|
||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
- application
|
|
||||||
- authorization_flow
|
- authorization_flow
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
@ -15468,9 +15463,6 @@ definitions:
|
||||||
title: Name
|
title: Name
|
||||||
type: string
|
type: string
|
||||||
minLength: 1
|
minLength: 1
|
||||||
application:
|
|
||||||
title: Application
|
|
||||||
type: string
|
|
||||||
authorization_flow:
|
authorization_flow:
|
||||||
title: Authorization flow
|
title: Authorization flow
|
||||||
description: Flow used when authorizing this provider.
|
description: Flow used when authorizing this provider.
|
||||||
|
@ -16686,7 +16678,6 @@ definitions:
|
||||||
ProxyProvider:
|
ProxyProvider:
|
||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
- application
|
|
||||||
- authorization_flow
|
- authorization_flow
|
||||||
- internal_host
|
- internal_host
|
||||||
- external_host
|
- external_host
|
||||||
|
@ -16700,9 +16691,6 @@ definitions:
|
||||||
title: Name
|
title: Name
|
||||||
type: string
|
type: string
|
||||||
minLength: 1
|
minLength: 1
|
||||||
application:
|
|
||||||
title: Application
|
|
||||||
type: string
|
|
||||||
authorization_flow:
|
authorization_flow:
|
||||||
title: Authorization flow
|
title: Authorization flow
|
||||||
description: Flow used when authorizing this provider.
|
description: Flow used when authorizing this provider.
|
||||||
|
@ -16774,7 +16762,6 @@ definitions:
|
||||||
SAMLProvider:
|
SAMLProvider:
|
||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
- application
|
|
||||||
- authorization_flow
|
- authorization_flow
|
||||||
- acs_url
|
- acs_url
|
||||||
type: object
|
type: object
|
||||||
|
@ -16787,9 +16774,6 @@ definitions:
|
||||||
title: Name
|
title: Name
|
||||||
type: string
|
type: string
|
||||||
minLength: 1
|
minLength: 1
|
||||||
application:
|
|
||||||
title: Application
|
|
||||||
type: string
|
|
||||||
authorization_flow:
|
authorization_flow:
|
||||||
title: Authorization flow
|
title: Authorization flow
|
||||||
description: Flow used when authorizing this provider.
|
description: Flow used when authorizing this provider.
|
||||||
|
@ -16892,6 +16876,14 @@ definitions:
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
x-nullable: true
|
x-nullable: true
|
||||||
|
sp_binding:
|
||||||
|
title: Service Provider Binding
|
||||||
|
description: This determines how authentik sends the response back to the
|
||||||
|
Service Provider.
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- redirect
|
||||||
|
- post
|
||||||
SAMLMetadata:
|
SAMLMetadata:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|
|
@ -4,10 +4,6 @@ export class AdminURLManager {
|
||||||
return `/administration/policies/${rest}`;
|
return `/administration/policies/${rest}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static providers(rest: string): string {
|
|
||||||
return `/administration/providers/${rest}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static stages(rest: string): string {
|
static stages(rest: string): string {
|
||||||
return `/administration/stages/${rest}`;
|
return `/administration/stages/${rest}`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,12 +72,14 @@ export class GroupForm extends Form<Group> {
|
||||||
?required=${true}
|
?required=${true}
|
||||||
name="users">
|
name="users">
|
||||||
<select class="pf-c-form-control" multiple>
|
<select class="pf-c-form-control" multiple>
|
||||||
${until(new CoreApi(DEFAULT_CONFIG).coreUsersList({}).then(users => {
|
${until(new CoreApi(DEFAULT_CONFIG).coreUsersList({
|
||||||
|
ordering: "username",
|
||||||
|
}).then(users => {
|
||||||
return users.results.map(user => {
|
return users.results.map(user => {
|
||||||
const selected = Array.from(this.group?.users || []).some(su => {
|
const selected = Array.from(this.group?.users || []).some(su => {
|
||||||
return su == user.pk;
|
return su == user.pk;
|
||||||
});
|
});
|
||||||
return html`<option value=${ifDefined(user.pk)} ?selected=${selected}>${user.username}</option>`;
|
return html`<option value=${ifDefined(user.pk)} ?selected=${selected}>${user.username} (${user.name})</option>`;
|
||||||
});
|
});
|
||||||
}))}
|
}))}
|
||||||
</select>
|
</select>
|
||||||
|
|
|
@ -77,10 +77,7 @@ export class ServiceConnectionDockerForm extends Form<DockerServiceConnection> {
|
||||||
ordering: "pk"
|
ordering: "pk"
|
||||||
}).then(certs => {
|
}).then(certs => {
|
||||||
return certs.results.map(cert => {
|
return certs.results.map(cert => {
|
||||||
const selected = Array.from(this.sc?.tlsVerification || []).some(sp => {
|
return html`<option value=${ifDefined(cert.pk)} ?selected=${this.sc?.tlsVerification === cert.pk}>${cert.name}</option>`;
|
||||||
return sp == cert.pk;
|
|
||||||
});
|
|
||||||
return html`<option value=${ifDefined(cert.pk)} ?selected=${selected}>${cert.name}</option>`;
|
|
||||||
});
|
});
|
||||||
}))}
|
}))}
|
||||||
</select>
|
</select>
|
||||||
|
@ -96,10 +93,7 @@ export class ServiceConnectionDockerForm extends Form<DockerServiceConnection> {
|
||||||
ordering: "pk"
|
ordering: "pk"
|
||||||
}).then(certs => {
|
}).then(certs => {
|
||||||
return certs.results.map(cert => {
|
return certs.results.map(cert => {
|
||||||
const selected = Array.from(this.sc?.tlsAuthentication || []).some(sp => {
|
return html`<option value=${ifDefined(cert.pk)} ?selected=${this.sc?.tlsAuthentication === cert.pk}>${cert.name}</option>`;
|
||||||
return sp == cert.pk;
|
|
||||||
});
|
|
||||||
return html`<option value=${ifDefined(cert.pk)} ?selected=${selected}>${cert.name}</option>`;
|
|
||||||
});
|
});
|
||||||
}))}
|
}))}
|
||||||
</select>
|
</select>
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { DEFAULT_CONFIG } from "../../api/Config";
|
||||||
import { Form } from "../../elements/forms/Form";
|
import { Form } from "../../elements/forms/Form";
|
||||||
import { ifDefined } from "lit-html/directives/if-defined";
|
import { ifDefined } from "lit-html/directives/if-defined";
|
||||||
import "../../elements/forms/HorizontalFormElement";
|
import "../../elements/forms/HorizontalFormElement";
|
||||||
|
import "../../elements/CodeMirror";
|
||||||
|
|
||||||
@customElement("ak-property-mapping-ldap-form")
|
@customElement("ak-property-mapping-ldap-form")
|
||||||
export class PropertyMappingLDAPForm extends Form<LDAPPropertyMapping> {
|
export class PropertyMappingLDAPForm extends Form<LDAPPropertyMapping> {
|
||||||
|
@ -60,7 +61,7 @@ export class PropertyMappingLDAPForm extends Form<LDAPPropertyMapping> {
|
||||||
<ak-form-element-horizontal
|
<ak-form-element-horizontal
|
||||||
label=${gettext("Expression")}
|
label=${gettext("Expression")}
|
||||||
name="expression">
|
name="expression">
|
||||||
<ak-codemirror mode="python" value="${this.mapping?.expression}">
|
<ak-codemirror mode="python" value="${ifDefined(this.mapping?.expression)}">
|
||||||
</ak-codemirror>
|
</ak-codemirror>
|
||||||
<p class="pf-c-form__helper-text">
|
<p class="pf-c-form__helper-text">
|
||||||
Expression using Python. See <a href="https://goauthentik.io/docs/property-mappings/expression/">here</a> for a list of all variables.
|
Expression using Python. See <a href="https://goauthentik.io/docs/property-mappings/expression/">here</a> for a list of all variables.
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { DEFAULT_CONFIG } from "../../api/Config";
|
||||||
import { Form } from "../../elements/forms/Form";
|
import { Form } from "../../elements/forms/Form";
|
||||||
import { ifDefined } from "lit-html/directives/if-defined";
|
import { ifDefined } from "lit-html/directives/if-defined";
|
||||||
import "../../elements/forms/HorizontalFormElement";
|
import "../../elements/forms/HorizontalFormElement";
|
||||||
|
import "../../elements/CodeMirror";
|
||||||
|
|
||||||
@customElement("ak-property-mapping-saml-form")
|
@customElement("ak-property-mapping-saml-form")
|
||||||
export class PropertyMappingLDAPForm extends Form<SAMLPropertyMapping> {
|
export class PropertyMappingLDAPForm extends Form<SAMLPropertyMapping> {
|
||||||
|
@ -62,7 +63,7 @@ export class PropertyMappingLDAPForm extends Form<SAMLPropertyMapping> {
|
||||||
<ak-form-element-horizontal
|
<ak-form-element-horizontal
|
||||||
label=${gettext("Friendly Name")}
|
label=${gettext("Friendly Name")}
|
||||||
name="friendlyName">
|
name="friendlyName">
|
||||||
<input type="text" value="${ifDefined(this.mapping?.friendlyName)}" class="pf-c-form-control">
|
<input type="text" value="${ifDefined(this.mapping?.friendlyName || "")}" class="pf-c-form-control">
|
||||||
<p class="pf-c-form__helper-text">
|
<p class="pf-c-form__helper-text">
|
||||||
${gettext("Optionally set the `FriendlyName` value of the Assertion attribute.")}
|
${gettext("Optionally set the `FriendlyName` value of the Assertion attribute.")}
|
||||||
</p>
|
</p>
|
||||||
|
@ -70,7 +71,7 @@ export class PropertyMappingLDAPForm extends Form<SAMLPropertyMapping> {
|
||||||
<ak-form-element-horizontal
|
<ak-form-element-horizontal
|
||||||
label=${gettext("Expression")}
|
label=${gettext("Expression")}
|
||||||
name="expression">
|
name="expression">
|
||||||
<ak-codemirror mode="python" value="${this.mapping?.expression}">
|
<ak-codemirror mode="python" value="${ifDefined(this.mapping?.expression)}">
|
||||||
</ak-codemirror>
|
</ak-codemirror>
|
||||||
<p class="pf-c-form__helper-text">
|
<p class="pf-c-form__helper-text">
|
||||||
Expression using Python. See <a href="https://goauthentik.io/docs/property-mappings/expression/">here</a> for a list of all variables.
|
Expression using Python. See <a href="https://goauthentik.io/docs/property-mappings/expression/">here</a> for a list of all variables.
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { DEFAULT_CONFIG } from "../../api/Config";
|
||||||
import { Form } from "../../elements/forms/Form";
|
import { Form } from "../../elements/forms/Form";
|
||||||
import { ifDefined } from "lit-html/directives/if-defined";
|
import { ifDefined } from "lit-html/directives/if-defined";
|
||||||
import "../../elements/forms/HorizontalFormElement";
|
import "../../elements/forms/HorizontalFormElement";
|
||||||
|
import "../../elements/CodeMirror";
|
||||||
|
|
||||||
@customElement("ak-property-mapping-scope-form")
|
@customElement("ak-property-mapping-scope-form")
|
||||||
export class PropertyMappingScopeForm extends Form<ScopeMapping> {
|
export class PropertyMappingScopeForm extends Form<ScopeMapping> {
|
||||||
|
@ -67,7 +68,7 @@ export class PropertyMappingScopeForm extends Form<ScopeMapping> {
|
||||||
<ak-form-element-horizontal
|
<ak-form-element-horizontal
|
||||||
label=${gettext("Expression")}
|
label=${gettext("Expression")}
|
||||||
name="expression">
|
name="expression">
|
||||||
<ak-codemirror mode="python" value="${this.mapping?.expression}">
|
<ak-codemirror mode="python" value="${ifDefined(this.mapping?.expression)}">
|
||||||
</ak-codemirror>
|
</ak-codemirror>
|
||||||
<p class="pf-c-form__helper-text">
|
<p class="pf-c-form__helper-text">
|
||||||
Expression using Python. See <a href="https://goauthentik.io/docs/property-mappings/expression/">here</a> for a list of all variables.
|
Expression using Python. See <a href="https://goauthentik.io/docs/property-mappings/expression/">here</a> for a list of all variables.
|
||||||
|
|
|
@ -3,16 +3,20 @@ import { customElement, html, property, TemplateResult } from "lit-element";
|
||||||
import { AKResponse } from "../../api/Client";
|
import { AKResponse } from "../../api/Client";
|
||||||
import { TablePage } from "../../elements/table/TablePage";
|
import { TablePage } from "../../elements/table/TablePage";
|
||||||
|
|
||||||
import "../../elements/buttons/ModalButton";
|
|
||||||
import "../../elements/buttons/SpinnerButton";
|
import "../../elements/buttons/SpinnerButton";
|
||||||
import "../../elements/buttons/Dropdown";
|
import "../../elements/buttons/Dropdown";
|
||||||
import "../../elements/forms/DeleteForm";
|
import "../../elements/forms/DeleteForm";
|
||||||
|
import "../../elements/forms/ModalForm";
|
||||||
|
import "../../elements/forms/ProxyForm";
|
||||||
|
import "./oauth2/OAuth2ProviderForm";
|
||||||
|
import "./proxy/ProxyProviderForm";
|
||||||
|
import "./saml/SAMLProviderForm";
|
||||||
import { TableColumn } from "../../elements/table/Table";
|
import { TableColumn } from "../../elements/table/Table";
|
||||||
import { until } from "lit-html/directives/until";
|
import { until } from "lit-html/directives/until";
|
||||||
import { PAGE_SIZE } from "../../constants";
|
import { PAGE_SIZE } from "../../constants";
|
||||||
import { Provider, ProvidersApi } from "authentik-api";
|
import { Provider, ProvidersApi } from "authentik-api";
|
||||||
import { DEFAULT_CONFIG } from "../../api/Config";
|
import { DEFAULT_CONFIG } from "../../api/Config";
|
||||||
import { AdminURLManager } from "../../api/legacy";
|
import { ifDefined } from "lit-html/directives/if-defined";
|
||||||
|
|
||||||
@customElement("ak-provider-list")
|
@customElement("ak-provider-list")
|
||||||
export class ProviderListPage extends TablePage<Provider> {
|
export class ProviderListPage extends TablePage<Provider> {
|
||||||
|
@ -63,12 +67,29 @@ export class ProviderListPage extends TablePage<Provider> {
|
||||||
${gettext("Warning: Provider not assigned to any application.")}`,
|
${gettext("Warning: Provider not assigned to any application.")}`,
|
||||||
html`${item.verboseName}`,
|
html`${item.verboseName}`,
|
||||||
html`
|
html`
|
||||||
<ak-modal-button href="${AdminURLManager.providers(`${item.pk}/update/`)}">
|
<ak-forms-modal>
|
||||||
<ak-spinner-button slot="trigger" class="pf-m-secondary">
|
<span slot="submit">
|
||||||
|
${gettext("Update")}
|
||||||
|
</span>
|
||||||
|
<span slot="header">
|
||||||
|
${gettext(`Update ${item.verboseName}`)}
|
||||||
|
</span>
|
||||||
|
<ak-proxy-form
|
||||||
|
slot="form"
|
||||||
|
.args=${{
|
||||||
|
"providerUUID": item.pk
|
||||||
|
}}
|
||||||
|
type=${ifDefined(item.objectType)}
|
||||||
|
.typeMap=${{
|
||||||
|
"oauth2": "ak-provider-oauth2-form",
|
||||||
|
"saml": "ak-provider-saml-form",
|
||||||
|
"proxy": "ak-provider-proxy-form",
|
||||||
|
}}>
|
||||||
|
</ak-proxy-form>
|
||||||
|
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||||
${gettext("Edit")}
|
${gettext("Edit")}
|
||||||
</ak-spinner-button>
|
</button>
|
||||||
<div slot="modal"></div>
|
</ak-forms-modal>
|
||||||
</ak-modal-button>
|
|
||||||
<ak-forms-delete
|
<ak-forms-delete
|
||||||
.obj=${item}
|
.obj=${item}
|
||||||
objectLabel=${gettext("Source")}
|
objectLabel=${gettext("Source")}
|
||||||
|
@ -95,12 +116,22 @@ export class ProviderListPage extends TablePage<Provider> {
|
||||||
${until(new ProvidersApi(DEFAULT_CONFIG).providersAllTypes({}).then((types) => {
|
${until(new ProvidersApi(DEFAULT_CONFIG).providersAllTypes({}).then((types) => {
|
||||||
return types.map((type) => {
|
return types.map((type) => {
|
||||||
return html`<li>
|
return html`<li>
|
||||||
<ak-modal-button href="${type.link}">
|
<ak-forms-modal>
|
||||||
<button slot="trigger" class="pf-c-dropdown__menu-item">${type.name}<br>
|
<span slot="submit">
|
||||||
|
${gettext("Create")}
|
||||||
|
</span>
|
||||||
|
<span slot="header">
|
||||||
|
${gettext(`Create ${type.name}`)}
|
||||||
|
</span>
|
||||||
|
<ak-proxy-form
|
||||||
|
slot="form"
|
||||||
|
type=${type.link}>
|
||||||
|
</ak-proxy-form>
|
||||||
|
<button slot="trigger" class="pf-c-dropdown__menu-item">
|
||||||
|
${type.name}<br>
|
||||||
<small>${type.description}</small>
|
<small>${type.description}</small>
|
||||||
</button>
|
</button>
|
||||||
<div slot="modal"></div>
|
</ak-forms-modal>
|
||||||
</ak-modal-button>
|
|
||||||
</li>`;
|
</li>`;
|
||||||
});
|
});
|
||||||
}), html`<ak-spinner></ak-spinner>`)}
|
}), html`<ak-spinner></ak-spinner>`)}
|
||||||
|
|
|
@ -4,9 +4,9 @@ import "../../elements/buttons/ModalButton";
|
||||||
import "../../elements/buttons/SpinnerButton";
|
import "../../elements/buttons/SpinnerButton";
|
||||||
import "../../elements/EmptyState";
|
import "../../elements/EmptyState";
|
||||||
|
|
||||||
import "./SAMLProviderViewPage";
|
import "./saml/SAMLProviderViewPage";
|
||||||
import "./OAuth2ProviderViewPage";
|
import "./oauth2/OAuth2ProviderViewPage";
|
||||||
import "./ProxyProviderViewPage";
|
import "./proxy/ProxyProviderViewPage";
|
||||||
import { Provider, ProvidersApi } from "authentik-api";
|
import { Provider, ProvidersApi } from "authentik-api";
|
||||||
import { DEFAULT_CONFIG } from "../../api/Config";
|
import { DEFAULT_CONFIG } from "../../api/Config";
|
||||||
import { ifDefined } from "lit-html/directives/if-defined";
|
import { ifDefined } from "lit-html/directives/if-defined";
|
||||||
|
|
|
@ -0,0 +1,206 @@
|
||||||
|
import { CryptoApi, FlowDesignationEnum, FlowsApi, OAuth2Provider, OAuth2ProviderClientTypeEnum, OAuth2ProviderIssuerModeEnum, OAuth2ProviderJwtAlgEnum, OAuth2ProviderSubModeEnum, PropertymappingsApi, ProvidersApi } from "authentik-api";
|
||||||
|
import { gettext } from "django";
|
||||||
|
import { customElement, property } from "lit-element";
|
||||||
|
import { html, TemplateResult } from "lit-html";
|
||||||
|
import { DEFAULT_CONFIG } from "../../../api/Config";
|
||||||
|
import { Form } from "../../../elements/forms/Form";
|
||||||
|
import { until } from "lit-html/directives/until";
|
||||||
|
import { ifDefined } from "lit-html/directives/if-defined";
|
||||||
|
import "../../../elements/forms/HorizontalFormElement";
|
||||||
|
|
||||||
|
@customElement("ak-provider-oauth2-form")
|
||||||
|
export class OAuth2ProviderFormPage extends Form<OAuth2Provider> {
|
||||||
|
|
||||||
|
set providerUUID(value: number) {
|
||||||
|
new ProvidersApi(DEFAULT_CONFIG).providersOauth2Read({
|
||||||
|
id: value,
|
||||||
|
}).then(provider => {
|
||||||
|
this.provider = provider;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@property({attribute: false})
|
||||||
|
provider?: OAuth2Provider;
|
||||||
|
|
||||||
|
getSuccessMessage(): string {
|
||||||
|
if (this.provider) {
|
||||||
|
return gettext("Successfully updated provider.");
|
||||||
|
} else {
|
||||||
|
return gettext("Successfully created provider.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
send = (data: OAuth2Provider): Promise<OAuth2Provider> => {
|
||||||
|
if (this.provider) {
|
||||||
|
return new ProvidersApi(DEFAULT_CONFIG).providersOauth2Update({
|
||||||
|
id: this.provider.pk || 0,
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return new ProvidersApi(DEFAULT_CONFIG).providersOauth2Create({
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
renderForm(): TemplateResult {
|
||||||
|
return html`<form class="pf-c-form pf-m-horizontal">
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Name")}
|
||||||
|
?required=${true}
|
||||||
|
name="name">
|
||||||
|
<input type="text" value="${ifDefined(this.provider?.name)}" class="pf-c-form-control" required>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Authorization flow")}
|
||||||
|
?required=${true}
|
||||||
|
name="authorizationFlow">
|
||||||
|
<select class="pf-c-form-control">
|
||||||
|
${until(new FlowsApi(DEFAULT_CONFIG).flowsInstancesList({
|
||||||
|
ordering: "pk",
|
||||||
|
designation: FlowDesignationEnum.Authorization,
|
||||||
|
}).then(flows => {
|
||||||
|
return flows.results.map(flow => {
|
||||||
|
return html`<option value=${ifDefined(flow.pk)} ?selected=${this.provider?.authorizationFlow === flow.pk}>${flow.name}</option>`;
|
||||||
|
});
|
||||||
|
}))}
|
||||||
|
</select>
|
||||||
|
<p class="pf-c-form__helper-text">${gettext("Flow used when authorizing this provider.")}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Client type")}
|
||||||
|
?required=${true}
|
||||||
|
name="clientType">
|
||||||
|
<select class="pf-c-form-control">
|
||||||
|
<option value=${OAuth2ProviderClientTypeEnum.Confidential} ?selected=${this.provider?.clientType === OAuth2ProviderClientTypeEnum.Confidential}>
|
||||||
|
${gettext("Confidential")}
|
||||||
|
</option>
|
||||||
|
<option value=${OAuth2ProviderClientTypeEnum.Public} ?selected=${this.provider?.clientType === OAuth2ProviderClientTypeEnum.Public}>
|
||||||
|
${gettext("Public")}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<p class="pf-c-form__helper-text">${gettext("Confidential clients are capable of maintaining the confidentiality of their credentials. Public clients are incapable.")}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Client ID")}
|
||||||
|
?required=${true}
|
||||||
|
name="clientId">
|
||||||
|
<input type="text" value="${ifDefined(this.provider?.clientId)}" class="pf-c-form-control" required>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Client Secret")}
|
||||||
|
name="clientSecret">
|
||||||
|
<input type="text" value="${ifDefined(this.provider?.clientSecret /* TODO: Generate secret */)}" class="pf-c-form-control">
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Token validity")}
|
||||||
|
?required=${true}
|
||||||
|
name="tokenValidity">
|
||||||
|
<input type="text" value="${this.provider?.tokenValidity || "minutes=10"}" class="pf-c-form-control" required>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("JWT Algorithm")}
|
||||||
|
?required=${true}
|
||||||
|
name="jwtAlg">
|
||||||
|
<select class="pf-c-form-control">
|
||||||
|
<option value=${OAuth2ProviderJwtAlgEnum.Rs256} ?selected=${this.provider?.jwtAlg === OAuth2ProviderJwtAlgEnum.Rs256}>
|
||||||
|
${gettext("RS256 (Asymmetric Encryption)")}
|
||||||
|
</option>
|
||||||
|
<option value=${OAuth2ProviderJwtAlgEnum.Hs256} ?selected=${this.provider?.jwtAlg === OAuth2ProviderJwtAlgEnum.Hs256}>
|
||||||
|
${gettext("HS256 (Symmetric Encryption)")}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<p class="pf-c-form__helper-text">${gettext("Algorithm used to sign the JWT Tokens.")}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Scopes")}
|
||||||
|
?required=${true}
|
||||||
|
name="propertyMappings">
|
||||||
|
<select class="pf-c-form-control" multiple>
|
||||||
|
${until(new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsScopeList({
|
||||||
|
ordering: "scope_name"
|
||||||
|
}).then(scopes => {
|
||||||
|
return scopes.results.map(scope => {
|
||||||
|
const selected = Array.from(this.provider?.propertyMappings || []).some(su => {
|
||||||
|
return su == scope.pk;
|
||||||
|
});
|
||||||
|
return html`<option value=${ifDefined(scope.pk)} ?selected=${selected}>${scope.name}</option>`;
|
||||||
|
});
|
||||||
|
}))}
|
||||||
|
</select>
|
||||||
|
<p class="pf-c-form__helper-text">${gettext("Select which scopes can be used by the client. The client stil has to specify the scope to access the data.")}</p>
|
||||||
|
<p class="pf-c-form__helper-text">${gettext("Hold control/command to select multiple items.")}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("RSA Key")}
|
||||||
|
?required=${true}
|
||||||
|
name="rsaKey">
|
||||||
|
<select class="pf-c-form-control">
|
||||||
|
${until(new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsList({
|
||||||
|
ordering: "pk",
|
||||||
|
hasKey: "true",
|
||||||
|
}).then(keys => {
|
||||||
|
return keys.results.map(key => {
|
||||||
|
return html`<option value=${ifDefined(key.pk)} ?selected=${this.provider?.rsaKey === key.pk}>${key.name}</option>`;
|
||||||
|
});
|
||||||
|
}))}
|
||||||
|
</select>
|
||||||
|
<p class="pf-c-form__helper-text">${gettext("Key used to sign the tokens. Only required when JWT Algorithm is set to RS256.")}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Redirect URIs")}
|
||||||
|
name="redirectUris">
|
||||||
|
<textarea class="pf-c-form-control">${this.provider?.redirectUris}</textarea>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Subject mode")}
|
||||||
|
?required=${true}
|
||||||
|
name="subMode">
|
||||||
|
<select class="pf-c-form-control">
|
||||||
|
<option value="${OAuth2ProviderSubModeEnum.HashedUserId}" ?selected=${this.provider?.subMode === OAuth2ProviderSubModeEnum.HashedUserId}>
|
||||||
|
${gettext("Based on the Hashed User ID")}
|
||||||
|
</option>
|
||||||
|
<option value="${OAuth2ProviderSubModeEnum.UserUsername}" ?selected=${this.provider?.subMode === OAuth2ProviderSubModeEnum.UserUsername}>
|
||||||
|
${gettext("Based on the username")}
|
||||||
|
</option>
|
||||||
|
<option value="${OAuth2ProviderSubModeEnum.UserEmail}" ?selected=${this.provider?.subMode === OAuth2ProviderSubModeEnum.UserEmail}>
|
||||||
|
${gettext("Based on the User's Email. This is recommended over the UPN method.")}
|
||||||
|
</option>
|
||||||
|
<option value="${OAuth2ProviderSubModeEnum.UserUpn}" ?selected=${this.provider?.subMode === OAuth2ProviderSubModeEnum.UserUpn}>
|
||||||
|
${gettext("Based on the User's UPN, only works if user has a 'upn' attribute set. Use this method only if you have different UPN and Mail domains.")}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<p class="pf-c-form__helper-text">
|
||||||
|
${gettext("Configure what data should be used as unique User Identifier. For most cases, the default should be fine.")}
|
||||||
|
</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal name="includeClaimsInIdToken">
|
||||||
|
<div class="pf-c-check">
|
||||||
|
<input type="checkbox" class="pf-c-check__input" ?checked=${this.provider?.includeClaimsInIdToken || false}>
|
||||||
|
<label class="pf-c-check__label">
|
||||||
|
${gettext("Include claims in id_token")}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<p class="pf-c-form__helper-text">${gettext("Include User claims from scopes in the id_token, for applications that don't access the userinfo endpoint.")}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Issuer mode")}
|
||||||
|
?required=${true}
|
||||||
|
name="issuerMode">
|
||||||
|
<select class="pf-c-form-control">
|
||||||
|
<option value="${OAuth2ProviderIssuerModeEnum.PerProvider}" ?selected=${this.provider?.issuerMode === OAuth2ProviderIssuerModeEnum.PerProvider}>
|
||||||
|
${gettext("Each provider has a different issuer, based on the application slug.")}
|
||||||
|
</option>
|
||||||
|
<option value="${OAuth2ProviderIssuerModeEnum.Global}" ?selected=${this.provider?.issuerMode === OAuth2ProviderIssuerModeEnum.Global}>
|
||||||
|
${gettext("Same identifier is used for all providers")}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<p class="pf-c-form__helper-text">
|
||||||
|
${gettext("Configure how the issuer field of the ID Token should be filled.")}
|
||||||
|
</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
</form>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -9,23 +9,23 @@ import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList
|
||||||
import PFSizing from "@patternfly/patternfly/utilities/Sizing/sizing.css";
|
import PFSizing from "@patternfly/patternfly/utilities/Sizing/sizing.css";
|
||||||
import PFFlex from "@patternfly/patternfly/utilities/Flex/flex.css";
|
import PFFlex from "@patternfly/patternfly/utilities/Flex/flex.css";
|
||||||
import PFDisplay from "@patternfly/patternfly/utilities/Display/display.css";
|
import PFDisplay from "@patternfly/patternfly/utilities/Display/display.css";
|
||||||
import AKGlobal from "../../authentik.css";
|
import AKGlobal from "../../../authentik.css";
|
||||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
||||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
||||||
|
|
||||||
import "../../elements/buttons/ModalButton";
|
import "../../../elements/buttons/ModalButton";
|
||||||
import "../../elements/buttons/SpinnerButton";
|
import "../../../elements/buttons/SpinnerButton";
|
||||||
import "../../elements/CodeMirror";
|
import "../../../elements/CodeMirror";
|
||||||
import "../../elements/Tabs";
|
import "../../../elements/Tabs";
|
||||||
import "../../elements/events/ObjectChangelog";
|
import "../../../elements/events/ObjectChangelog";
|
||||||
import "./RelatedApplicationButton";
|
import "../RelatedApplicationButton";
|
||||||
import { Page } from "../../elements/Page";
|
import "./OAuth2ProviderForm";
|
||||||
import { convertToTitle } from "../../utils";
|
import { Page } from "../../../elements/Page";
|
||||||
|
import { convertToTitle } from "../../../utils";
|
||||||
import { OAuth2Provider, OAuth2ProviderSetupURLs, ProvidersApi } from "authentik-api";
|
import { OAuth2Provider, OAuth2ProviderSetupURLs, ProvidersApi } from "authentik-api";
|
||||||
import { DEFAULT_CONFIG } from "../../api/Config";
|
import { DEFAULT_CONFIG } from "../../../api/Config";
|
||||||
import { AdminURLManager } from "../../api/legacy";
|
import { EVENT_REFRESH } from "../../../constants";
|
||||||
import { EVENT_REFRESH } from "../../constants";
|
|
||||||
|
|
||||||
@customElement("ak-provider-oauth2-view")
|
@customElement("ak-provider-oauth2-view")
|
||||||
export class OAuth2ProviderViewPage extends Page {
|
export class OAuth2ProviderViewPage extends Page {
|
||||||
|
@ -128,12 +128,21 @@ export class OAuth2ProviderViewPage extends Page {
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
<div class="pf-c-card__footer">
|
<div class="pf-c-card__footer">
|
||||||
<ak-modal-button href="${AdminURLManager.providers(`${this.provider.pk}/update/`)}">
|
<ak-forms-modal>
|
||||||
<ak-spinner-button slot="trigger" class="pf-m-primary">
|
<span slot="submit">
|
||||||
|
${gettext("Update")}
|
||||||
|
</span>
|
||||||
|
<span slot="header">
|
||||||
|
${gettext("Update OAuth2 Provider")}
|
||||||
|
</span>
|
||||||
|
<ak-provider-oauth2-form
|
||||||
|
slot="form"
|
||||||
|
.providerUUID=${this.provider.pk || 0}>
|
||||||
|
</ak-provider-oauth2-form>
|
||||||
|
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||||
${gettext("Edit")}
|
${gettext("Edit")}
|
||||||
</ak-spinner-button>
|
</button>
|
||||||
<div slot="modal"></div>
|
</ak-forms-modal>
|
||||||
</ak-modal-button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -0,0 +1,139 @@
|
||||||
|
import { CryptoApi, FlowDesignationEnum, FlowsApi, ProvidersApi, ProxyProvider } from "authentik-api";
|
||||||
|
import { gettext } from "django";
|
||||||
|
import { customElement, property } from "lit-element";
|
||||||
|
import { html, TemplateResult } from "lit-html";
|
||||||
|
import { DEFAULT_CONFIG } from "../../../api/Config";
|
||||||
|
import { Form } from "../../../elements/forms/Form";
|
||||||
|
import { until } from "lit-html/directives/until";
|
||||||
|
import { ifDefined } from "lit-html/directives/if-defined";
|
||||||
|
import "../../../elements/forms/HorizontalFormElement";
|
||||||
|
|
||||||
|
@customElement("ak-provider-proxy-form")
|
||||||
|
export class ProxyProviderFormPage extends Form<ProxyProvider> {
|
||||||
|
|
||||||
|
set providerUUID(value: number) {
|
||||||
|
new ProvidersApi(DEFAULT_CONFIG).providersProxyRead({
|
||||||
|
id: value,
|
||||||
|
}).then(provider => {
|
||||||
|
this.provider = provider;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@property({attribute: false})
|
||||||
|
provider?: ProxyProvider;
|
||||||
|
|
||||||
|
getSuccessMessage(): string {
|
||||||
|
if (this.provider) {
|
||||||
|
return gettext("Successfully updated provider.");
|
||||||
|
} else {
|
||||||
|
return gettext("Successfully created provider.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
send = (data: ProxyProvider): Promise<ProxyProvider> => {
|
||||||
|
if (this.provider) {
|
||||||
|
return new ProvidersApi(DEFAULT_CONFIG).providersProxyUpdate({
|
||||||
|
id: this.provider.pk || 0,
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return new ProvidersApi(DEFAULT_CONFIG).providersProxyCreate({
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
renderForm(): TemplateResult {
|
||||||
|
return html`<form class="pf-c-form pf-m-horizontal">
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Name")}
|
||||||
|
?required=${true}
|
||||||
|
name="name">
|
||||||
|
<input type="text" value="${ifDefined(this.provider?.name)}" class="pf-c-form-control" required>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Authorization flow")}
|
||||||
|
?required=${true}
|
||||||
|
name="authorizationFlow">
|
||||||
|
<select class="pf-c-form-control">
|
||||||
|
${until(new FlowsApi(DEFAULT_CONFIG).flowsInstancesList({
|
||||||
|
ordering: "pk",
|
||||||
|
designation: FlowDesignationEnum.Authorization,
|
||||||
|
}).then(flows => {
|
||||||
|
return flows.results.map(flow => {
|
||||||
|
return html`<option value=${ifDefined(flow.pk)} ?selected=${this.provider?.authorizationFlow === flow.pk}>${flow.name}</option>`;
|
||||||
|
});
|
||||||
|
}))}
|
||||||
|
</select>
|
||||||
|
<p class="pf-c-form__helper-text">${gettext("Flow used when authorizing this provider.")}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Internal host")}
|
||||||
|
?required=${true}
|
||||||
|
name="internalHost">
|
||||||
|
<input type="text" value="${ifDefined(this.provider?.internalHost)}" class="pf-c-form-control" required>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal name="internalHostSslValidation">
|
||||||
|
<div class="pf-c-check">
|
||||||
|
<input type="checkbox" class="pf-c-check__input" ?checked=${this.provider?.internalHostSslValidation || false}>
|
||||||
|
<label class="pf-c-check__label">
|
||||||
|
${gettext("Internal host SSL Validation")}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<p class="pf-c-form__helper-text">${gettext("Validate SSL Certificates of upstream servers.")}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("External host")}
|
||||||
|
?required=${true}
|
||||||
|
name="externalHost">
|
||||||
|
<input type="text" value="${ifDefined(this.provider?.externalHost)}" class="pf-c-form-control" required>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Certificate")}
|
||||||
|
name="certificate">
|
||||||
|
<select class="pf-c-form-control">
|
||||||
|
${until(new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsList({
|
||||||
|
ordering: "pk",
|
||||||
|
hasKey: "true",
|
||||||
|
}).then(keys => {
|
||||||
|
return keys.results.map(key => {
|
||||||
|
return html`<option value=${ifDefined(key.pk)} ?selected=${this.provider?.certificate === key.pk}>${key.name}</option>`;
|
||||||
|
});
|
||||||
|
}))}
|
||||||
|
</select>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Skip path regex")}
|
||||||
|
name="skipPathRegex">
|
||||||
|
<textarea class="pf-c-form-control">${this.provider?.skipPathRegex}</textarea>
|
||||||
|
<p class="pf-c-form__helper-text">${gettext("Regular expressions for which authentication is not required. Each new line is interpreted as a new Regular Expression.")}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
|
||||||
|
<ak-form-element-horizontal name="basicAuthEnabled">
|
||||||
|
<div class="pf-c-check">
|
||||||
|
<input type="checkbox" class="pf-c-check__input" ?checked=${this.provider?.basicAuthEnabled || false}>
|
||||||
|
<label class="pf-c-check__label">
|
||||||
|
${gettext("Set HTTP-Basic Authentication")}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<p class="pf-c-form__helper-text">${gettext("Set a custom HTTP-Basic Authentication header based on values from authentik.")}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("HTTP-Basic Username Key")}
|
||||||
|
name="basicAuthUserAttribute">
|
||||||
|
<input type="text" value="${ifDefined(this.provider?.basicAuthUserAttribute)}" class="pf-c-form-control">
|
||||||
|
<p class="pf-c-form__helper-text">${gettext("User/Group Attribute used for the user part of the HTTP-Basic Header. If not set, the user's Email address is used.")}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("HTTP-Basic Password Key")}
|
||||||
|
name="basicAuthPasswordAttribute">
|
||||||
|
<input type="text" value="${ifDefined(this.provider?.basicAuthPasswordAttribute)}" class="pf-c-form-control">
|
||||||
|
<p class="pf-c-form__helper-text">${gettext("User/Group Attribute used for the password part of the HTTP-Basic Header.")}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
</form>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -9,20 +9,20 @@ import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList
|
||||||
import PFSizing from "@patternfly/patternfly/utilities/Sizing/sizing.css";
|
import PFSizing from "@patternfly/patternfly/utilities/Sizing/sizing.css";
|
||||||
import PFFlex from "@patternfly/patternfly/utilities/Flex/flex.css";
|
import PFFlex from "@patternfly/patternfly/utilities/Flex/flex.css";
|
||||||
import PFDisplay from "@patternfly/patternfly/utilities/Display/display.css";
|
import PFDisplay from "@patternfly/patternfly/utilities/Display/display.css";
|
||||||
import AKGlobal from "../../authentik.css";
|
|
||||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||||
|
import AKGlobal from "../../../authentik.css";
|
||||||
|
|
||||||
import "../../elements/buttons/ModalButton";
|
import "../../../elements/buttons/ModalButton";
|
||||||
import "../../elements/buttons/SpinnerButton";
|
import "../../../elements/buttons/SpinnerButton";
|
||||||
import "../../elements/CodeMirror";
|
import "../../../elements/CodeMirror";
|
||||||
import "../../elements/Tabs";
|
import "../../../elements/Tabs";
|
||||||
import "../../elements/events/ObjectChangelog";
|
import "../../../elements/events/ObjectChangelog";
|
||||||
import "./RelatedApplicationButton";
|
import "../RelatedApplicationButton";
|
||||||
import { Page } from "../../elements/Page";
|
import "./ProxyProviderForm";
|
||||||
|
import { Page } from "../../../elements/Page";
|
||||||
import { ProvidersApi, ProxyProvider } from "authentik-api";
|
import { ProvidersApi, ProxyProvider } from "authentik-api";
|
||||||
import { DEFAULT_CONFIG } from "../../api/Config";
|
import { DEFAULT_CONFIG } from "../../../api/Config";
|
||||||
import { AdminURLManager } from "../../api/legacy";
|
import { EVENT_REFRESH } from "../../../constants";
|
||||||
import { EVENT_REFRESH } from "../../constants";
|
|
||||||
|
|
||||||
@customElement("ak-provider-proxy-view")
|
@customElement("ak-provider-proxy-view")
|
||||||
export class ProxyProviderViewPage extends Page {
|
export class ProxyProviderViewPage extends Page {
|
||||||
|
@ -128,12 +128,21 @@ export class ProxyProviderViewPage extends Page {
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
<div class="pf-c-card__footer">
|
<div class="pf-c-card__footer">
|
||||||
<ak-modal-button href="${AdminURLManager.providers(`${this.provider.pk}/update/`)}">
|
<ak-forms-modal>
|
||||||
<ak-spinner-button slot="trigger" class="pf-m-primary">
|
<span slot="submit">
|
||||||
|
${gettext("Update")}
|
||||||
|
</span>
|
||||||
|
<span slot="header">
|
||||||
|
${gettext("Update Proxy Provider")}
|
||||||
|
</span>
|
||||||
|
<ak-provider-proxy-form
|
||||||
|
slot="form"
|
||||||
|
.providerUUID=${this.provider.pk || 0}>
|
||||||
|
</ak-provider-proxy-form>
|
||||||
|
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||||
${gettext("Edit")}
|
${gettext("Edit")}
|
||||||
</ak-spinner-button>
|
</button>
|
||||||
<div slot="modal"></div>
|
</ak-forms-modal>
|
||||||
</ak-modal-button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -0,0 +1,237 @@
|
||||||
|
import { CryptoApi, FlowDesignationEnum, FlowsApi, SAMLProvider, ProvidersApi, PropertymappingsApi, SAMLProviderSpBindingEnum, SAMLProviderDigestAlgorithmEnum, SAMLProviderSignatureAlgorithmEnum } from "authentik-api";
|
||||||
|
import { gettext } from "django";
|
||||||
|
import { customElement, property } from "lit-element";
|
||||||
|
import { html, TemplateResult } from "lit-html";
|
||||||
|
import { DEFAULT_CONFIG } from "../../../api/Config";
|
||||||
|
import { Form } from "../../../elements/forms/Form";
|
||||||
|
import { until } from "lit-html/directives/until";
|
||||||
|
import { ifDefined } from "lit-html/directives/if-defined";
|
||||||
|
import "../../../elements/forms/HorizontalFormElement";
|
||||||
|
|
||||||
|
@customElement("ak-provider-saml-form")
|
||||||
|
export class SAMLProviderFormPage extends Form<SAMLProvider> {
|
||||||
|
|
||||||
|
set providerUUID(value: number) {
|
||||||
|
new ProvidersApi(DEFAULT_CONFIG).providersSamlRead({
|
||||||
|
id: value,
|
||||||
|
}).then(provider => {
|
||||||
|
this.provider = provider;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@property({attribute: false})
|
||||||
|
provider?: SAMLProvider;
|
||||||
|
|
||||||
|
getSuccessMessage(): string {
|
||||||
|
if (this.provider) {
|
||||||
|
return gettext("Successfully updated provider.");
|
||||||
|
} else {
|
||||||
|
return gettext("Successfully created provider.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
send = (data: SAMLProvider): Promise<SAMLProvider> => {
|
||||||
|
if (this.provider) {
|
||||||
|
return new ProvidersApi(DEFAULT_CONFIG).providersSamlUpdate({
|
||||||
|
id: this.provider.pk || 0,
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return new ProvidersApi(DEFAULT_CONFIG).providersSamlCreate({
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
renderForm(): TemplateResult {
|
||||||
|
return html`<form class="pf-c-form pf-m-horizontal">
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Name")}
|
||||||
|
?required=${true}
|
||||||
|
name="name">
|
||||||
|
<input type="text" value="${ifDefined(this.provider?.name)}" class="pf-c-form-control" required>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Authorization flow")}
|
||||||
|
?required=${true}
|
||||||
|
name="authorizationFlow">
|
||||||
|
<select class="pf-c-form-control">
|
||||||
|
${until(new FlowsApi(DEFAULT_CONFIG).flowsInstancesList({
|
||||||
|
ordering: "pk",
|
||||||
|
designation: FlowDesignationEnum.Authorization,
|
||||||
|
}).then(flows => {
|
||||||
|
return flows.results.map(flow => {
|
||||||
|
return html`<option value=${ifDefined(flow.pk)} ?selected=${this.provider?.authorizationFlow === flow.pk}>${flow.name}</option>`;
|
||||||
|
});
|
||||||
|
}))}
|
||||||
|
</select>
|
||||||
|
<p class="pf-c-form__helper-text">${gettext("Flow used when authorizing this provider.")}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("ACS URL")}
|
||||||
|
?required=${true}
|
||||||
|
name="acsUrl">
|
||||||
|
<input type="text" value="${ifDefined(this.provider?.acsUrl)}" class="pf-c-form-control" required>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Issuer")}
|
||||||
|
?required=${true}
|
||||||
|
name="issuer">
|
||||||
|
<input type="text" value="${this.provider?.issuer || "authentik"}" class="pf-c-form-control" required>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Service Provider Binding")}
|
||||||
|
?required=${true}
|
||||||
|
name="spBinding">
|
||||||
|
<select class="pf-c-form-control">
|
||||||
|
<option value=${SAMLProviderSpBindingEnum.Redirect} ?selected=${this.provider?.spBinding === SAMLProviderSpBindingEnum.Redirect}>
|
||||||
|
${gettext("Redirect")}
|
||||||
|
</option>
|
||||||
|
<option value=${SAMLProviderSpBindingEnum.Post} ?selected=${this.provider?.spBinding === SAMLProviderSpBindingEnum.Post}>
|
||||||
|
${gettext("Post")}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<p class="pf-c-form__helper-text">${gettext("Determines how authentik sends the response back to the Service Provider.")}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Audience")}
|
||||||
|
name="audience">
|
||||||
|
<input type="text" value="${ifDefined(this.provider?.audience)}" class="pf-c-form-control">
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Signing Keypair")}
|
||||||
|
name="signingKp">
|
||||||
|
<select class="pf-c-form-control">
|
||||||
|
<option value="" ?selected=${this.provider?.signingKp === undefined}>---------</option>
|
||||||
|
${until(new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsList({
|
||||||
|
ordering: "pk",
|
||||||
|
hasKey: "true",
|
||||||
|
}).then(keys => {
|
||||||
|
return keys.results.map(key => {
|
||||||
|
return html`<option value=${ifDefined(key.pk)} ?selected=${this.provider?.signingKp === key.pk}>${key.name}</option>`;
|
||||||
|
});
|
||||||
|
}))}
|
||||||
|
</select>
|
||||||
|
<p class="pf-c-form__helper-text">${gettext("Keypair used to sign outgoing Responses going to the Service Provider.")}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Verification Certificate")}
|
||||||
|
?required=${true}
|
||||||
|
name="verificationKp">
|
||||||
|
<select class="pf-c-form-control">
|
||||||
|
<option value="" ?selected=${this.provider?.verificationKp === undefined}>---------</option>
|
||||||
|
${until(new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsList({
|
||||||
|
ordering: "pk",
|
||||||
|
}).then(keys => {
|
||||||
|
return keys.results.map(key => {
|
||||||
|
return html`<option value=${ifDefined(key.pk)} ?selected=${this.provider?.verificationKp === key.pk}>${key.name}</option>`;
|
||||||
|
});
|
||||||
|
}))}
|
||||||
|
</select>
|
||||||
|
<p class="pf-c-form__helper-text">${gettext("When selected, incoming assertion's Signatures will be validated against this certificate. To allow unsigned Requests, leave on default.")}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Property mappings")}
|
||||||
|
?required=${true}
|
||||||
|
name="propertyMappings">
|
||||||
|
<select class="pf-c-form-control" multiple>
|
||||||
|
${until(new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsSamlList({
|
||||||
|
ordering: "saml_name"
|
||||||
|
}).then(mappings => {
|
||||||
|
return mappings.results.map(mapping => {
|
||||||
|
const selected = Array.from(this.provider?.propertyMappings || []).some(su => {
|
||||||
|
return su == mapping.pk;
|
||||||
|
});
|
||||||
|
return html`<option value=${ifDefined(mapping.pk)} ?selected=${selected}>${mapping.name}</option>`;
|
||||||
|
});
|
||||||
|
}))}
|
||||||
|
</select>
|
||||||
|
<p class="pf-c-form__helper-text">${gettext("Hold control/command to select multiple items.")}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("NameID Property Mapping")}
|
||||||
|
name="nameIdMapping">
|
||||||
|
<select class="pf-c-form-control">
|
||||||
|
<option value="" ?selected=${this.provider?.nameIdMapping === undefined}>---------</option>
|
||||||
|
${until(new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsSamlList({
|
||||||
|
ordering: "saml_name"
|
||||||
|
}).then(mappings => {
|
||||||
|
return mappings.results.map(mapping => {
|
||||||
|
return html`<option value=${ifDefined(mapping.pk)} ?selected=${this.provider?.nameIdMapping === mapping.pk}>${mapping.name}</option>`;
|
||||||
|
});
|
||||||
|
}))}
|
||||||
|
</select>
|
||||||
|
<p class="pf-c-form__helper-text">${gettext("Configure how the NameID value will be created. When left empty, the NameIDPolicy of the incoming request will be respected.")}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Assertion valid not before")}
|
||||||
|
?required=${true}
|
||||||
|
name="assertionValidNotBefore">
|
||||||
|
<input type="text" value="${this.provider?.assertionValidNotBefore || "minutes=-5"}" class="pf-c-form-control" required>
|
||||||
|
<p class="pf-c-form__helper-text">${gettext("Assertion valid not before current time + this value (Format: hours=-1;minutes=-2;seconds=-3).")}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Assertion valid not on or after")}
|
||||||
|
?required=${true}
|
||||||
|
name="assertionValidNotOnOrAfter">
|
||||||
|
<input type="text" value="${this.provider?.assertionValidNotOnOrAfter || "minutes=5"}" class="pf-c-form-control" required>
|
||||||
|
<p class="pf-c-form__helper-text">${gettext("Assertion not valid on or after current time + this value (Format: hours=1;minutes=2;seconds=3).")}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Session valid not on or after")}
|
||||||
|
?required=${true}
|
||||||
|
name="sessionValidNotOnOrAfter">
|
||||||
|
<input type="text" value="${this.provider?.sessionValidNotOnOrAfter || "minutes=86400"}" class="pf-c-form-control" required>
|
||||||
|
<p class="pf-c-form__helper-text">${gettext("Session not valid on or after current time + this value (Format: hours=1;minutes=2;seconds=3).")}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Digest algorithm")}
|
||||||
|
?required=${true}
|
||||||
|
name="digestAlgorithm">
|
||||||
|
<select class="pf-c-form-control">
|
||||||
|
<option value=${SAMLProviderDigestAlgorithmEnum._200009Xmldsigsha1} ?selected=${this.provider?.digestAlgorithm === SAMLProviderDigestAlgorithmEnum._200009Xmldsigsha1}>
|
||||||
|
${gettext("SHA1")}
|
||||||
|
</option>
|
||||||
|
<option value=${SAMLProviderDigestAlgorithmEnum._200104Xmlencsha256} ?selected=${this.provider?.digestAlgorithm === SAMLProviderDigestAlgorithmEnum._200104Xmlencsha256 || this.provider?.digestAlgorithm === undefined}>
|
||||||
|
${gettext("SHA256")}
|
||||||
|
</option>
|
||||||
|
<option value=${SAMLProviderDigestAlgorithmEnum._200104XmldsigMoresha384} ?selected=${this.provider?.digestAlgorithm === SAMLProviderDigestAlgorithmEnum._200104XmldsigMoresha384}>
|
||||||
|
${gettext("SHA384")}
|
||||||
|
</option>
|
||||||
|
<option value=${SAMLProviderDigestAlgorithmEnum._200104Xmlencsha512} ?selected=${this.provider?.digestAlgorithm === SAMLProviderDigestAlgorithmEnum._200104Xmlencsha512}>
|
||||||
|
${gettext("SHA512")}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Signature algorithm")}
|
||||||
|
?required=${true}
|
||||||
|
name="signatureAlgorithm">
|
||||||
|
<select class="pf-c-form-control">
|
||||||
|
<option value=${SAMLProviderSignatureAlgorithmEnum._200009XmldsigrsaSha1} ?selected=${this.provider?.signatureAlgorithm === SAMLProviderSignatureAlgorithmEnum._200009XmldsigrsaSha1}>
|
||||||
|
${gettext("RSA-SHA1")}
|
||||||
|
</option>
|
||||||
|
<option value=${SAMLProviderSignatureAlgorithmEnum._200104XmldsigMorersaSha256} ?selected=${this.provider?.signatureAlgorithm === SAMLProviderSignatureAlgorithmEnum._200104XmldsigMorersaSha256 || this.provider?.signatureAlgorithm === undefined}>
|
||||||
|
${gettext("RSA-SHA256")}
|
||||||
|
</option>
|
||||||
|
<option value=${SAMLProviderSignatureAlgorithmEnum._200104XmldsigMorersaSha384} ?selected=${this.provider?.signatureAlgorithm === SAMLProviderSignatureAlgorithmEnum._200104XmldsigMorersaSha384}>
|
||||||
|
${gettext("RSA-SHA384")}
|
||||||
|
</option>
|
||||||
|
<option value=${SAMLProviderSignatureAlgorithmEnum._200104XmldsigMorersaSha512} ?selected=${this.provider?.signatureAlgorithm === SAMLProviderSignatureAlgorithmEnum._200104XmldsigMorersaSha512}>
|
||||||
|
${gettext("RSA-SHA512")}
|
||||||
|
</option>
|
||||||
|
<option value=${SAMLProviderSignatureAlgorithmEnum._200009XmldsigdsaSha1} ?selected=${this.provider?.signatureAlgorithm === SAMLProviderSignatureAlgorithmEnum._200009XmldsigdsaSha1}>
|
||||||
|
${gettext("DSA-SHA1")}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
</form>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -10,20 +10,21 @@ import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList
|
||||||
import PFSizing from "@patternfly/patternfly/utilities/Sizing/sizing.css";
|
import PFSizing from "@patternfly/patternfly/utilities/Sizing/sizing.css";
|
||||||
import PFFlex from "@patternfly/patternfly/utilities/Flex/flex.css";
|
import PFFlex from "@patternfly/patternfly/utilities/Flex/flex.css";
|
||||||
import PFDisplay from "@patternfly/patternfly/utilities/Display/display.css";
|
import PFDisplay from "@patternfly/patternfly/utilities/Display/display.css";
|
||||||
import AKGlobal from "../../authentik.css";
|
import AKGlobal from "../../../authentik.css";
|
||||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||||
|
|
||||||
import "../../elements/buttons/ModalButton";
|
import "../../../elements/buttons/ModalButton";
|
||||||
import "../../elements/buttons/SpinnerButton";
|
import "../../../elements/buttons/SpinnerButton";
|
||||||
import "../../elements/CodeMirror";
|
import "../../../elements/CodeMirror";
|
||||||
import "../../elements/Tabs";
|
import "../../../elements/Tabs";
|
||||||
import "../../elements/events/ObjectChangelog";
|
import "../../../elements/events/ObjectChangelog";
|
||||||
import "./RelatedApplicationButton";
|
import "../RelatedApplicationButton";
|
||||||
import { Page } from "../../elements/Page";
|
import "./SAMLProviderForm";
|
||||||
|
import { Page } from "../../../elements/Page";
|
||||||
import { ProvidersApi, SAMLProvider } from "authentik-api";
|
import { ProvidersApi, SAMLProvider } from "authentik-api";
|
||||||
import { DEFAULT_CONFIG } from "../../api/Config";
|
import { DEFAULT_CONFIG } from "../../../api/Config";
|
||||||
import { AdminURLManager, AppURLManager } from "../../api/legacy";
|
import { AppURLManager } from "../../../api/legacy";
|
||||||
import { EVENT_REFRESH } from "../../constants";
|
import { EVENT_REFRESH } from "../../../constants";
|
||||||
import { ifDefined } from "lit-html/directives/if-defined";
|
import { ifDefined } from "lit-html/directives/if-defined";
|
||||||
|
|
||||||
@customElement("ak-provider-saml-view")
|
@customElement("ak-provider-saml-view")
|
||||||
|
@ -121,12 +122,21 @@ export class SAMLProviderViewPage extends Page {
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
<div class="pf-c-card__footer">
|
<div class="pf-c-card__footer">
|
||||||
<ak-modal-button href="${AdminURLManager.providers(`${this.provider.pk}/update/`)}">
|
<ak-forms-modal>
|
||||||
<ak-spinner-button slot="trigger" class="pf-m-primary">
|
<span slot="submit">
|
||||||
|
${gettext("Update")}
|
||||||
|
</span>
|
||||||
|
<span slot="header">
|
||||||
|
${gettext("Update SAML Provider")}
|
||||||
|
</span>
|
||||||
|
<ak-provider-saml-form
|
||||||
|
slot="form"
|
||||||
|
.providerUUID=${this.provider.pk || 0}>
|
||||||
|
</ak-provider-saml-form>
|
||||||
|
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||||
${gettext("Edit")}
|
${gettext("Edit")}
|
||||||
</ak-spinner-button>
|
</button>
|
||||||
<div slot="modal"></div>
|
</ak-forms-modal>
|
||||||
</ak-modal-button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
Reference in New Issue