From 20b0ded22318025e5b0b23ee74e1526e462407bd Mon Sep 17 00:00:00 2001 From: Erik Michelson Date: Tue, 28 Dec 2021 01:16:42 +0100 Subject: [PATCH] refactor(frontend-config): return auth providers as array This change removes the customAuthNames property and redefines the authProviders property of the frontend-config DTO. Instead of an map from auth providers to their enabled-state (boolean), there is now an array that just includes the configured auth providers while also having the identifier and providerName of custom auth providers. Signed-off-by: Erik Michelson --- src/frontend-config/frontend-config.dto.ts | 178 +++++++----------- .../frontend-config.service.spec.ts | 177 +++++++++-------- .../frontend-config.service.ts | 108 ++++++----- 3 files changed, 229 insertions(+), 234 deletions(-) diff --git a/src/frontend-config/frontend-config.dto.ts b/src/frontend-config/frontend-config.dto.ts index edcdb74c7..1e2c86d73 100644 --- a/src/frontend-config/frontend-config.dto.ts +++ b/src/frontend-config/frontend-config.dto.ts @@ -16,68 +16,67 @@ import { URL } from 'url'; import { ServerVersion } from '../monitoring/server-status.dto'; -export class AuthProviders { - /** - * Is Facebook available as a auth provider? - */ - @IsBoolean() - facebook: boolean; - - /** - * Is GitHub available as a auth provider? - */ - @IsBoolean() - github: boolean; - - /** - * Is Twitter available as a auth provider? - */ - @IsBoolean() - twitter: boolean; - - /** - * Is at least one GitLab server available as a auth provider? - */ - @IsBoolean() - gitlab: boolean; - - /** - * Is DropBox available as a auth provider? - */ - @IsBoolean() - dropbox: boolean; - - /** - * Is at least one LDAP server available as a auth provider? - */ - @IsBoolean() - ldap: boolean; - - /** - * Is Google available as a auth provider? - */ - @IsBoolean() - google: boolean; - - /** - * Is at least one SAML provider available as a auth provider? - */ - @IsBoolean() - saml: boolean; - - /** - * Is at least one OAuth2 provider available as a auth provider? - */ - @IsBoolean() - oauth2: boolean; - - /** - * Is local auth available? - */ - @IsBoolean() - local: boolean; +export enum AuthProviderType { + LOCAL = 'local', + LDAP = 'ldap', + SAML = 'saml', + OAUTH2 = 'oauth2', + GITLAB = 'gitlab', + FACEBOOK = 'facebook', + GITHUB = 'github', + TWITTER = 'twitter', + DROPBOX = 'dropbox', + GOOGLE = 'google', } +export type AuthProviderTypeWithCustomName = + | AuthProviderType.LDAP + | AuthProviderType.OAUTH2 + | AuthProviderType.SAML + | AuthProviderType.GITLAB; + +export type AuthProviderTypeWithoutCustomName = + | AuthProviderType.LOCAL + | AuthProviderType.FACEBOOK + | AuthProviderType.GITHUB + | AuthProviderType.TWITTER + | AuthProviderType.DROPBOX + | AuthProviderType.GOOGLE; + +export class AuthProviderWithoutCustomNameDto { + /** + * The type of the auth provider. + */ + @IsString() + type: AuthProviderTypeWithoutCustomName; +} + +export class AuthProviderWithCustomNameDto { + /** + * The type of the auth provider. + */ + @IsString() + type: AuthProviderTypeWithCustomName; + + /** + * The identifier with which the auth provider can be called + * @example gitlab-fsorg + */ + @IsString() + identifier: string; + + /** + * The name given to the auth provider + * @example GitLab fachschaften.org + */ + @IsString() + providerName: string; +} + +export type AuthProviderDto = + | AuthProviderWithCustomNameDto + | AuthProviderWithoutCustomNameDto; + export class BrandingDto { /** * The name to be displayed next to the HedgeDoc logo @@ -96,52 +95,6 @@ export class BrandingDto { logo?: URL; } -export class CustomAuthEntry { - /** - * The identifier with which the auth provider can be called - * @example gitlab - */ - @IsString() - identifier: string; - - /** - * The name given to the auth provider - * @example GitLab - */ - @IsString() - providerName: string; -} - -export class CustomAuthNamesDto { - /** - * All configured GitLab server - */ - @IsArray() - @ValidateNested({ each: true }) - gitlab: CustomAuthEntry[]; - - /** - * All configured LDAP server - */ - @IsArray() - @ValidateNested({ each: true }) - ldap: CustomAuthEntry[]; - - /** - * All configured OAuth2 provider - */ - @IsArray() - @ValidateNested({ each: true }) - oauth2: CustomAuthEntry[]; - - /** - * All configured SAML provider - */ - @IsArray() - @ValidateNested({ each: true }) - saml: CustomAuthEntry[]; -} - export class SpecialUrlsDto { /** * A link to the privacy notice @@ -200,10 +153,11 @@ export class FrontendConfigDto { allowRegister: boolean; /** - * Which auth providers are available? + * Which auth providers are enabled and how are they configured? */ - @ValidateNested() - authProviders: AuthProviders; + @IsArray() + @ValidateNested({ each: true }) + authProviders: AuthProviderDto[]; /** * Individual branding information @@ -211,12 +165,6 @@ export class FrontendConfigDto { @ValidateNested() branding: BrandingDto; - /** - * The custom names of auth providers, which can be specified multiple times - */ - @ValidateNested() - customAuthNames: CustomAuthNamesDto; - /** * Is an image proxy enabled? */ diff --git a/src/frontend-config/frontend-config.service.spec.ts b/src/frontend-config/frontend-config.service.spec.ts index b019f8460..770c909c3 100644 --- a/src/frontend-config/frontend-config.service.spec.ts +++ b/src/frontend-config/frontend-config.service.spec.ts @@ -14,6 +14,7 @@ import { GitlabScope, GitlabVersion } from '../config/gitlab.enum'; import { Loglevel } from '../config/loglevel.enum'; import { LoggerModule } from '../logger/logger.module'; import { getServerVersionFromPackageJson } from '../utils/serverVersion'; +import { AuthProviderType } from './frontend-config.dto'; import { FrontendConfigService } from './frontend-config.service'; /* eslint-disable @@ -250,85 +251,113 @@ describe('FrontendConfigService', () => { expect(config.allowRegister).toEqual( enableRegister, ); - expect(config.authProviders.dropbox).toEqual( - !!authConfig.dropbox.clientID, - ); - expect(config.authProviders.facebook).toEqual( - !!authConfig.facebook.clientID, - ); - expect(config.authProviders.github).toEqual( - !!authConfig.github.clientID, - ); - expect(config.authProviders.google).toEqual( - !!authConfig.google.clientID, - ); - expect(config.authProviders.local).toEqual( - enableLogin, - ); - expect(config.authProviders.twitter).toEqual( - !!authConfig.twitter.consumerKey, - ); - expect(config.authProviders.gitlab).toEqual( - authConfig.gitlab.length !== 0, - ); - expect(config.authProviders.ldap).toEqual( - authConfig.ldap.length !== 0, - ); - expect(config.authProviders.saml).toEqual( - authConfig.saml.length !== 0, - ); - expect(config.authProviders.oauth2).toEqual( - authConfig.oauth2.length !== 0, - ); + if (authConfig.dropbox.clientID) { + expect(config.authProviders).toContainEqual({ + type: AuthProviderType.DROPBOX, + }); + } + if (authConfig.facebook.clientID) { + expect(config.authProviders).toContainEqual({ + type: AuthProviderType.FACEBOOK, + }); + } + if (authConfig.google.clientID) { + expect(config.authProviders).toContainEqual({ + type: AuthProviderType.GOOGLE, + }); + } + if (authConfig.github.clientID) { + expect(config.authProviders).toContainEqual({ + type: AuthProviderType.GITHUB, + }); + } + if (authConfig.local.enableLogin) { + expect(config.authProviders).toContainEqual({ + type: AuthProviderType.LOCAL, + }); + } + if (authConfig.twitter.consumerKey) { + expect(config.authProviders).toContainEqual({ + type: AuthProviderType.TWITTER, + }); + } + expect( + config.authProviders.filter( + (provider) => + provider.type === AuthProviderType.GITLAB, + ).length, + ).toEqual(authConfig.gitlab.length); + expect( + config.authProviders.filter( + (provider) => + provider.type === AuthProviderType.LDAP, + ).length, + ).toEqual(authConfig.ldap.length); + expect( + config.authProviders.filter( + (provider) => + provider.type === AuthProviderType.SAML, + ).length, + ).toEqual(authConfig.saml.length); + expect( + config.authProviders.filter( + (provider) => + provider.type === AuthProviderType.OAUTH2, + ).length, + ).toEqual(authConfig.oauth2.length); + if (authConfig.gitlab.length > 0) { + expect( + config.authProviders.find( + (provider) => + provider.type === AuthProviderType.GITLAB, + ), + ).toEqual({ + type: AuthProviderType.GITLAB, + providerName: authConfig.gitlab[0].providerName, + identifier: authConfig.gitlab[0].identifier, + }); + } + if (authConfig.ldap.length > 0) { + expect( + config.authProviders.find( + (provider) => + provider.type === AuthProviderType.LDAP, + ), + ).toEqual({ + type: AuthProviderType.LDAP, + providerName: authConfig.ldap[0].providerName, + identifier: authConfig.ldap[0].identifier, + }); + } + if (authConfig.saml.length > 0) { + expect( + config.authProviders.find( + (provider) => + provider.type === AuthProviderType.SAML, + ), + ).toEqual({ + type: AuthProviderType.SAML, + providerName: authConfig.saml[0].providerName, + identifier: authConfig.saml[0].identifier, + }); + } + if (authConfig.oauth2.length > 0) { + expect( + config.authProviders.find( + (provider) => + provider.type === AuthProviderType.OAUTH2, + ), + ).toEqual({ + type: AuthProviderType.OAUTH2, + providerName: authConfig.oauth2[0].providerName, + identifier: authConfig.oauth2[0].identifier, + }); + } expect(config.allowAnonymous).toEqual(false); expect(config.branding.name).toEqual(customName); expect(config.branding.logo).toEqual( customLogo ? new URL(customLogo) : undefined, ); - expect( - config.customAuthNames.gitlab.length, - ).toEqual(authConfig.gitlab.length); - if (config.customAuthNames.gitlab.length === 1) { - expect( - config.customAuthNames.gitlab[0].identifier, - ).toEqual(authConfig.gitlab[0].identifier); - expect( - config.customAuthNames.gitlab[0].providerName, - ).toEqual(authConfig.gitlab[0].providerName); - } - expect(config.customAuthNames.ldap.length).toEqual( - authConfig.ldap.length, - ); - if (config.customAuthNames.ldap.length === 1) { - expect( - config.customAuthNames.ldap[0].identifier, - ).toEqual(authConfig.ldap[0].identifier); - expect( - config.customAuthNames.ldap[0].providerName, - ).toEqual(authConfig.ldap[0].providerName); - } - expect(config.customAuthNames.saml.length).toEqual( - authConfig.saml.length, - ); - if (config.customAuthNames.saml.length === 1) { - expect( - config.customAuthNames.saml[0].identifier, - ).toEqual(authConfig.saml[0].identifier); - expect( - config.customAuthNames.saml[0].providerName, - ).toEqual(authConfig.saml[0].providerName); - } - expect( - config.customAuthNames.oauth2.length, - ).toEqual(authConfig.oauth2.length); - if (config.customAuthNames.oauth2.length === 1) { - expect( - config.customAuthNames.oauth2[0].identifier, - ).toEqual(authConfig.oauth2[0].identifier); - expect( - config.customAuthNames.oauth2[0].providerName, - ).toEqual(authConfig.oauth2[0].providerName); - } expect( config.iframeCommunication.editorOrigin, ).toEqual(new URL(appConfig.domain)); diff --git a/src/frontend-config/frontend-config.service.ts b/src/frontend-config/frontend-config.service.ts index cbee7d21e..5b2b13bfb 100644 --- a/src/frontend-config/frontend-config.service.ts +++ b/src/frontend-config/frontend-config.service.ts @@ -17,9 +17,9 @@ import externalServicesConfiguration, { import { ConsoleLoggerService } from '../logger/console-logger.service'; import { getServerVersionFromPackageJson } from '../utils/serverVersion'; import { - AuthProviders, + AuthProviderDto, + AuthProviderType, BrandingDto, - CustomAuthNamesDto, FrontendConfigDto, IframeCommunicationDto, SpecialUrlsDto, @@ -48,7 +48,6 @@ export class FrontendConfigService { allowRegister: this.authConfig.local.enableRegister, authProviders: this.getAuthProviders(), branding: this.getBranding(), - customAuthNames: this.getCustomAuthNames(), iframeCommunication: this.getIframeCommunication(), maxDocumentLength: this.appConfig.maxDocumentLength, plantUmlServer: this.externalServicesConfig.plantUmlServer @@ -60,48 +59,67 @@ export class FrontendConfigService { }; } - private getAuthProviders(): AuthProviders { - return { - dropbox: !!this.authConfig.dropbox.clientID, - facebook: !!this.authConfig.facebook.clientID, - github: !!this.authConfig.github.clientID, - gitlab: this.authConfig.gitlab.length !== 0, - google: !!this.authConfig.google.clientID, - local: this.authConfig.local.enableLogin, - ldap: this.authConfig.ldap.length !== 0, - oauth2: this.authConfig.oauth2.length !== 0, - saml: this.authConfig.saml.length !== 0, - twitter: !!this.authConfig.twitter.consumerKey, - }; - } - - private getCustomAuthNames(): CustomAuthNamesDto { - return { - gitlab: this.authConfig.gitlab.map((entry) => { - return { - identifier: entry.identifier, - providerName: entry.providerName, - }; - }), - ldap: this.authConfig.ldap.map((entry) => { - return { - identifier: entry.identifier, - providerName: entry.providerName, - }; - }), - oauth2: this.authConfig.oauth2.map((entry) => { - return { - identifier: entry.identifier, - providerName: entry.providerName, - }; - }), - saml: this.authConfig.saml.map((entry) => { - return { - identifier: entry.identifier, - providerName: entry.providerName, - }; - }), - }; + private getAuthProviders(): AuthProviderDto[] { + const providers: AuthProviderDto[] = []; + if (this.authConfig.local.enableLogin) { + providers.push({ + type: AuthProviderType.LOCAL, + }); + } + if (this.authConfig.dropbox.clientID) { + providers.push({ + type: AuthProviderType.DROPBOX, + }); + } + if (this.authConfig.facebook.clientID) { + providers.push({ + type: AuthProviderType.FACEBOOK, + }); + } + if (this.authConfig.github.clientID) { + providers.push({ + type: AuthProviderType.GITHUB, + }); + } + if (this.authConfig.google.clientID) { + providers.push({ + type: AuthProviderType.GOOGLE, + }); + } + if (this.authConfig.twitter.consumerKey) { + providers.push({ + type: AuthProviderType.TWITTER, + }); + } + this.authConfig.gitlab.forEach((gitLabEntry) => { + providers.push({ + type: AuthProviderType.GITLAB, + providerName: gitLabEntry.providerName, + identifier: gitLabEntry.identifier, + }); + }); + this.authConfig.ldap.forEach((ldapEntry) => { + providers.push({ + type: AuthProviderType.LDAP, + providerName: ldapEntry.providerName, + identifier: ldapEntry.identifier, + }); + }); + this.authConfig.oauth2.forEach((oauth2Entry) => { + providers.push({ + type: AuthProviderType.OAUTH2, + providerName: oauth2Entry.providerName, + identifier: oauth2Entry.identifier, + }); + }); + this.authConfig.saml.forEach((samlEntry) => { + providers.push({ + type: AuthProviderType.SAML, + providerName: samlEntry.providerName, + identifier: samlEntry.identifier, + }); + }); + return providers; } private getBranding(): BrandingDto {