mirror of
https://github.com/bitwarden/directory-connector
synced 2025-12-05 23:53:21 +00:00
gsuite directory query logic to make entries result
This commit is contained in:
@@ -71,7 +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 syncSevrice = new SyncService(configurationService, logService);
|
||||
|
||||
const analytics = new Analytics(window, () => true, platformUtilsService, storageService, appIdService);
|
||||
containerService.attachToWindow(window);
|
||||
|
||||
@@ -5,7 +5,9 @@ import * as querystring from 'querystring';
|
||||
import { DirectoryType } from '../enums/directoryType';
|
||||
|
||||
import { AzureConfiguration } from '../models/azureConfiguration';
|
||||
import { GroupEntry } from '../models/groupEntry';
|
||||
import { SyncConfiguration } from '../models/syncConfiguration';
|
||||
import { UserEntry } from '../models/userEntry';
|
||||
|
||||
import { ConfigurationService } from './configuration.service';
|
||||
import { DirectoryService } from './directory.service';
|
||||
@@ -55,7 +57,7 @@ export class AzureDirectoryService implements DirectoryService {
|
||||
});
|
||||
}
|
||||
|
||||
async getEntries(force = false) {
|
||||
async getEntries(force = false): Promise<[GroupEntry[], UserEntry[]]> {
|
||||
const type = await this.configurationService.getDirectoryType();
|
||||
if (type !== DirectoryType.AzureActiveDirectory) {
|
||||
return;
|
||||
@@ -74,6 +76,8 @@ export class AzureDirectoryService implements DirectoryService {
|
||||
|
||||
await this.getUsers();
|
||||
await this.getGroups();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private async getUsers() {
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import { GroupEntry } from '../models/groupEntry';
|
||||
import { UserEntry } from '../models/userEntry';
|
||||
|
||||
export interface DirectoryService {
|
||||
getEntries(force?: boolean): any;
|
||||
getEntries(force?: boolean): Promise<[GroupEntry[], UserEntry[]]>;
|
||||
}
|
||||
|
||||
@@ -1,15 +1,26 @@
|
||||
import { JWT } from 'google-auth-library';
|
||||
import { google, GoogleApis } from 'googleapis';
|
||||
import { Admin } from 'googleapis/build/src/apis/admin/directory_v1';
|
||||
import {
|
||||
google,
|
||||
GoogleApis,
|
||||
} from 'googleapis';
|
||||
import {
|
||||
Admin,
|
||||
Schema$Group,
|
||||
Schema$User,
|
||||
} from 'googleapis/build/src/apis/admin/directory_v1';
|
||||
|
||||
import { DirectoryType } from '../enums/directoryType';
|
||||
|
||||
import { GroupEntry } from '../models/groupEntry';
|
||||
import { GSuiteConfiguration } from '../models/gsuiteConfiguration';
|
||||
import { SyncConfiguration } from '../models/syncConfiguration';
|
||||
import { UserEntry } from '../models/userEntry';
|
||||
|
||||
import { ConfigurationService } from './configuration.service';
|
||||
import { DirectoryService } from './directory.service';
|
||||
|
||||
import { LogService } from 'jslib/abstractions/log.service';
|
||||
|
||||
export class GSuiteDirectoryService implements DirectoryService {
|
||||
private client: JWT;
|
||||
private service: Admin;
|
||||
@@ -17,11 +28,11 @@ export class GSuiteDirectoryService implements DirectoryService {
|
||||
private dirConfig: GSuiteConfiguration;
|
||||
private syncConfig: SyncConfiguration;
|
||||
|
||||
constructor(private configurationService: ConfigurationService) {
|
||||
constructor(private configurationService: ConfigurationService, private logService: LogService) {
|
||||
this.service = google.admin<Admin>('directory_v1');
|
||||
}
|
||||
|
||||
async getEntries(force = false) {
|
||||
async getEntries(force = false): Promise<[GroupEntry[], UserEntry[]]> {
|
||||
const type = await this.configurationService.getDirectoryType();
|
||||
if (type !== DirectoryType.GSuite) {
|
||||
return;
|
||||
@@ -38,30 +49,201 @@ export class GSuiteDirectoryService implements DirectoryService {
|
||||
}
|
||||
|
||||
await this.auth();
|
||||
await this.getUsers();
|
||||
await this.getGroups();
|
||||
}
|
||||
|
||||
private async getUsers() {
|
||||
const response = await this.service.users.list(this.authParams);
|
||||
console.log(response);
|
||||
}
|
||||
|
||||
private async getGroups() {
|
||||
const response = await this.service.groups.list(this.authParams);
|
||||
console.log(response);
|
||||
|
||||
if (response.data.groups.length === 0) {
|
||||
return;
|
||||
let users: UserEntry[];
|
||||
if (this.syncConfig.users) {
|
||||
users = await this.getUsers();
|
||||
}
|
||||
|
||||
response.data.groups.forEach(async (g) => {
|
||||
const params: any = Object.assign({
|
||||
groupKey: g.id,
|
||||
}, this.authParams);
|
||||
const members = await this.service.members.list(params);
|
||||
console.log(members);
|
||||
let groups: GroupEntry[];
|
||||
if (this.syncConfig.groups) {
|
||||
groups = await this.getGroups();
|
||||
}
|
||||
|
||||
return [groups, users];
|
||||
}
|
||||
|
||||
private async getUsers(): Promise<UserEntry[]> {
|
||||
const entries: UserEntry[] = [];
|
||||
const query = this.createQuery(this.syncConfig.userFilter);
|
||||
|
||||
this.logService.info('Querying users.');
|
||||
let p = Object.assign({ query: query }, this.authParams);
|
||||
const res = await this.service.users.list(p);
|
||||
if (res.status !== 200) {
|
||||
throw new Error('User list API failed: ' + res.statusText);
|
||||
}
|
||||
|
||||
const filter = this.createSet(this.syncConfig.userFilter);
|
||||
if (res.data.users != null) {
|
||||
res.data.users.forEach((user) => {
|
||||
if (this.filterOutResult(filter, user.primaryEmail)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const entry = this.buildUser(user, false);
|
||||
if (entry != null) {
|
||||
entries.push(entry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.logService.info('Querying deleted users.');
|
||||
p = Object.assign({ showDeleted: true, query: query }, this.authParams);
|
||||
const delRes = await this.service.users.list(p);
|
||||
if (delRes.status !== 200) {
|
||||
throw new Error('Deleted user list API failed: ' + delRes.statusText);
|
||||
}
|
||||
|
||||
if (delRes.data.users != null) {
|
||||
delRes.data.users.forEach((user) => {
|
||||
if (this.filterOutResult(filter, user.primaryEmail)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const entry = this.buildUser(user, true);
|
||||
if (entry != null) {
|
||||
entries.push(entry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
private buildUser(user: Schema$User, deleted: boolean) {
|
||||
if ((user.emails == null || user.emails === '') && !deleted) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const entry = new UserEntry();
|
||||
entry.referenceId = user.id;
|
||||
entry.externalId = user.id;
|
||||
entry.email = user.primaryEmail;
|
||||
entry.disabled = user.suspended || false;
|
||||
entry.deleted = deleted;
|
||||
// entry.creationDate = user.creationTime; // TODO: string to date conversion
|
||||
return entry;
|
||||
}
|
||||
|
||||
private async getGroups(): Promise<GroupEntry[]> {
|
||||
const entries: GroupEntry[] = [];
|
||||
|
||||
this.logService.info('Querying groups.');
|
||||
const res = await this.service.groups.list(this.authParams);
|
||||
if (res.status !== 200) {
|
||||
throw new Error('Group list API failed: ' + res.statusText);
|
||||
}
|
||||
|
||||
const filter = this.createSet(this.syncConfig.groupFilter);
|
||||
if (res.data.groups != null) {
|
||||
res.data.groups.forEach(async (group) => {
|
||||
if (this.filterOutResult(filter, group.name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const entry = await this.buildGroup(group);
|
||||
entries.push(entry);
|
||||
});
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
private async buildGroup(group: Schema$Group) {
|
||||
const entry = new GroupEntry();
|
||||
entry.referenceId = group.id;
|
||||
entry.externalId = group.id;
|
||||
entry.name = group.name;
|
||||
|
||||
const p = Object.assign({ groupKey: group.id }, this.authParams);
|
||||
const memRes = await this.service.members.list(p);
|
||||
if (memRes.status !== 200) {
|
||||
this.logService.warning('Group member list API failed: ' + memRes.statusText);
|
||||
return entry;
|
||||
}
|
||||
|
||||
if (memRes.data.members != null) {
|
||||
memRes.data.members.forEach((member) => {
|
||||
if (member.role.toLowerCase() !== 'member') {
|
||||
return;
|
||||
}
|
||||
if (member.status.toLowerCase() !== 'active') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (member.type.toLowerCase() === 'user') {
|
||||
entry.userMemberExternalIds.add(member.id);
|
||||
} else if (member.type.toLowerCase() === 'group') {
|
||||
entry.groupMemberReferenceIds.add(member.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
private createQuery(filter: string) {
|
||||
if (filter == null || filter === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
const mainParts = filter.split('|');
|
||||
if (mainParts.length < 2 || mainParts[1] == null || mainParts[1].trim() === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return mainParts[1].trim();
|
||||
}
|
||||
|
||||
private createSet(filter: string): [boolean, Set<string>] {
|
||||
if (filter == null || filter === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
const mainParts = filter.split('|');
|
||||
if (mainParts.length < 1 || mainParts[0] == null || mainParts[0].trim() === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
const parts = mainParts[0].split(':');
|
||||
if (parts.length !== 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const keyword = parts[0].trim().toLowerCase();
|
||||
let exclude = true;
|
||||
if (keyword === 'include') {
|
||||
exclude = false;
|
||||
} else if (keyword === 'exclude') {
|
||||
exclude = true;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
const set = new Set<string>();
|
||||
const pieces = parts[1].split(',');
|
||||
pieces.forEach((p) => {
|
||||
set.add(p.trim().toLowerCase());
|
||||
});
|
||||
|
||||
return [exclude, set];
|
||||
}
|
||||
|
||||
private filterOutResult(filter: [boolean, Set<string>], result: string) {
|
||||
if (filter != null) {
|
||||
result = result.trim().toLowerCase();
|
||||
const excluded = filter[0];
|
||||
const set = filter[1];
|
||||
|
||||
if (excluded && set.has(result)) {
|
||||
return true;
|
||||
} else if (!excluded && !set.has(result)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private async auth() {
|
||||
|
||||
@@ -2,8 +2,10 @@ import * as ldap from 'ldapjs';
|
||||
|
||||
import { DirectoryType } from '../enums/directoryType';
|
||||
|
||||
import { GroupEntry } from '../models/groupEntry';
|
||||
import { LdapConfiguration } from '../models/ldapConfiguration';
|
||||
import { SyncConfiguration } from '../models/syncConfiguration';
|
||||
import { UserEntry } from '../models/userEntry';
|
||||
|
||||
import { ConfigurationService } from './configuration.service';
|
||||
import { DirectoryService } from './directory.service';
|
||||
@@ -15,7 +17,7 @@ export class LdapDirectoryService implements DirectoryService {
|
||||
|
||||
constructor(private configurationService: ConfigurationService) { }
|
||||
|
||||
async getEntries(force = false) {
|
||||
async getEntries(force = false): Promise<[GroupEntry[], UserEntry[]]> {
|
||||
const type = await this.configurationService.getDirectoryType();
|
||||
if (type !== DirectoryType.Ldap) {
|
||||
return;
|
||||
@@ -33,6 +35,8 @@ export class LdapDirectoryService implements DirectoryService {
|
||||
|
||||
await this.auth();
|
||||
await this.getUsers();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private getUsers() {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { DirectoryType } from '../enums/directoryType';
|
||||
|
||||
import { LogService } from 'jslib/abstractions/log.service';
|
||||
import { StorageService } from 'jslib/abstractions/storage.service';
|
||||
|
||||
import { AzureDirectoryService } from './azure-directory.service';
|
||||
@@ -14,7 +15,7 @@ const Keys = {
|
||||
export class SyncService {
|
||||
private dirType: DirectoryType;
|
||||
|
||||
constructor(private configurationService: ConfigurationService) { }
|
||||
constructor(private configurationService: ConfigurationService, private logService: LogService) { }
|
||||
|
||||
async sync(force = true, sendToServer = true): Promise<any> {
|
||||
this.dirType = await this.configurationService.getDirectoryType();
|
||||
@@ -27,13 +28,14 @@ export class SyncService {
|
||||
return;
|
||||
}
|
||||
|
||||
directoryService.getEntries(force);
|
||||
const entries = await directoryService.getEntries(force);
|
||||
console.log(entries);
|
||||
}
|
||||
|
||||
private getDirectoryService(): DirectoryService {
|
||||
switch (this.dirType) {
|
||||
case DirectoryType.GSuite:
|
||||
return new GSuiteDirectoryService(this.configurationService);
|
||||
return new GSuiteDirectoryService(this.configurationService, this.logService);
|
||||
case DirectoryType.AzureActiveDirectory:
|
||||
return new AzureDirectoryService(this.configurationService);
|
||||
case DirectoryType.Ldap:
|
||||
|
||||
Reference in New Issue
Block a user