diff --git a/src/app/services/services.module.ts b/src/app/services/services.module.ts index 37a9ff73..b7c87204 100644 --- a/src/app/services/services.module.ts +++ b/src/app/services/services.module.ts @@ -72,7 +72,7 @@ const authService = new AuthService(cryptoService, apiService, userService, toke i18nService, platformUtilsService, messagingService, false); const configurationService = new ConfigurationService(storageService, secureStorageService); const syncSevrice = new SyncService(configurationService, logService, cryptoFunctionService, apiService, - messagingService); + messagingService, i18nService); const analytics = new Analytics(window, () => true, platformUtilsService, storageService, appIdService); containerService.attachToWindow(window); diff --git a/src/app/tabs/dashboard.component.ts b/src/app/tabs/dashboard.component.ts index cd7c0610..c07ad2fb 100644 --- a/src/app/tabs/dashboard.component.ts +++ b/src/app/tabs/dashboard.component.ts @@ -97,8 +97,8 @@ export class DashboardComponent implements OnInit, OnDestroy { } async simulate() { - this.simGroups = null; - this.simUsers = null; + this.simGroups = []; + this.simUsers = []; this.simEnabledUsers = []; this.simDisabledUsers = []; this.simDeletedUsers = []; @@ -106,28 +106,33 @@ export class DashboardComponent implements OnInit, OnDestroy { this.simPromise = new Promise(async (resolve, reject) => { try { const result = await this.syncService.sync(!this.simSinceLast, true); - this.simUsers = result[1]; - this.simGroups = result[0]; + if (result[0] != null) { + this.simGroups = result[0]; + } + if (result[1] != null) { + this.simUsers = result[1]; + } } catch (e) { + this.simGroups = null; + this.simUsers = null; reject(e || this.i18nService.t('syncError')); + return; } const userMap = new Map(); - if (this.simUsers != null) { - this.sort(this.simUsers); - for (const u of this.simUsers) { - userMap.set(u.externalId, u); - if (u.deleted) { - this.simDeletedUsers.push(u); - } else if (u.disabled) { - this.simDisabledUsers.push(u); - } else { - this.simEnabledUsers.push(u); - } + this.sort(this.simUsers); + for (const u of this.simUsers) { + userMap.set(u.externalId, u); + if (u.deleted) { + this.simDeletedUsers.push(u); + } else if (u.disabled) { + this.simDisabledUsers.push(u); + } else { + this.simEnabledUsers.push(u); } } - if (userMap.size > 0 && this.simGroups != null) { + if (userMap.size > 0) { this.sort(this.simGroups); for (const g of this.simGroups) { if (g.userMemberExternalIds == null) { diff --git a/src/locales/en/messages.json b/src/locales/en/messages.json index 5641c5a4..29b205e1 100644 --- a/src/locales/en/messages.json +++ b/src/locales/en/messages.json @@ -534,5 +534,11 @@ }, "logInDesc": { "message": "Log in as an organization admin user below." + }, + "dirConfigIncomplete": { + "message": "Directory configuration incomplete." + }, + "usernamePasswordNotConfigured": { + "message": "Username/password are not configured." } } diff --git a/src/services/azure-directory.service.ts b/src/services/azure-directory.service.ts index 0da5d8f0..752fa277 100644 --- a/src/services/azure-directory.service.ts +++ b/src/services/azure-directory.service.ts @@ -14,6 +14,9 @@ import { BaseDirectoryService } from './baseDirectory.service'; import { ConfigurationService } from './configuration.service'; import { DirectoryService } from './directory.service'; +import { I18nService } from 'jslib/abstractions/i18n.service'; +import { LogService } from 'jslib/abstractions/log.service'; + const NextLink = '@odata.nextLink'; const DeltaLink = '@odata.deltaLink'; const ObjectType = '@odata.type'; @@ -25,7 +28,8 @@ export class AzureDirectoryService extends BaseDirectoryService implements Direc private accessToken: string; private accessTokenExpiration: Date; - constructor(private configurationService: ConfigurationService) { + constructor(private configurationService: ConfigurationService, private logService: LogService, + private i18nService: I18nService) { super(); this.init(); } @@ -238,6 +242,12 @@ export class AzureDirectoryService extends BaseDirectoryService implements Direc private init() { this.client = graph.Client.init({ authProvider: (done) => { + if (this.dirConfig.applicationId == null || this.dirConfig.key == null || + this.dirConfig.tenant == null) { + done(this.i18nService.t('dirConfigIncomplete'), null); + return; + } + if (!this.accessTokenIsExpired()) { done(null, this.accessToken); return; diff --git a/src/services/gsuite-directory.service.ts b/src/services/gsuite-directory.service.ts index 337b7ee3..4097c379 100644 --- a/src/services/gsuite-directory.service.ts +++ b/src/services/gsuite-directory.service.ts @@ -20,6 +20,7 @@ import { BaseDirectoryService } from './baseDirectory.service'; import { ConfigurationService } from './configuration.service'; import { DirectoryService } from './directory.service'; +import { I18nService } from 'jslib/abstractions/i18n.service'; import { LogService } from 'jslib/abstractions/log.service'; export class GSuiteDirectoryService extends BaseDirectoryService implements DirectoryService { @@ -29,7 +30,8 @@ export class GSuiteDirectoryService extends BaseDirectoryService implements Dire private dirConfig: GSuiteConfiguration; private syncConfig: SyncConfiguration; - constructor(private configurationService: ConfigurationService, private logService: LogService) { + constructor(private configurationService: ConfigurationService, private logService: LogService, + private i18nService: I18nService) { super(); this.service = google.admin('directory_v1'); } @@ -183,6 +185,11 @@ export class GSuiteDirectoryService extends BaseDirectoryService implements Dire } private async auth() { + if (this.dirConfig.clientEmail == null || this.dirConfig.privateKey == null || + this.dirConfig.adminUser == null || this.dirConfig.domain == null) { + throw new Error(this.i18nService.t('dirConfigIncomplete')); + } + this.client = new google.auth.JWT({ email: this.dirConfig.clientEmail, key: this.dirConfig.privateKey, diff --git a/src/services/ldap-directory.service.ts b/src/services/ldap-directory.service.ts index ae03022f..602b793e 100644 --- a/src/services/ldap-directory.service.ts +++ b/src/services/ldap-directory.service.ts @@ -10,7 +10,9 @@ import { UserEntry } from '../models/userEntry'; import { ConfigurationService } from './configuration.service'; import { DirectoryService } from './directory.service'; +import { I18nService } from 'jslib/abstractions/i18n.service'; import { LogService } from 'jslib/abstractions/log.service'; + import { Utils } from 'jslib/misc/utils'; const UserControlAccountDisabled = 2; @@ -20,7 +22,8 @@ export class LdapDirectoryService implements DirectoryService { private dirConfig: LdapConfiguration; private syncConfig: SyncConfiguration; - constructor(private configurationService: ConfigurationService, private logService: LogService) { } + constructor(private configurationService: ConfigurationService, private logService: LogService, + private i18nService: I18nService) { } async getEntries(force: boolean, test: boolean): Promise<[GroupEntry[], UserEntry[]]> { const type = await this.configurationService.getDirectoryType(); @@ -312,6 +315,11 @@ export class LdapDirectoryService implements DirectoryService { private async bind(): Promise { return new Promise((resolve, reject) => { + if (this.dirConfig.hostname == null || this.dirConfig.port == null) { + reject(this.i18nService.t('dirConfigIncomplete')); + return; + } + const url = 'ldap' + (this.dirConfig.ssl ? 's' : '') + '://' + this.dirConfig.hostname + ':' + this.dirConfig.port; @@ -325,13 +333,13 @@ export class LdapDirectoryService implements DirectoryService { this.dirConfig.password; if (user == null || pass == null) { - reject('Username and/or password are not configured.'); + reject(this.i18nService.t('usernamePasswordNotConfigured')); return; } this.client.bind(user, pass, (err) => { if (err != null) { - reject('Error authenticating: ' + err.message); + reject(err.message); } else { resolve(); } diff --git a/src/services/okta-directory.service.ts b/src/services/okta-directory.service.ts index fe18f46c..abc62822 100644 --- a/src/services/okta-directory.service.ts +++ b/src/services/okta-directory.service.ts @@ -9,6 +9,7 @@ import { BaseDirectoryService } from './baseDirectory.service'; import { ConfigurationService } from './configuration.service'; import { DirectoryService } from './directory.service'; +import { I18nService } from 'jslib/abstractions/i18n.service'; import { LogService } from 'jslib/abstractions/log.service'; // tslint:disable-next-line @@ -19,7 +20,8 @@ export class OktaDirectoryService extends BaseDirectoryService implements Direct private syncConfig: SyncConfiguration; private client: any; - constructor(private configurationService: ConfigurationService, private logService: LogService) { + constructor(private configurationService: ConfigurationService, private logService: LogService, + private i18nService: I18nService) { super(); } @@ -39,6 +41,10 @@ export class OktaDirectoryService extends BaseDirectoryService implements Direct return; } + if (this.dirConfig.orgUrl == null || this.dirConfig.token == null) { + throw new Error(this.i18nService.t('dirConfigIncomplete')); + } + this.client = new okta.Client({ orgUrl: this.dirConfig.orgUrl, token: this.dirConfig.token, diff --git a/src/services/sync.service.ts b/src/services/sync.service.ts index 6229d3a1..a163f190 100644 --- a/src/services/sync.service.ts +++ b/src/services/sync.service.ts @@ -10,6 +10,7 @@ import { ImportDirectoryRequestUser } from 'jslib/models/request/importDirectory import { ApiService } from 'jslib/abstractions/api.service'; import { CryptoFunctionService } from 'jslib/abstractions/cryptoFunction.service'; +import { I18nService } from 'jslib/abstractions/i18n.service'; import { LogService } from 'jslib/abstractions/log.service'; import { MessagingService } from 'jslib/abstractions/messaging.service'; import { StorageService } from 'jslib/abstractions/storage.service'; @@ -31,7 +32,7 @@ export class SyncService { constructor(private configurationService: ConfigurationService, private logService: LogService, private cryptoFunctionService: CryptoFunctionService, private apiService: ApiService, - private messagingService: MessagingService) { } + private messagingService: MessagingService, private i18nService: I18nService) { } async sync(force: boolean, test: boolean): Promise<[GroupEntry[], UserEntry[]]> { this.dirType = await this.configurationService.getDirectoryType(); @@ -119,13 +120,13 @@ export class SyncService { private getDirectoryService(): DirectoryService { switch (this.dirType) { case DirectoryType.GSuite: - return new GSuiteDirectoryService(this.configurationService, this.logService); + return new GSuiteDirectoryService(this.configurationService, this.logService, this.i18nService); case DirectoryType.AzureActiveDirectory: - return new AzureDirectoryService(this.configurationService); + return new AzureDirectoryService(this.configurationService, this.logService, this.i18nService); case DirectoryType.Ldap: - return new LdapDirectoryService(this.configurationService, this.logService); + return new LdapDirectoryService(this.configurationService, this.logService, this.i18nService); case DirectoryType.Okta: - return new OktaDirectoryService(this.configurationService, this.logService); + return new OktaDirectoryService(this.configurationService, this.logService, this.i18nService); default: return null; }