diff --git a/app/client/ui/AdminPanel.ts b/app/client/ui/AdminPanel.ts index de0efceb..3a229714 100644 --- a/app/client/ui/AdminPanel.ts +++ b/app/client/ui/AdminPanel.ts @@ -105,6 +105,13 @@ export class AdminPanel extends Disposable { value: this._buildSandboxingDisplay(owner), expandedContent: this._buildSandboxingNotice(), }), + dom.create(AdminSectionItem, { + id: 'authentication', + name: t('Authentication'), + description: t('Current authentication method'), + value: this._buildAuthenticationDisplay(owner), + expandedContent: this._buildAuthenticationNotice(owner), + }) ]), dom.create(AdminSection, t('Version'), [ @@ -156,6 +163,37 @@ isolated from other documents and isolated from the network.'), ]; } + private _buildAuthenticationDisplay(owner: IDisposableOwner) { + return dom.domComputed( + use => { + const req = this._checks.requestCheckById(use, 'authentication'); + const result = req ? use(req.result) : undefined; + if (!result) { + return cssValueLabel(cssErrorText('unavailable')); + } + + const { success, details } = result; + const loginSystemId = details?.loginSystemId; + + if (!success || !loginSystemId) { + return cssValueLabel(cssErrorText('auth error')); + } + + if (loginSystemId === 'no-logins') { + return cssValueLabel(cssDangerText('no authentication')); + } + + return cssValueLabel(cssHappyText(loginSystemId)); + } + ); + } + + private _buildAuthenticationNotice(owner: IDisposableOwner) { + return t('Grist allows different types of authentication to be configured, including SAML and OIDC. \ + We recommend enabling one of these if Grist is accessible over the network or being made available \ + to multiple people.'); + } + private _buildUpdates(owner: MultiHolder) { // We can be in those states: enum State { @@ -446,6 +484,10 @@ const cssErrorText = styled('span', ` color: ${theme.errorText}; `); +export const cssDangerText = styled('div', ` + color: ${theme.dangerText}; +`); + const cssHappyText = styled('span', ` color: ${theme.controlFg}; `); diff --git a/app/client/ui/AdminPanelCss.ts b/app/client/ui/AdminPanelCss.ts index 122ff395..3732f801 100644 --- a/app/client/ui/AdminPanelCss.ts +++ b/app/client/ui/AdminPanelCss.ts @@ -124,6 +124,7 @@ const cssItemName = styled('div', ` font-weight: bold; display: flex; align-items: center; + margin-right: 14px; font-size: ${vars.largeFontSize}; padding-left: 24px; &-prefixed { diff --git a/app/common/BootProbe.ts b/app/common/BootProbe.ts index 753af1c4..dd867049 100644 --- a/app/common/BootProbe.ts +++ b/app/common/BootProbe.ts @@ -6,7 +6,8 @@ export type BootProbeIds = 'reachable' | 'host-header' | 'sandboxing' | - 'system-user' + 'system-user' | + 'authentication' ; export interface BootProbeResult { diff --git a/app/server/lib/BootProbes.ts b/app/server/lib/BootProbes.ts index 8edc28ae..95429491 100644 --- a/app/server/lib/BootProbes.ts +++ b/app/server/lib/BootProbes.ts @@ -58,6 +58,7 @@ export class BootProbes { this._probes.push(_bootProbe); this._probes.push(_hostHeaderProbe); this._probes.push(_sandboxingProbe); + this._probes.push(_authenticationProbe); this._probeById = new Map(this._probes.map(p => [p.id, p])); } } @@ -202,3 +203,17 @@ const _sandboxingProbe: Probe = { }; }, }; + +const _authenticationProbe: Probe = { + id: 'authentication', + name: 'Authentication system', + apply: async(server, req) => { + const loginSystemId = server.getInfo('loginMiddlewareComment'); + return { + success: loginSystemId != undefined, + details: { + loginSystemId, + } + }; + }, +}; diff --git a/app/server/lib/FlexServer.ts b/app/server/lib/FlexServer.ts index 59d8a3e5..0e8b28a6 100644 --- a/app/server/lib/FlexServer.ts +++ b/app/server/lib/FlexServer.ts @@ -1426,6 +1426,11 @@ export class FlexServer implements GristServer { return this._sandboxInfo; } + public getInfo(key: string): any { + const infoPair = this.info.find(([keyToCheck]) => key === keyToCheck); + return infoPair?.[1]; + } + public disableExternalStorage() { if (this.deps.has('doc')) { throw new Error('disableExternalStorage called too late'); diff --git a/app/server/lib/GristServer.ts b/app/server/lib/GristServer.ts index f40bf109..57e66389 100644 --- a/app/server/lib/GristServer.ts +++ b/app/server/lib/GristServer.ts @@ -67,6 +67,7 @@ export interface GristServer { getBundledWidgets(): ICustomWidget[]; hasBoot(): boolean; getSandboxInfo(): SandboxInfo|undefined; + getInfo(key: string): any; } export interface GristLoginSystem { @@ -159,6 +160,7 @@ export function createDummyGristServer(): GristServer { getBundledWidgets() { return []; }, hasBoot() { return false; }, getSandboxInfo() { return undefined; }, + getInfo(key: string) { return undefined; } }; }