diff --git a/authentik/sources/ldap/templates/ldap/source_list_status.html b/authentik/sources/ldap/templates/ldap/source_list_status.html deleted file mode 100644 index 05c187d6a..000000000 --- a/authentik/sources/ldap/templates/ldap/source_list_status.html +++ /dev/null @@ -1,8 +0,0 @@ -{% load humanize %} -{% load i18n %} - -{% if last_sync %} - {% blocktrans with last_sync=last_sync|naturaltime %}Synced {{ last_sync }}.{% endblocktrans %} -{% else %} - Not synced yet/Sync in Progress -{% endif %} diff --git a/web/src/api/sources/LDAP.ts b/web/src/api/sources/LDAP.ts new file mode 100644 index 000000000..7d4c427c3 --- /dev/null +++ b/web/src/api/sources/LDAP.ts @@ -0,0 +1,35 @@ +import { DefaultClient } from "../Client"; +import { Source } from "../Sources"; + +export class LDAPSource extends Source { + server_uri: string; + bind_cn: string; + start_tls: boolean + base_dn: string; + additional_user_dn: string; + additional_group_dn: string; + user_object_filter: string; + group_object_filter: string; + group_membership_field: string; + object_uniqueness_field: string; + sync_users: boolean; + sync_users_password: boolean; + sync_groups: boolean; + sync_parent_group?: string; + property_mappings: string[]; + property_mappings_group: string[]; + + constructor() { + super(); + throw Error(); + } + + static get(slug: string): Promise { + return DefaultClient.fetch(["sources", "ldap", slug]); + } + + static syncStatus(slug: string): Promise<{ last_sync?: number }> { + return DefaultClient.fetch(["sources", "ldap", slug, "sync_status"]); + } + +} diff --git a/web/src/authentik.css b/web/src/authentik.css index 510b7393b..5fda3c5dd 100644 --- a/web/src/authentik.css +++ b/web/src/authentik.css @@ -127,6 +127,7 @@ select[multiple] { .pf-c-card { --pf-c-card--BackgroundColor: var(--ak-dark-background-light); } + .pf-c-card__title, .pf-c-card__header-main, .pf-c-card__body { color: var(--ak-dark-foreground); diff --git a/web/src/interfaces/AdminInterface.ts b/web/src/interfaces/AdminInterface.ts index f38154d62..b176cd694 100644 --- a/web/src/interfaces/AdminInterface.ts +++ b/web/src/interfaces/AdminInterface.ts @@ -23,7 +23,7 @@ export const SIDEBAR_ITEMS: SidebarItem[] = [ new SidebarItem("Applications", "/applications").activeWhen( `^/applications/(?${SLUG_REGEX})$` ), - new SidebarItem("Sources", "/administration/sources/").activeWhen( + new SidebarItem("Sources", "/sources").activeWhen( `^/sources/(?${SLUG_REGEX})$`, ), new SidebarItem("Providers", "/providers"), diff --git a/web/src/pages/providers/OAuth2ProviderViewPage.ts b/web/src/pages/providers/OAuth2ProviderViewPage.ts index 532587890..c2ac450ee 100644 --- a/web/src/pages/providers/OAuth2ProviderViewPage.ts +++ b/web/src/pages/providers/OAuth2ProviderViewPage.ts @@ -23,11 +23,6 @@ export class OAuth2ProviderViewPage extends Page { return "pf-icon pf-icon-integration"; } - @property() - set args(value: { [key: string]: number }) { - this.providerID = value.id; - } - @property({type: Number}) set providerID(value: number) { OAuth2Provider.get(value).then((app) => this.provider = app); diff --git a/web/src/pages/sources/LDAPSourceViewPage.ts b/web/src/pages/sources/LDAPSourceViewPage.ts new file mode 100644 index 000000000..88017b404 --- /dev/null +++ b/web/src/pages/sources/LDAPSourceViewPage.ts @@ -0,0 +1,131 @@ +import { gettext } from "django"; +import { CSSResult, customElement, html, property, TemplateResult } from "lit-element"; +import { COMMON_STYLES } from "../../common/styles"; + +import "../../elements/buttons/ModalButton"; +import "../../elements/buttons/SpinnerButton"; +import "../../elements/CodeMirror"; +import "../../elements/Tabs"; +import { Page } from "../../elements/Page"; +import { LDAPSource } from "../../api/sources/LDAP"; +import { Source } from "../../api/Sources"; +import { until } from "lit-html/directives/until"; +import { DefaultClient } from "../../api/Client"; + +@customElement("ak-source-ldap-view") +export class LDAPSourceViewPage extends Page { + pageTitle(): string { + return gettext(`LDAP Source ${this.source?.name || ""}`); + } + pageDescription(): string | undefined { + return; + } + pageIcon(): string { + return "pf-icon pf-icon-middleware"; + } + + @property({ type: String }) + set sourceSlug(slug: string) { + LDAPSource.get(slug).then((s) => this.source = s); + } + + @property({ attribute: false }) + source?: LDAPSource; + + static get styles(): CSSResult[] { + return COMMON_STYLES; + } + + constructor() { + super(); + this.addEventListener("ak-refresh", () => { + if (!this.source?.slug) return; + this.sourceSlug = this.source?.slug; + }); + } + + renderContent(): TemplateResult { + if (!this.source) { + return html``; + } + return html` +
+
+
+
+
+
+
+
+ ${gettext("Name")} +
+
+
${this.source.name}
+
+
+
+
+ ${gettext("Server URI")} +
+
+
${this.source.server_uri}
+
+
+
+
+ ${gettext("Base DN")} +
+
+
+
    +
  • ${this.source.base_dn}
  • +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+

${gettext("Sync status")}

+
+
+

+ ${until(LDAPSource.syncStatus(this.source.slug).then((ls) => { + if (!ls.last_sync) { + return gettext("Not synced in the last hour, check System tasks."); + } + const syncDate = new Date(ls.last_sync * 1000); + return gettext(`Last sync: ${syncDate.toLocaleString()}`) + }), "loading")} +

+
+ +
+
+
+
+
+
`; + } +} diff --git a/web/src/pages/sources/OAuthSourceViewPage.ts b/web/src/pages/sources/OAuthSourceViewPage.ts new file mode 100644 index 000000000..61ec59423 --- /dev/null +++ b/web/src/pages/sources/OAuthSourceViewPage.ts @@ -0,0 +1,124 @@ +import { gettext } from "django"; +import { CSSResult, customElement, html, property, TemplateResult } from "lit-element"; +import { COMMON_STYLES } from "../../common/styles"; + +import "../../elements/buttons/ModalButton"; +import "../../elements/buttons/SpinnerButton"; +import "../../elements/CodeMirror"; +import "../../elements/Tabs"; +import { Page } from "../../elements/Page"; +import { LDAPSource } from "../../api/sources/LDAP"; +import { Source } from "../../api/Sources"; + +@customElement("ak-source-oauth-view") +export class OAuthSourceViewPage extends Page { + pageTitle(): string { + return gettext(`LDAP Source ${this.source?.name}`); + } + pageDescription(): string | undefined { + return; + } + pageIcon(): string { + return "pf-icon pf-icon-middleware"; + } + + @property() + set args(value: { [key: string]: string }) { + this.sourceID = value.id; + } + + @property({ type: String }) + set sourceID(value: string) { + LDAPSource.get(value).then((s) => this.source = s); + } + + @property({ attribute: false }) + source?: LDAPSource; + + static get styles(): CSSResult[] { + return COMMON_STYLES; + } + + constructor() { + super(); + this.addEventListener("ak-refresh", () => { + if (!this.source?.pk) return; + this.sourceID = this.source?.pk; + }); + } + + renderContent(): TemplateResult { + if (!this.source) { + return html``; + } + return html` +
+
+
+
+
+
+
+
+ ${gettext("Name")} +
+
+
${this.source.name}
+
+
+
+
+ ${gettext("Server URI")} +
+
+
${this.source.server_uri}
+
+
+
+
+ ${gettext("Base DN")} +
+
+
+
    +
  • ${this.source.base_dn}
  • +
+
+
+
+
+
+ +
+
+
+ ${gettext("Sync status")} +
+
+ +
+
+
+
+
+
+
+
+
+ ${gettext("These policies control which users can authorize using these policies.")} +
+
+ + +
+
+
`; + } +} diff --git a/web/src/pages/sources/SourceViewPage.ts b/web/src/pages/sources/SourceViewPage.ts index 2b5aa1f68..7439c7bfd 100644 --- a/web/src/pages/sources/SourceViewPage.ts +++ b/web/src/pages/sources/SourceViewPage.ts @@ -1,12 +1,12 @@ -import { gettext } from "django"; -import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element"; +import { CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element"; import { COMMON_STYLES } from "../../common/styles"; -import "../../elements/Tabs"; -import "../../elements/AdminLoginsChart"; import "../../elements/buttons/ModalButton"; import "../../elements/buttons/SpinnerButton"; -import "../../elements/policies/BoundPoliciesList"; +import { SpinnerSize } from "../../elements/Spinner"; + +import "./LDAPSourceViewPage"; +import "./OAuthSourceViewPage"; import { Source } from "../../api/Sources"; @customElement("ak-source-view") @@ -16,48 +16,39 @@ export class SourceViewPage extends LitElement { this.sourceSlug = value.slug; } - @property() - set sourceSlug(value: string) { - Source.get(value).then((source) => (this.source = source)); + @property({ type: String }) + set sourceSlug(slug: string) { + Source.get(slug).then((app) => (this.source = app)); } - @property({attribute: false}) + @property({ attribute: false }) source?: Source; static get styles(): CSSResult[] { - return COMMON_STYLES.concat( - css` - img.pf-icon { - max-height: 24px; - } - ` - ); + return COMMON_STYLES; } render(): TemplateResult { if (!this.source) { - return html``; - } - return html`
-
-

- - ${this.source?.name} -

-
-
- -
-
-
-
- ${gettext("These policies control which users can access this application.")} -
+ return html`
+
+
+
+
- -
- `; +
`; + } + switch (this.source?.object_type) { + case "ldap": + return html``; + case "oauth2": + return html``; + // case "proxy": + // return html``; + default: + return html`

Invalid source type ${this.source.object_type}

`; + } } }