26 changed files with 259 additions and 37 deletions
@ -1,10 +0,0 @@
@@ -1,10 +0,0 @@
|
||||
if ! [ -x "$(command -v mkcert)" ]; then |
||||
echo 'Error: mkcert is not installed. Install mkcert first and then re-run this script.' |
||||
echo 'e.g. brew install mkcert' |
||||
exit 1 |
||||
fi |
||||
|
||||
mkcert -install |
||||
mkdir -p ./openldap/certs |
||||
cp "$(mkcert -CAROOT)/rootCA.pem" ./openldap/certs/rootCA.pem |
||||
mkcert -key-file ./openldap/certs/openldap-key.pem -cert-file ./openldap/certs/openldap.pem localhost openldap |
||||
@ -0,0 +1,82 @@
@@ -0,0 +1,82 @@
|
||||
import { config as dotenvConfig } from "dotenv"; |
||||
import { mock, MockProxy } from "jest-mock-extended"; |
||||
|
||||
import { I18nService } from "../../jslib/common/src/abstractions/i18n.service"; |
||||
import { LogService } from "../../jslib/common/src/abstractions/log.service"; |
||||
import { |
||||
getGSuiteConfiguration, |
||||
getSyncConfiguration, |
||||
} from "../../utils/google-workspace/config-fixtures"; |
||||
import { groupFixtures } from "../../utils/google-workspace/group-fixtures"; |
||||
import { userFixtures } from "../../utils/google-workspace/user-fixtures"; |
||||
import { DirectoryType } from "../enums/directoryType"; |
||||
|
||||
import { GSuiteDirectoryService } from "./gsuite-directory.service"; |
||||
import { StateService } from "./state.service"; |
||||
|
||||
// These tests integrate with a test Google Workspace instance.
|
||||
// Credentials are located in the shared Bitwarden collection for Directory Connector testing.
|
||||
// Place the .env file attachment in the utils folder.
|
||||
|
||||
// Load .env variables
|
||||
dotenvConfig({ path: "utils/.env" }); |
||||
|
||||
// These filters target integration test data.
|
||||
// These should return data that matches the user and group fixtures exactly.
|
||||
// There may be additional data present if not used.
|
||||
const INTEGRATION_USER_FILTER = |
||||
"exclude:integration-user-a@bwrox.dev|orgUnitPath='/Integration testing'"; |
||||
const INTEGRATION_GROUP_FILTER = "|name:Integration*"; |
||||
|
||||
describe("gsuiteDirectoryService", () => { |
||||
let logService: MockProxy<LogService>; |
||||
let i18nService: MockProxy<I18nService>; |
||||
let stateService: MockProxy<StateService>; |
||||
|
||||
let directoryService: GSuiteDirectoryService; |
||||
|
||||
beforeEach(() => { |
||||
logService = mock(); |
||||
i18nService = mock(); |
||||
stateService = mock(); |
||||
|
||||
stateService.getDirectoryType.mockResolvedValue(DirectoryType.GSuite); |
||||
stateService.getLastUserSync.mockResolvedValue(null); // do not filter results by last modified date
|
||||
i18nService.t.mockImplementation((id) => id); // passthrough implementation for any error messages
|
||||
|
||||
directoryService = new GSuiteDirectoryService(logService, i18nService, stateService); |
||||
}); |
||||
|
||||
it("syncs without using filters (includes test data)", async () => { |
||||
const directoryConfig = getGSuiteConfiguration(); |
||||
stateService.getDirectory.calledWith(DirectoryType.GSuite).mockResolvedValue(directoryConfig); |
||||
|
||||
const syncConfig = getSyncConfiguration({ |
||||
groups: true, |
||||
users: true, |
||||
}); |
||||
stateService.getSync.mockResolvedValue(syncConfig); |
||||
|
||||
const result = await directoryService.getEntries(true, true); |
||||
|
||||
expect(result[0]).toEqual(expect.arrayContaining(groupFixtures)); |
||||
expect(result[1]).toEqual(expect.arrayContaining(userFixtures)); |
||||
}); |
||||
|
||||
it("syncs using user and group filters (exact match for test data)", async () => { |
||||
const directoryConfig = getGSuiteConfiguration(); |
||||
stateService.getDirectory.calledWith(DirectoryType.GSuite).mockResolvedValue(directoryConfig); |
||||
|
||||
const syncConfig = getSyncConfiguration({ |
||||
groups: true, |
||||
users: true, |
||||
userFilter: INTEGRATION_USER_FILTER, |
||||
groupFilter: INTEGRATION_GROUP_FILTER, |
||||
}); |
||||
stateService.getSync.mockResolvedValue(syncConfig); |
||||
|
||||
const result = await directoryService.getEntries(true, true); |
||||
|
||||
expect(result).toEqual([groupFixtures, userFixtures]); |
||||
}); |
||||
}); |
||||
@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
|
||||
GOOGLE_DOMAIN= |
||||
GOOGLE_ADMIN_USER= |
||||
GOOGLE_CLIENT_EMAIL= |
||||
GOOGLE_PRIVATE_KEY= |
||||
@ -0,0 +1,56 @@
@@ -0,0 +1,56 @@
|
||||
import { GSuiteConfiguration } from "../../src/models/gsuiteConfiguration"; |
||||
import { SyncConfiguration } from "../../src/models/syncConfiguration"; |
||||
|
||||
/** |
||||
* @returns a basic GSuite configuration. Can be overridden by passing in a partial configuration. |
||||
*/ |
||||
export const getGSuiteConfiguration = ( |
||||
config?: Partial<GSuiteConfiguration>, |
||||
): GSuiteConfiguration => { |
||||
const adminUser = process.env.GOOGLE_ADMIN_USER; |
||||
const clientEmail = process.env.GOOGLE_CLIENT_EMAIL; |
||||
const privateKey = process.env.GOOGLE_PRIVATE_KEY; |
||||
const domain = process.env.GOOGLE_DOMAIN; |
||||
|
||||
if (!adminUser || !clientEmail || !privateKey || !domain) { |
||||
throw new Error("Google Workspace integration test credentials not configured."); |
||||
} |
||||
|
||||
return { |
||||
// TODO
|
||||
adminUser, |
||||
clientEmail, |
||||
privateKey, |
||||
domain: domain, |
||||
customer: "", |
||||
...(config ?? {}), |
||||
}; |
||||
}; |
||||
|
||||
/** |
||||
* @returns a basic Google Workspace sync configuration. Can be overridden by passing in a partial configuration. |
||||
*/ |
||||
export const getSyncConfiguration = (config?: Partial<SyncConfiguration>): SyncConfiguration => ({ |
||||
users: false, |
||||
groups: false, |
||||
interval: 5, |
||||
userFilter: "", |
||||
groupFilter: "", |
||||
removeDisabled: false, |
||||
overwriteExisting: false, |
||||
largeImport: false, |
||||
// Ldap properties - not optional for some reason
|
||||
groupObjectClass: "", |
||||
userObjectClass: "", |
||||
groupPath: null, |
||||
userPath: null, |
||||
groupNameAttribute: "", |
||||
userEmailAttribute: "", |
||||
memberAttribute: "", |
||||
useEmailPrefixSuffix: false, |
||||
emailPrefixAttribute: "", |
||||
emailSuffix: null, |
||||
creationDateAttribute: "", |
||||
revisionDateAttribute: "", |
||||
...(config ?? {}), |
||||
}); |
||||
@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
|
||||
import { Jsonify } from "type-fest"; |
||||
|
||||
import { GroupEntry } from "../../src/models/groupEntry"; |
||||
|
||||
// These must match the Google Workspace seed data
|
||||
|
||||
const data: Jsonify<GroupEntry>[] = [ |
||||
{ |
||||
externalId: "0319y80a3anpxhj", |
||||
groupMemberReferenceIds: [], |
||||
name: "Integration Test Group A", |
||||
referenceId: "0319y80a3anpxhj", |
||||
userMemberExternalIds: ["111605910541641314041", "111147009830456099026"], |
||||
users: [], |
||||
}, |
||||
{ |
||||
externalId: "02afmg28317uyub", |
||||
groupMemberReferenceIds: [], |
||||
name: "Integration Test Group B", |
||||
referenceId: "02afmg28317uyub", |
||||
userMemberExternalIds: ["111147009830456099026", "100150970267699397306"], |
||||
users: [], |
||||
}, |
||||
]; |
||||
|
||||
export const groupFixtures = data.map((g) => GroupEntry.fromJSON(g)); |
||||
@ -0,0 +1,50 @@
@@ -0,0 +1,50 @@
|
||||
import { Jsonify } from "type-fest"; |
||||
|
||||
import { UserEntry } from "../../src/models/userEntry"; |
||||
|
||||
// These must match the Google Workspace seed data
|
||||
|
||||
const data: Jsonify<UserEntry>[] = [ |
||||
// In Group A
|
||||
{ |
||||
deleted: false, |
||||
disabled: false, |
||||
email: "testuser1@bwrox.dev", |
||||
externalId: "111605910541641314041", |
||||
referenceId: "111605910541641314041", |
||||
}, |
||||
// In Groups A + B
|
||||
{ |
||||
deleted: false, |
||||
disabled: false, |
||||
email: "testuser2@bwrox.dev", |
||||
externalId: "111147009830456099026", |
||||
referenceId: "111147009830456099026", |
||||
}, |
||||
// In Group B
|
||||
{ |
||||
deleted: false, |
||||
disabled: false, |
||||
email: "testuser3@bwrox.dev", |
||||
externalId: "100150970267699397306", |
||||
referenceId: "100150970267699397306", |
||||
}, |
||||
// Not in a group
|
||||
{ |
||||
deleted: false, |
||||
disabled: false, |
||||
email: "testuser4@bwrox.dev", |
||||
externalId: "113764752650306721470", |
||||
referenceId: "113764752650306721470", |
||||
}, |
||||
// Disabled user
|
||||
{ |
||||
deleted: false, |
||||
disabled: true, |
||||
email: "testuser5@bwrox.dev", |
||||
externalId: "110381976819725658200", |
||||
referenceId: "110381976819725658200", |
||||
}, |
||||
]; |
||||
|
||||
export const userFixtures = data.map((g) => UserEntry.fromJSON(g)); |
||||
@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
|
||||
import { LdapConfiguration } from "../models/ldapConfiguration"; |
||||
import { SyncConfiguration } from "../models/syncConfiguration"; |
||||
import { LdapConfiguration } from "../../src/models/ldapConfiguration"; |
||||
import { SyncConfiguration } from "../../src/models/syncConfiguration"; |
||||
|
||||
/** |
||||
* @returns a basic ldap configuration without TLS/SSL enabled. Can be overridden by passing in a partial configuration. |
||||
@ -1,6 +1,6 @@
@@ -1,6 +1,6 @@
|
||||
import { Jsonify } from "type-fest"; |
||||
|
||||
import { GroupEntry } from "../src/models/groupEntry"; |
||||
import { GroupEntry } from "@/src/models/groupEntry"; |
||||
|
||||
// These must match the ldap server seed data in directory.ldif
|
||||
const data: Jsonify<GroupEntry>[] = [ |
||||
@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
|
||||
if ! [ -x "$(command -v mkcert)" ]; then |
||||
echo 'Error: mkcert is not installed. Install mkcert first and then re-run this script.' |
||||
echo 'e.g. brew install mkcert' |
||||
exit 1 |
||||
fi |
||||
|
||||
mkcert -install |
||||
mkdir -p ./utils/openldap/certs |
||||
cp "$(mkcert -CAROOT)/rootCA.pem" ./utils/openldap/certs/rootCA.pem |
||||
mkcert -key-file ./utils/openldap/certs/openldap-key.pem -cert-file ./utils/openldap/certs/openldap.pem localhost openldap |
||||
@ -1,6 +1,6 @@
@@ -1,6 +1,6 @@
|
||||
import { Jsonify } from "type-fest"; |
||||
|
||||
import { UserEntry } from "../src/models/userEntry"; |
||||
import { UserEntry } from "@/src/models/userEntry"; |
||||
|
||||
// These must match the ldap server seed data in directory.ldif
|
||||
const data: Jsonify<UserEntry>[] = [ |
||||
@ -1,7 +1,7 @@
@@ -1,7 +1,7 @@
|
||||
import { GetUniqueString } from "@/jslib/common/spec/utils"; |
||||
|
||||
import { GroupEntry } from "../models/groupEntry"; |
||||
import { UserEntry } from "../models/userEntry"; |
||||
import { GroupEntry } from "../src/models/groupEntry"; |
||||
import { UserEntry } from "../src/models/userEntry"; |
||||
|
||||
export function userSimulator(userCount: number): UserEntry[] { |
||||
const users: UserEntry[] = []; |
||||
Loading…
Reference in new issue