mirror of
https://github.com/bitwarden/directory-connector
synced 2025-12-05 23:53:21 +00:00
suggestion changes
This commit is contained in:
committed by
Thomas Rittson
parent
2ca8654492
commit
0ce4547d34
@@ -37,9 +37,9 @@ const data: Jsonify<GroupEntry>[] = [
|
||||
},
|
||||
{
|
||||
userMemberExternalIds: [
|
||||
"cn=Benjamin Chen,ou=Product Development,dc=bitwarden,dc=com",
|
||||
"cn=Karen Smith,ou=Product Development,dc=bitwarden,dc=com",
|
||||
"cn=Robert Johnson,ou=Product Development,dc=bitwarden,dc=com",
|
||||
"cn=Painterson Miki,ou=Product Development,dc=bitwarden,dc=com",
|
||||
"cn=Virgina Pichocki,ou=Product Development,dc=bitwarden,dc=com",
|
||||
"cn=Steffen Carsten,ou=Product Development,dc=bitwarden,dc=com",
|
||||
],
|
||||
groupMemberReferenceIds: [],
|
||||
users: [],
|
||||
@@ -49,8 +49,8 @@ const data: Jsonify<GroupEntry>[] = [
|
||||
},
|
||||
{
|
||||
userMemberExternalIds: [
|
||||
"cn=Thomas Williams,ou=Management,dc=bitwarden,dc=com",
|
||||
"cn=Michelle Brown,ou=Management,dc=bitwarden,dc=com",
|
||||
"cn=Angus Merizzi,ou=Management,dc=bitwarden,dc=com",
|
||||
"cn=Grissel Currer,ou=Management,dc=bitwarden,dc=com",
|
||||
],
|
||||
groupMemberReferenceIds: [],
|
||||
users: [],
|
||||
|
||||
@@ -690,13 +690,17 @@ roomNumber: 9273
|
||||
manager: cn=Inga Schnirer,ou=Product Testing,dc=bitwarden, dc=com
|
||||
secretary: cn=Keven Gilleland,ou=Administrative,dc=bitwarden, dc=com
|
||||
|
||||
# DevOps Team and Security Team identify their members by the member uid attribute,
|
||||
# instead of the member Dn attribute.
|
||||
# These test that group membership by uid works correctly.
|
||||
|
||||
dn: cn=DevOps Team,dc=bitwarden,dc=com
|
||||
changetype: add
|
||||
cn: DevOps Team
|
||||
gidnumber: 800
|
||||
memberuid: ChenB
|
||||
memberuid: SmithK
|
||||
memberuid: JohnsonR
|
||||
memberuid: mikip
|
||||
memberuid: pichockv
|
||||
memberuid: carstens
|
||||
objectclass: posixGroup
|
||||
objectclass: top
|
||||
|
||||
@@ -704,157 +708,9 @@ dn: cn=Security Team,dc=bitwarden,dc=com
|
||||
changetype: add
|
||||
cn: Security Team
|
||||
gidnumber: 900
|
||||
memberuid: WilliamsT
|
||||
memberuid: BrownM
|
||||
memberuid: merizzia
|
||||
memberuid: currerg
|
||||
objectclass: posixGroup
|
||||
objectclass: top
|
||||
|
||||
dn: cn=Benjamin Chen,ou=Product Development,dc=bitwarden, dc=com
|
||||
changetype: add
|
||||
objectClass: top
|
||||
objectClass: person
|
||||
objectClass: organizationalPerson
|
||||
objectClass: inetOrgPerson
|
||||
cn: Benjamin Chen
|
||||
sn: Chen
|
||||
description: This is Benjamin Chen's description
|
||||
facsimileTelephoneNumber: +1 408 555-1234
|
||||
l: San Jose
|
||||
ou: Product Development
|
||||
postalAddress: Product Development$San Jose
|
||||
telephoneNumber: +1 408 555-5678
|
||||
title: Senior DevOps Engineer
|
||||
userPassword: Password1
|
||||
uid: ChenB
|
||||
givenName: Benjamin
|
||||
mail: ChenB@9f8a7b6c5d4e3f2a1b0c9d8e7f6a5b4c3.bitwarden.com
|
||||
carLicense: 2K8N9L
|
||||
departmentNumber: 1001
|
||||
employeeType: Employee
|
||||
homePhone: +1 408 555-9876
|
||||
initials: B. C.
|
||||
mobile: +1 408 555-4321
|
||||
pager: +1 408 555-7890
|
||||
roomNumber: 7125
|
||||
manager: cn=Roland Dyke,ou=Human Resources,dc=bitwarden, dc=com
|
||||
secretary: cn=Keven Gilleland,ou=Administrative,dc=bitwarden, dc=com
|
||||
|
||||
dn: cn=Karen Smith,ou=Product Development,dc=bitwarden, dc=com
|
||||
changetype: add
|
||||
objectClass: top
|
||||
objectClass: person
|
||||
objectClass: organizationalPerson
|
||||
objectClass: inetOrgPerson
|
||||
cn: Karen Smith
|
||||
sn: Smith
|
||||
description: This is Karen Smith's description
|
||||
facsimileTelephoneNumber: +1 415 555-2345
|
||||
l: San Francisco
|
||||
ou: Product Development
|
||||
postalAddress: Product Development$San Francisco
|
||||
telephoneNumber: +1 415 555-6789
|
||||
title: Senior Systems Administrator
|
||||
userPassword: Password1
|
||||
uid: SmithK
|
||||
givenName: Karen
|
||||
mail: SmithK@3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9.bitwarden.com
|
||||
carLicense: 5M3P7Q
|
||||
departmentNumber: 1002
|
||||
employeeType: Employee
|
||||
homePhone: +1 415 555-0987
|
||||
initials: K. S.
|
||||
mobile: +1 415 555-5432
|
||||
pager: +1 415 555-8901
|
||||
roomNumber: 7126
|
||||
manager: cn=Roland Dyke,ou=Human Resources,dc=bitwarden, dc=com
|
||||
secretary: cn=Keven Gilleland,ou=Administrative,dc=bitwarden, dc=com
|
||||
|
||||
dn: cn=Robert Johnson,ou=Product Development,dc=bitwarden, dc=com
|
||||
changetype: add
|
||||
objectClass: top
|
||||
objectClass: person
|
||||
objectClass: organizationalPerson
|
||||
objectClass: inetOrgPerson
|
||||
cn: Robert Johnson
|
||||
sn: Johnson
|
||||
description: This is Robert Johnson's description
|
||||
facsimileTelephoneNumber: +1 510 555-3456
|
||||
l: Oakland
|
||||
ou: Product Development
|
||||
postalAddress: Product Development$Oakland
|
||||
telephoneNumber: +1 510 555-7890
|
||||
title: Cloud Infrastructure Engineer
|
||||
userPassword: Password1
|
||||
uid: JohnsonR
|
||||
givenName: Robert
|
||||
mail: JohnsonR@7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3.bitwarden.com
|
||||
carLicense: 8X2Y4Z
|
||||
departmentNumber: 1003
|
||||
employeeType: Employee
|
||||
homePhone: +1 510 555-1098
|
||||
initials: R. J.
|
||||
mobile: +1 510 555-6543
|
||||
pager: +1 510 555-9012
|
||||
roomNumber: 7127
|
||||
manager: cn=Roland Dyke,ou=Human Resources,dc=bitwarden, dc=com
|
||||
secretary: cn=Keven Gilleland,ou=Administrative,dc=bitwarden, dc=com
|
||||
|
||||
dn: cn=Thomas Williams,ou=Management,dc=bitwarden, dc=com
|
||||
changetype: add
|
||||
objectClass: top
|
||||
objectClass: person
|
||||
objectClass: organizationalPerson
|
||||
objectClass: inetOrgPerson
|
||||
cn: Thomas Williams
|
||||
sn: Williams
|
||||
description: This is Thomas Williams's description
|
||||
facsimileTelephoneNumber: +1 650 555-4567
|
||||
l: Palo Alto
|
||||
ou: Management
|
||||
postalAddress: Management$Palo Alto
|
||||
telephoneNumber: +1 650 555-8901
|
||||
title: Chief Security Officer
|
||||
userPassword: Password1
|
||||
uid: WilliamsT
|
||||
givenName: Thomas
|
||||
mail: WilliamsT@1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7.bitwarden.com
|
||||
carLicense: 6H9J2K
|
||||
departmentNumber: 1004
|
||||
employeeType: Employee
|
||||
homePhone: +1 650 555-2109
|
||||
initials: T. W.
|
||||
mobile: +1 650 555-7654
|
||||
pager: +1 650 555-0123
|
||||
roomNumber: 7128
|
||||
manager: cn=Roland Dyke,ou=Human Resources,dc=bitwarden, dc=com
|
||||
secretary: cn=Keven Gilleland,ou=Administrative,dc=bitwarden, dc=com
|
||||
|
||||
dn: cn=Michelle Brown,ou=Management,dc=bitwarden, dc=com
|
||||
changetype: add
|
||||
objectClass: top
|
||||
objectClass: person
|
||||
objectClass: organizationalPerson
|
||||
objectClass: inetOrgPerson
|
||||
cn: Michelle Brown
|
||||
sn: Brown
|
||||
description: This is Michelle Brown's description
|
||||
facsimileTelephoneNumber: +1 408 555-5678
|
||||
l: Santa Clara
|
||||
ou: Management
|
||||
postalAddress: Management$Santa Clara
|
||||
telephoneNumber: +1 408 555-9012
|
||||
title: Security Analyst
|
||||
userPassword: Password1
|
||||
uid: BrownM
|
||||
givenName: Michelle
|
||||
mail: BrownM@5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1.bitwarden.com
|
||||
carLicense: 4T6U8V
|
||||
departmentNumber: 1005
|
||||
employeeType: Employee
|
||||
homePhone: +1 408 555-3210
|
||||
initials: M. B.
|
||||
mobile: +1 408 555-8765
|
||||
pager: +1 408 555-1234
|
||||
roomNumber: 7129
|
||||
manager: cn=Roland Dyke,ou=Human Resources,dc=bitwarden, dc=com
|
||||
secretary: cn=Keven Gilleland,ou=Administrative,dc=bitwarden, dc=com
|
||||
|
||||
@@ -144,41 +144,6 @@ const data: Jsonify<UserEntry>[] = [
|
||||
externalId: "cn=Loella Mak,ou=Payroll,dc=bitwarden,dc=com",
|
||||
email: "makl@6ab3e25ca49d4d64aaf44844288a8ef7.bitwarden.com",
|
||||
},
|
||||
{
|
||||
disabled: false,
|
||||
deleted: false,
|
||||
referenceId: "cn=Benjamin Chen,ou=Product Development,dc=bitwarden,dc=com",
|
||||
externalId: "cn=Benjamin Chen,ou=Product Development,dc=bitwarden,dc=com",
|
||||
email: "chenb@9f8a7b6c5d4e3f2a1b0c9d8e7f6a5b4c3.bitwarden.com",
|
||||
},
|
||||
{
|
||||
disabled: false,
|
||||
deleted: false,
|
||||
referenceId: "cn=Karen Smith,ou=Product Development,dc=bitwarden,dc=com",
|
||||
externalId: "cn=Karen Smith,ou=Product Development,dc=bitwarden,dc=com",
|
||||
email: "smithk@3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9.bitwarden.com",
|
||||
},
|
||||
{
|
||||
disabled: false,
|
||||
deleted: false,
|
||||
referenceId: "cn=Robert Johnson,ou=Product Development,dc=bitwarden,dc=com",
|
||||
externalId: "cn=Robert Johnson,ou=Product Development,dc=bitwarden,dc=com",
|
||||
email: "johnsonr@7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3.bitwarden.com",
|
||||
},
|
||||
{
|
||||
disabled: false,
|
||||
deleted: false,
|
||||
referenceId: "cn=Thomas Williams,ou=Management,dc=bitwarden,dc=com",
|
||||
externalId: "cn=Thomas Williams,ou=Management,dc=bitwarden,dc=com",
|
||||
email: "williamst@1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7.bitwarden.com",
|
||||
},
|
||||
{
|
||||
disabled: false,
|
||||
deleted: false,
|
||||
referenceId: "cn=Michelle Brown,ou=Management,dc=bitwarden,dc=com",
|
||||
externalId: "cn=Michelle Brown,ou=Management,dc=bitwarden,dc=com",
|
||||
email: "brownm@5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1.bitwarden.com",
|
||||
},
|
||||
];
|
||||
|
||||
export const userFixtures = data.map((v) => UserEntry.fromJSON(v));
|
||||
|
||||
@@ -152,88 +152,4 @@ describe("ldapDirectoryService", () => {
|
||||
expect(result).toEqual([[redTeam], undefined]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("new groups and users", () => {
|
||||
it("fetches DevOps Team and Security Team groups", async () => {
|
||||
stateService.getDirectory
|
||||
.calledWith(DirectoryType.Ldap)
|
||||
.mockResolvedValue(getLdapConfiguration());
|
||||
stateService.getSync.mockResolvedValue(
|
||||
getSyncConfiguration({
|
||||
groups: true,
|
||||
groupFilter: "(|(cn=DevOps Team)(cn=Security Team))",
|
||||
}),
|
||||
);
|
||||
|
||||
const devOpsTeam = groupFixtures.find(
|
||||
(g) => g.referenceId === "cn=DevOps Team,dc=bitwarden,dc=com",
|
||||
);
|
||||
const securityTeam = groupFixtures.find(
|
||||
(g) => g.referenceId === "cn=Security Team,dc=bitwarden,dc=com",
|
||||
);
|
||||
|
||||
const result = await directoryService.getEntries(true, true);
|
||||
expect(result[0]).toEqual(expect.arrayContaining([devOpsTeam, securityTeam]));
|
||||
expect(result[0].length).toEqual(2);
|
||||
});
|
||||
|
||||
it("fetches new users with correct group memberships", async () => {
|
||||
stateService.getDirectory
|
||||
.calledWith(DirectoryType.Ldap)
|
||||
.mockResolvedValue(getLdapConfiguration());
|
||||
stateService.getSync.mockResolvedValue(
|
||||
getSyncConfiguration({
|
||||
users: true,
|
||||
groups: true,
|
||||
userFilter: "(|(uid=ChenB)(uid=SmithK)(uid=JohnsonR)(uid=WilliamsT)(uid=BrownM))",
|
||||
}),
|
||||
);
|
||||
|
||||
const newUsers = userFixtures.filter(
|
||||
(u) =>
|
||||
u.referenceId === "cn=Benjamin Chen,ou=Product Development,dc=bitwarden,dc=com" ||
|
||||
u.referenceId === "cn=Karen Smith,ou=Product Development,dc=bitwarden,dc=com" ||
|
||||
u.referenceId === "cn=Robert Johnson,ou=Product Development,dc=bitwarden,dc=com" ||
|
||||
u.referenceId === "cn=Thomas Williams,ou=Management,dc=bitwarden,dc=com" ||
|
||||
u.referenceId === "cn=Michelle Brown,ou=Management,dc=bitwarden,dc=com",
|
||||
);
|
||||
|
||||
const devOpsTeam = groupFixtures.find(
|
||||
(g) => g.referenceId === "cn=DevOps Team,dc=bitwarden,dc=com",
|
||||
);
|
||||
const securityTeam = groupFixtures.find(
|
||||
(g) => g.referenceId === "cn=Security Team,dc=bitwarden,dc=com",
|
||||
);
|
||||
|
||||
const result = await directoryService.getEntries(true, true);
|
||||
|
||||
// Verify users are fetched
|
||||
expect(result[1]).toEqual(expect.arrayContaining(newUsers));
|
||||
expect(result[1].length).toEqual(newUsers.length);
|
||||
|
||||
// Verify groups are fetched with correct membership
|
||||
expect(result[0]).toEqual(expect.arrayContaining([devOpsTeam, securityTeam]));
|
||||
|
||||
// Verify DevOps Team has 3 members
|
||||
const fetchedDevOpsTeam = result[0].find((g) => g.name === "DevOps Team");
|
||||
expect(fetchedDevOpsTeam.userMemberExternalIds.size).toEqual(3);
|
||||
expect(Array.from(fetchedDevOpsTeam.userMemberExternalIds)).toEqual(
|
||||
expect.arrayContaining([
|
||||
"cn=Benjamin Chen,ou=Product Development,dc=bitwarden,dc=com",
|
||||
"cn=Karen Smith,ou=Product Development,dc=bitwarden,dc=com",
|
||||
"cn=Robert Johnson,ou=Product Development,dc=bitwarden,dc=com",
|
||||
]),
|
||||
);
|
||||
|
||||
// Verify Security Team has 2 members
|
||||
const fetchedSecurityTeam = result[0].find((g) => g.name === "Security Team");
|
||||
expect(fetchedSecurityTeam.userMemberExternalIds.size).toEqual(2);
|
||||
expect(Array.from(fetchedSecurityTeam.userMemberExternalIds)).toEqual(
|
||||
expect.arrayContaining([
|
||||
"cn=Thomas Williams,ou=Management,dc=bitwarden,dc=com",
|
||||
"cn=Michelle Brown,ou=Management,dc=bitwarden,dc=com",
|
||||
]),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -200,7 +200,7 @@ export class LdapDirectoryService implements IDirectoryService {
|
||||
const externalId = this.getExternalId(se, dn);
|
||||
userDnMap.set(dn, externalId);
|
||||
if (uid != null) {
|
||||
userUidMap.set(uid, externalId);
|
||||
userUidMap.set(uid.toLowerCase(), externalId);
|
||||
}
|
||||
return se;
|
||||
});
|
||||
@@ -215,6 +215,19 @@ export class LdapDirectoryService implements IDirectoryService {
|
||||
return entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a GroupEntry from an LDAP search entry, processing group members and determining member types.
|
||||
*
|
||||
* This method creates a group object with its basic properties (referenceId, externalId, name) and
|
||||
* processes its members to categorize them as either user members (DN or UID format) or nested groups.
|
||||
* Members are identified by their format: DN-like strings containing "=" and "," are checked against
|
||||
* user maps to determine if they're user DNs or group DNs, while other strings are treated as UIDs.
|
||||
*
|
||||
* @param searchEntry - The LDAP search entry containing group data
|
||||
* @param userDnMap - Map of user distinguished names to their external IDs
|
||||
* @param userUidMap - Map of user UIDs to their external IDs
|
||||
* @returns A populated GroupEntry object, or null if the group lacks required properties
|
||||
*/
|
||||
private buildGroup(
|
||||
searchEntry: any,
|
||||
userDnMap: Map<string, string>,
|
||||
@@ -239,6 +252,7 @@ export class LdapDirectoryService implements IDirectoryService {
|
||||
|
||||
const members = this.getAttrVals<string>(searchEntry, this.syncConfig.memberAttribute);
|
||||
if (members != null) {
|
||||
// Parses a group member attribute and identifies it as a member DN, member Uid, or a group Dn
|
||||
const getMemberAttributeType = (member: string): "memberDn" | "memberUid" | "groupDn" => {
|
||||
const isDnLike = member.includes("=") && member.includes(",");
|
||||
if (isDnLike) {
|
||||
@@ -257,7 +271,7 @@ export class LdapDirectoryService implements IDirectoryService {
|
||||
break;
|
||||
}
|
||||
case "memberUid": {
|
||||
const externalId = userUidMap.get(member);
|
||||
const externalId = userUidMap.get(member.toLowerCase());
|
||||
if (externalId != null) {
|
||||
group.userMemberExternalIds.add(externalId);
|
||||
}
|
||||
|
||||
@@ -164,13 +164,8 @@ export class SyncService {
|
||||
}
|
||||
} else {
|
||||
if (!u.deleted) {
|
||||
// Check that active UserEntry does not conflict with a deleted UserEntry
|
||||
if (processedDeletedUsers.has(u.email)) {
|
||||
duplicateEmails.push(u.email);
|
||||
} else {
|
||||
processedActiveUsers.set(u.email, JSON.stringify(u));
|
||||
uniqueUsers.push(u);
|
||||
}
|
||||
processedActiveUsers.set(u.email, JSON.stringify(u));
|
||||
uniqueUsers.push(u);
|
||||
} else {
|
||||
// UserEntrys with duplicate email will not throw an error if they are all deleted. They will be synced.
|
||||
processedDeletedUsers.set(u.email, JSON.stringify(u));
|
||||
|
||||
Reference in New Issue
Block a user