diff --git a/src/app/services/services.module.ts b/src/app/services/services.module.ts index 01ac192c..56c500ab 100644 --- a/src/app/services/services.module.ts +++ b/src/app/services/services.module.ts @@ -17,6 +17,7 @@ import { LaunchGuardService } from './launch-guard.service'; import { ConfigurationService } from '../../services/configuration.service'; import { I18nService } from '../../services/i18n.service'; +import { SyncService } from '../../services/sync.service'; import { BroadcasterService } from 'jslib/angular/services/broadcaster.service'; import { ValidationService } from 'jslib/angular/services/validation.service'; @@ -70,6 +71,7 @@ const containerService = new ContainerService(cryptoService, platformUtilsServic const authService = new AuthService(cryptoService, apiService, userService, tokenService, appIdService, i18nService, platformUtilsService, messagingService, false); const configurationService = new ConfigurationService(storageService, secureStorageService); +const syncSevrice = new SyncService(configurationService); const analytics = new Analytics(window, () => true, platformUtilsService, storageService, appIdService); containerService.attachToWindow(window); @@ -123,6 +125,7 @@ export function initFactory(): Function { { provide: StateServiceAbstraction, useValue: stateService }, { provide: LogServiceAbstraction, useValue: logService }, { provide: ConfigurationService, useValue: configurationService }, + { provide: SyncService, useValue: syncSevrice }, { provide: APP_INITIALIZER, useFactory: initFactory, diff --git a/src/app/tabs/dashboard.component.html b/src/app/tabs/dashboard.component.html index bc12410b..81345fca 100644 --- a/src/app/tabs/dashboard.component.html +++ b/src/app/tabs/dashboard.component.html @@ -1,7 +1,2 @@ - - -The dashboard!! - - - - + + diff --git a/src/app/tabs/dashboard.component.ts b/src/app/tabs/dashboard.component.ts index 4cf47c1a..59a21530 100644 --- a/src/app/tabs/dashboard.component.ts +++ b/src/app/tabs/dashboard.component.ts @@ -15,6 +15,7 @@ import { ModalComponent } from 'jslib/angular/components/modal.component'; import { AzureDirectoryService } from '../../services/azure-directory.service'; import { GSuiteDirectoryService } from '../../services/gsuite-directory.service'; import { LdapDirectoryService } from '../../services/ldap-directory.service'; +import { SyncService } from '../../services/sync.service'; @Component({ selector: 'app-dashboard', @@ -24,20 +25,14 @@ export class DashboardComponent { @ViewChild('settings', { read: ViewContainerRef }) settingsModal: ViewContainerRef; constructor(analytics: Angulartics2, toasterService: ToasterService, - i18nService: I18nService, private componentFactoryResolver: ComponentFactoryResolver) { } + i18nService: I18nService, private componentFactoryResolver: ComponentFactoryResolver, + private syncService: SyncService) { } - gsuite() { - const gsuite = new GSuiteDirectoryService(); - const entries = gsuite.getEntries(); + async sync() { + await this.syncService.sync(true, true); } - ldap() { - const gsuite = new LdapDirectoryService(); - const entries = gsuite.getEntries(); - } - - azuread() { - const gsuite = new AzureDirectoryService(); - const entries = gsuite.getEntries(); + async simulate() { + await this.syncService.sync(true, false); } } diff --git a/src/app/tabs/settings.component.html b/src/app/tabs/settings.component.html index 7934f9bf..c1262681 100644 --- a/src/app/tabs/settings.component.html +++ b/src/app/tabs/settings.component.html @@ -85,7 +85,7 @@
-
diff --git a/src/app/tabs/settings.component.ts b/src/app/tabs/settings.component.ts index 8f4bf58d..d158f97e 100644 --- a/src/app/tabs/settings.component.ts +++ b/src/app/tabs/settings.component.ts @@ -10,7 +10,6 @@ import { ToasterService } from 'angular2-toaster'; import { Angulartics2 } from 'angulartics2'; import { I18nService } from 'jslib/abstractions/i18n.service'; -import { StorageService } from 'jslib/abstractions/storage.service'; import { ConfigurationService } from '../../services/configuration.service'; @@ -36,7 +35,7 @@ export class SettingsComponent implements OnInit { constructor(analytics: Angulartics2, toasterService: ToasterService, i18nService: I18nService, private componentFactoryResolver: ComponentFactoryResolver, - private configurationService: ConfigurationService, private storageService: StorageService) { + private configurationService: ConfigurationService) { this.directoryOptions = [ { name: i18nService.t('select'), value: null }, { name: 'Active Directory / LDAP', value: DirectoryType.Ldap }, @@ -46,21 +45,21 @@ export class SettingsComponent implements OnInit { } async ngOnInit() { - this.directory = await this.storageService.get('directory'); - this.ldap = (await this.configurationService.get(DirectoryType.Ldap)) || + this.directory = await this.configurationService.getDirectoryType(); + this.ldap = (await this.configurationService.getDirectory(DirectoryType.Ldap)) || this.ldap; - this.gsuite = (await this.configurationService.get(DirectoryType.GSuite)) || + this.gsuite = (await this.configurationService.getDirectory(DirectoryType.GSuite)) || this.gsuite; - this.azure = (await this.configurationService.get(DirectoryType.AzureActiveDirectory)) || - this.azure; - this.sync = (await this.storageService.get('syncConfig')) || this.sync; + this.azure = (await this.configurationService.getDirectory( + DirectoryType.AzureActiveDirectory)) || this.azure; + this.sync = (await this.configurationService.getSync()) || this.sync; } async submit() { - await this.storageService.save('directory', this.directory); - await this.configurationService.save(DirectoryType.Ldap, this.ldap); - await this.configurationService.save(DirectoryType.GSuite, this.gsuite); - await this.configurationService.save(DirectoryType.AzureActiveDirectory, this.azure); - await this.storageService.save('syncConfig', this.sync); + await this.configurationService.saveDirectoryType(this.directory); + await this.configurationService.saveDirectory(DirectoryType.Ldap, this.ldap); + await this.configurationService.saveDirectory(DirectoryType.GSuite, this.gsuite); + await this.configurationService.saveDirectory(DirectoryType.AzureActiveDirectory, this.azure); + await this.configurationService.saveSync(this.sync); } } diff --git a/src/services/azure-directory.service.ts b/src/services/azure-directory.service.ts index 4e0b8f22..35138238 100644 --- a/src/services/azure-directory.service.ts +++ b/src/services/azure-directory.service.ts @@ -2,28 +2,32 @@ import * as graph from '@microsoft/microsoft-graph-client'; import * as https from 'https'; import * as querystring from 'querystring'; -import { DirectoryService } from 'src/services/directory.service'; +import { DirectoryType } from '../enums/directoryType'; -const Key = ''; -const ApplicationId = ''; -const Tenant = ''; +import { AzureConfiguration } from '../models/azureConfiguration'; +import { SyncConfiguration } from '../models/syncConfiguration'; + +import { ConfigurationService } from './configuration.service'; +import { DirectoryService } from './directory.service'; export class AzureDirectoryService implements DirectoryService { private client: graph.Client; + private dirConfig: AzureConfiguration; + private syncConfig: SyncConfiguration; - async getEntries(force = false) { + constructor(private configurationService: ConfigurationService) { this.client = graph.Client.init({ authProvider: (done) => { const data = querystring.stringify({ - client_id: ApplicationId, - client_secret: Key, + client_id: this.dirConfig.applicationId, + client_secret: this.dirConfig.key, grant_type: 'client_credentials', scope: 'https://graph.microsoft.com/.default', }); const req = https.request({ host: 'login.microsoftonline.com', - path: '/' + Tenant + '/oauth2/v2.0/token', + path: '/' + this.dirConfig.tenant + '/oauth2/v2.0/token', method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', @@ -49,6 +53,24 @@ export class AzureDirectoryService implements DirectoryService { req.end(); }, }); + } + + async getEntries(force = false) { + const type = await this.configurationService.getDirectoryType(); + if (type !== DirectoryType.AzureActiveDirectory) { + return; + } + + this.dirConfig = await this.configurationService.getDirectory( + DirectoryType.AzureActiveDirectory); + if (this.dirConfig == null) { + return; + } + + this.syncConfig = await this.configurationService.getSync(); + if (this.syncConfig == null) { + return; + } await this.getUsers(); await this.getGroups(); diff --git a/src/services/configuration.service.ts b/src/services/configuration.service.ts index 14a187da..80e93db4 100644 --- a/src/services/configuration.service.ts +++ b/src/services/configuration.service.ts @@ -1,6 +1,10 @@ import { DirectoryType } from '../enums/directoryType'; import { StorageService } from 'jslib/abstractions/storage.service'; +import { AzureConfiguration } from '../models/azureConfiguration'; +import { GSuiteConfiguration } from '../models/gsuiteConfiguration'; +import { LdapConfiguration } from '../models/ldapConfiguration'; +import { SyncConfiguration } from '../models/syncConfiguration'; const StoredSecurely = '[STORED SECURELY]'; const Keys = { @@ -8,12 +12,14 @@ const Keys = { gsuite: 'gsuitePrivateKey', azure: 'azureKey', directoryConfigPrefix: 'directoryConfig_', + sync: 'syncConfig', + directoryType: 'directoryType', }; export class ConfigurationService { constructor(private storageService: StorageService, private secureStorageService: StorageService) { } - async get(type: DirectoryType): Promise { + async getDirectory(type: DirectoryType): Promise { const config = await this.storageService.get(Keys.directoryConfigPrefix + type); if (config == null) { return config; @@ -33,7 +39,8 @@ export class ConfigurationService { return config; } - async save(type: DirectoryType, config: T): Promise { + async saveDirectory(type: DirectoryType, + config: LdapConfiguration | GSuiteConfiguration | AzureConfiguration): Promise { const savedConfig: any = Object.assign({}, config); switch (type) { case DirectoryType.Ldap: @@ -56,6 +63,8 @@ export class ConfigurationService { if (savedConfig.privateKey == null) { await this.secureStorageService.remove(Keys.gsuite); } else { + (config as any).privateKey = savedConfig.privateKey = + savedConfig.privateKey.replace(/\\n/g, '\n'); await this.secureStorageService.save(Keys.gsuite, savedConfig.privateKey); savedConfig.privateKey = StoredSecurely; } @@ -63,4 +72,20 @@ export class ConfigurationService { } await this.storageService.save(Keys.directoryConfigPrefix + type, savedConfig); } + + async getSync(): Promise { + return this.storageService.get(Keys.sync); + } + + async saveSync(config: SyncConfiguration) { + return this.storageService.save(Keys.sync, config); + } + + async getDirectoryType(): Promise { + return this.storageService.get(Keys.directoryType); + } + + async saveDirectoryType(type: DirectoryType) { + return this.storageService.save(Keys.directoryType, type); + } } diff --git a/src/services/gsuite-directory.service.ts b/src/services/gsuite-directory.service.ts index 87de4ef8..7a3744ea 100644 --- a/src/services/gsuite-directory.service.ts +++ b/src/services/gsuite-directory.service.ts @@ -2,23 +2,41 @@ import { JWT } from 'google-auth-library'; import { google, GoogleApis } from 'googleapis'; import { Admin } from 'googleapis/build/src/apis/admin/directory_v1'; -import { DirectoryService } from 'src/services/directory.service'; +import { DirectoryType } from '../enums/directoryType'; -const PrivateKey = ''; -const ClientEmail = ''; -const AdminEmail = ''; -const Domain = ''; +import { GSuiteConfiguration } from '../models/gsuiteConfiguration'; +import { SyncConfiguration } from '../models/syncConfiguration'; + +import { ConfigurationService } from './configuration.service'; +import { DirectoryService } from './directory.service'; export class GSuiteDirectoryService implements DirectoryService { private client: JWT; private service: Admin; private authParams: any; + private dirConfig: GSuiteConfiguration; + private syncConfig: SyncConfiguration; - constructor() { + constructor(private configurationService: ConfigurationService) { this.service = google.admin('directory_v1'); } async getEntries(force = false) { + const type = await this.configurationService.getDirectoryType(); + if (type !== DirectoryType.GSuite) { + return; + } + + this.dirConfig = await this.configurationService.getDirectory(DirectoryType.GSuite); + if (this.dirConfig == null) { + return; + } + + this.syncConfig = await this.configurationService.getSync(); + if (this.syncConfig == null) { + return; + } + await this.auth(); await this.getUsers(); await this.getGroups(); @@ -48,9 +66,9 @@ export class GSuiteDirectoryService implements DirectoryService { private async auth() { this.client = new google.auth.JWT({ - email: ClientEmail, - key: PrivateKey, - subject: AdminEmail, + email: this.dirConfig.clientEmail, + key: this.dirConfig.privateKey, + subject: this.dirConfig.adminUser, scopes: [ 'https://www.googleapis.com/auth/admin.directory.user.readonly', 'https://www.googleapis.com/auth/admin.directory.group.readonly', @@ -59,11 +77,13 @@ export class GSuiteDirectoryService implements DirectoryService { }); await this.client.authorize(); + this.authParams = { auth: this.client, - domain: Domain, + domain: this.dirConfig.domain, }; - - // TODO: add customer? + if (this.dirConfig.customer != null) { + this.authParams.customer = this.dirConfig.customer; + } } } diff --git a/src/services/ldap-directory.service.ts b/src/services/ldap-directory.service.ts index 6a94632e..620dd8a8 100644 --- a/src/services/ldap-directory.service.ts +++ b/src/services/ldap-directory.service.ts @@ -1,15 +1,36 @@ import * as ldap from 'ldapjs'; -import { DirectoryService } from 'src/services/directory.service'; +import { DirectoryType } from '../enums/directoryType'; -const Url = 'ldap://ldap.forumsys.com:389'; -const Username = 'cn=read-only-admin,dc=example,dc=com'; -const Password = 'password'; +import { LdapConfiguration } from '../models/ldapConfiguration'; +import { SyncConfiguration } from '../models/syncConfiguration'; + +import { ConfigurationService } from './configuration.service'; +import { DirectoryService } from './directory.service'; export class LdapDirectoryService implements DirectoryService { private client: ldap.Client; + private dirConfig: LdapConfiguration; + private syncConfig: SyncConfiguration; + + constructor(private configurationService: ConfigurationService) { } async getEntries(force = false) { + const type = await this.configurationService.getDirectoryType(); + if (type !== DirectoryType.Ldap) { + return; + } + + this.dirConfig = await this.configurationService.getDirectory(DirectoryType.Ldap); + if (this.dirConfig == null) { + return; + } + + this.syncConfig = await this.configurationService.getSync(); + if (this.syncConfig == null) { + return; + } + await this.auth(); await this.getUsers(); } @@ -49,11 +70,13 @@ export class LdapDirectoryService implements DirectoryService { private async auth() { return new Promise((resolve, reject) => { + const url = 'ldap' + (this.dirConfig.ssl ? 's' : '') + '://' + this.dirConfig.hostname + + ':' + this.dirConfig.port; this.client = ldap.createClient({ - url: Url, + url: url, }); - this.client.bind(Username, Password, (err) => { + this.client.bind(this.dirConfig.username, this.dirConfig.password, (err) => { if (err != null) { reject(err); } else { diff --git a/src/services/sync.service.ts b/src/services/sync.service.ts new file mode 100644 index 00000000..78884a2d --- /dev/null +++ b/src/services/sync.service.ts @@ -0,0 +1,45 @@ +import { DirectoryType } from '../enums/directoryType'; + +import { StorageService } from 'jslib/abstractions/storage.service'; + +import { AzureDirectoryService } from './azure-directory.service'; +import { ConfigurationService } from './configuration.service'; +import { DirectoryService } from './directory.service'; +import { GSuiteDirectoryService } from './gsuite-directory.service'; +import { LdapDirectoryService } from './ldap-directory.service'; + +const Keys = { +}; + +export class SyncService { + private dirType: DirectoryType; + + constructor(private configurationService: ConfigurationService) { } + + async sync(force = true, sendToServer = true): Promise { + this.dirType = await this.configurationService.getDirectoryType(); + if (this.dirType == null) { + return; + } + + const directoryService = this.getDirectoryService(); + if (directoryService == null) { + return; + } + + directoryService.getEntries(force); + } + + private getDirectoryService(): DirectoryService { + switch (this.dirType) { + case DirectoryType.GSuite: + return new GSuiteDirectoryService(this.configurationService); + case DirectoryType.AzureActiveDirectory: + return new AzureDirectoryService(this.configurationService); + case DirectoryType.Ldap: + return new LdapDirectoryService(this.configurationService); + default: + return null; + } + } +}