From 6bb14da830346e29a534b4d6348facb2fd0f37da Mon Sep 17 00:00:00 2001 From: Daniel Kleveros Date: Tue, 12 Dec 2023 17:23:37 -0800 Subject: [PATCH 1/4] adding discrepancies logic for concord org owners. --- .../cfg/LdapGroupSyncConfiguration.java | 8 +++ .../ldap/UserLdapGroupSynchronizer.java | 61 ++++++++++++++++++- 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/server/impl/src/main/java/com/walmartlabs/concord/server/cfg/LdapGroupSyncConfiguration.java b/server/impl/src/main/java/com/walmartlabs/concord/server/cfg/LdapGroupSyncConfiguration.java index 44aeb9c3d1..8ce4dbfcc5 100644 --- a/server/impl/src/main/java/com/walmartlabs/concord/server/cfg/LdapGroupSyncConfiguration.java +++ b/server/impl/src/main/java/com/walmartlabs/concord/server/cfg/LdapGroupSyncConfiguration.java @@ -52,6 +52,10 @@ public class LdapGroupSyncConfiguration implements Serializable { @Config("ldapGroupSync.disabledAge") private Duration disabledAge; + @Inject + @Config("ldapGroupSync.concordOrgOwnersGroup") + private String concordOrgOwnersGroup; + public Duration getInterval() { return interval; } @@ -71,4 +75,8 @@ public Duration getMinAgeSync() { public Duration getDisabledAge() { return disabledAge; } + + public String getConcordOrgOwnersGroup() { + return concordOrgOwnersGroup; + } } diff --git a/server/impl/src/main/java/com/walmartlabs/concord/server/security/ldap/UserLdapGroupSynchronizer.java b/server/impl/src/main/java/com/walmartlabs/concord/server/security/ldap/UserLdapGroupSynchronizer.java index f4a23c3172..14c304c9c1 100644 --- a/server/impl/src/main/java/com/walmartlabs/concord/server/security/ldap/UserLdapGroupSynchronizer.java +++ b/server/impl/src/main/java/com/walmartlabs/concord/server/security/ldap/UserLdapGroupSynchronizer.java @@ -26,6 +26,7 @@ import com.walmartlabs.concord.server.audit.ActionSource; import com.walmartlabs.concord.server.audit.AuditLog; import com.walmartlabs.concord.server.cfg.LdapGroupSyncConfiguration; +import com.walmartlabs.concord.server.org.team.TeamRole; import com.walmartlabs.concord.server.sdk.ScheduledTask; import com.walmartlabs.concord.server.user.UserManager; import com.walmartlabs.concord.server.user.UserType; @@ -38,11 +39,15 @@ import javax.inject.Named; import java.time.OffsetDateTime; import java.util.Collections; +import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; + import static com.walmartlabs.concord.server.jooq.Tables.USERS; +import static com.walmartlabs.concord.server.jooq.Tables.USER_TEAMS; import static org.jooq.impl.DSL.*; /** @@ -87,18 +92,25 @@ public void performTask() { Field cutoff = PgUtils.nowMinus(cfg.getMinAgeSync()); Field disabledAge = cfg.getDisabledAge() != null ? PgUtils.nowMinus(cfg.getDisabledAge()) : null; + List concordOrgOwners = new ArrayList<>(); + long usersCount = 0; List users; do { users = dao.list(cfg.getFetchLimit(), cutoff, disabledAge); - users.forEach(this::processUser); + users.forEach(user -> { + processUser(user, concordOrgOwners); + }); usersCount += users.size(); } while (users.size() >= cfg.getFetchLimit()); + //TODO: Check concordOrgOwners against all owners in DB. Send discrepancy report on slack or email + checkOrgOwnerDiscrepancies(users, dao.listOrgOwners()); + log.info("performTask -> done, {} user(s) synchronized", usersCount); } - private void processUser(UserItem u) { + private void processUser(UserItem u, List concordOrgOwners) { try { Set groups = ldapManager.getGroups(u.username, u.domain); if (groups == null) { @@ -111,6 +123,9 @@ private void processUser(UserItem u) { } else { enableUser(u.userId); ldapGroupsDao.update(u.userId, groups); + if(groups.contains(cfg.getConcordOrgOwnersGroup())) { + concordOrgOwners.add(u); + } } } catch (Exception e) { log.error("processUser ['{}'] -> error", u.username, e); @@ -149,9 +164,41 @@ public List list(int limit, Field cutoff, Field new UserItem(r.value1(), r.value2(), r.value3(), r.value4()))); } + + public List listOrgOwners() { + // Expired users already handled at this stage + return txResult(tx -> tx.select(USERS.USER_ID, USERS.USERNAME, USERS.DOMAIN) + .from(USER_TEAMS.join(USERS).on(USER_TEAMS.USER_ID.eq(USERS.USER_ID))) + .where(USER_TEAMS.TEAM_ROLE.eq(TeamRole.OWNER.toString())) + .fetch(r -> new UserItem(r.value1(), r.value2(), r.value3(), false))); + } + + /* public List listOrgOwners(int limit, Field cutoff, Field disabledAge) { + Field expiredFiled = disabledAge == null ? inline(false) : field(nvl(USERS.DISABLED_DATE, currentOffsetDateTime()).lessThan(disabledAge)); + return txResult(tx -> tx.select(USERS.USER_ID, USERS.USERNAME, USERS.DOMAIN, expiredFiled) + .from(USER_LDAP_GROUPS.join(USERS).on(USER_LDAP_GROUPS.USER_ID.eq(USERS.USER_ID))) + .where(USER_LDAP_GROUPS.LDAP_GROUP.eq("concord-org-admins")) + .limit(limit) + .fetch(r -> new UserItem(r.value1(), r.value2(), r.value3(), r.value4()))); + } */ } - private static class UserItem { + private void checkOrgOwnerDiscrepancies(List ldapGroupUsers, List ownerRoleUsers) { + List diffUsersOnlyInLdapGroup = ldapGroupUsers.stream() + .filter(item -> !ownerRoleUsers.contains(item)) + .toList(); + + List diffUsersWithOwnerRoleAndNotInLdap = ownerRoleUsers.stream() + .filter(item -> !ldapGroupUsers.contains(item)) + .toList(); + + + log.info("checkOrgOwnerDiscrepancies -> done, {} user(s) only in ldapGroup not registered as owners", diffUsersOnlyInLdapGroup.stream().map(Object::toString).collect(Collectors.joining(", "))); + log.info("checkOrgOwnerDiscrepancies -> done, {} user(s) only registered as owners not in ldapGroup", ldapGroupUsers.stream().map(Object::toString).collect(Collectors.joining(", "))); + + } + + private static class UserItem implements Comparable { private final UUID userId; private final String username; @@ -164,5 +211,13 @@ private UserItem(UUID userId, String username, String domain, boolean expired) { this.domain = domain; this.expired = expired; } + + @Override + public int compareTo(UserLdapGroupSynchronizer.UserItem o) { + if(userId==o.userId) + return 0; + else + return userId.compareTo(o.userId); + } } } From 0135afb1f75b95a9899d39be8b3829a490d3aaf5 Mon Sep 17 00:00:00 2001 From: Daniel Kleveros Date: Wed, 13 Dec 2023 17:16:01 -0800 Subject: [PATCH 2/4] cleanup --- .../security/ldap/UserLdapGroupSynchronizer.java | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/server/impl/src/main/java/com/walmartlabs/concord/server/security/ldap/UserLdapGroupSynchronizer.java b/server/impl/src/main/java/com/walmartlabs/concord/server/security/ldap/UserLdapGroupSynchronizer.java index 14c304c9c1..da683af87b 100644 --- a/server/impl/src/main/java/com/walmartlabs/concord/server/security/ldap/UserLdapGroupSynchronizer.java +++ b/server/impl/src/main/java/com/walmartlabs/concord/server/security/ldap/UserLdapGroupSynchronizer.java @@ -172,15 +172,6 @@ public List listOrgOwners() { .where(USER_TEAMS.TEAM_ROLE.eq(TeamRole.OWNER.toString())) .fetch(r -> new UserItem(r.value1(), r.value2(), r.value3(), false))); } - - /* public List listOrgOwners(int limit, Field cutoff, Field disabledAge) { - Field expiredFiled = disabledAge == null ? inline(false) : field(nvl(USERS.DISABLED_DATE, currentOffsetDateTime()).lessThan(disabledAge)); - return txResult(tx -> tx.select(USERS.USER_ID, USERS.USERNAME, USERS.DOMAIN, expiredFiled) - .from(USER_LDAP_GROUPS.join(USERS).on(USER_LDAP_GROUPS.USER_ID.eq(USERS.USER_ID))) - .where(USER_LDAP_GROUPS.LDAP_GROUP.eq("concord-org-admins")) - .limit(limit) - .fetch(r -> new UserItem(r.value1(), r.value2(), r.value3(), r.value4()))); - } */ } private void checkOrgOwnerDiscrepancies(List ldapGroupUsers, List ownerRoleUsers) { @@ -213,7 +204,7 @@ private UserItem(UUID userId, String username, String domain, boolean expired) { } @Override - public int compareTo(UserLdapGroupSynchronizer.UserItem o) { + public int compareTo(UserItem o) { if(userId==o.userId) return 0; else From 2ea7f091690a97c9c140c661e410a1210ef2f182 Mon Sep 17 00:00:00 2001 From: Daniel Kleveros Date: Wed, 13 Dec 2023 19:48:42 -0800 Subject: [PATCH 3/4] adding test --- .../cfg/LdapGroupSyncConfiguration.java | 1 + .../ldap/UserLdapGroupSynchronizer.java | 37 ++++++-- .../ldap/UserLdapGroupSynchronizerTest.java | 86 +++++++++++++++++++ 3 files changed, 115 insertions(+), 9 deletions(-) create mode 100644 server/impl/src/test/java/com/walmartlabs/concord/server/security/ldap/UserLdapGroupSynchronizerTest.java diff --git a/server/impl/src/main/java/com/walmartlabs/concord/server/cfg/LdapGroupSyncConfiguration.java b/server/impl/src/main/java/com/walmartlabs/concord/server/cfg/LdapGroupSyncConfiguration.java index 8ce4dbfcc5..47cf324399 100644 --- a/server/impl/src/main/java/com/walmartlabs/concord/server/cfg/LdapGroupSyncConfiguration.java +++ b/server/impl/src/main/java/com/walmartlabs/concord/server/cfg/LdapGroupSyncConfiguration.java @@ -53,6 +53,7 @@ public class LdapGroupSyncConfiguration implements Serializable { private Duration disabledAge; @Inject + @Nullable @Config("ldapGroupSync.concordOrgOwnersGroup") private String concordOrgOwnersGroup; diff --git a/server/impl/src/main/java/com/walmartlabs/concord/server/security/ldap/UserLdapGroupSynchronizer.java b/server/impl/src/main/java/com/walmartlabs/concord/server/security/ldap/UserLdapGroupSynchronizer.java index da683af87b..e069c28815 100644 --- a/server/impl/src/main/java/com/walmartlabs/concord/server/security/ldap/UserLdapGroupSynchronizer.java +++ b/server/impl/src/main/java/com/walmartlabs/concord/server/security/ldap/UserLdapGroupSynchronizer.java @@ -34,6 +34,7 @@ import org.jooq.Field; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import scala.Tuple2; import javax.inject.Inject; import javax.inject.Named; @@ -104,8 +105,9 @@ public void performTask() { usersCount += users.size(); } while (users.size() >= cfg.getFetchLimit()); - //TODO: Check concordOrgOwners against all owners in DB. Send discrepancy report on slack or email - checkOrgOwnerDiscrepancies(users, dao.listOrgOwners()); + if(cfg.getConcordOrgOwnersGroup() != null) { + checkOrgOwnerDiscrepancies(users, dao.listOrgOwners()); + } log.info("performTask -> done, {} user(s) synchronized", usersCount); } @@ -123,7 +125,7 @@ private void processUser(UserItem u, List concordOrgOwners) { } else { enableUser(u.userId); ldapGroupsDao.update(u.userId, groups); - if(groups.contains(cfg.getConcordOrgOwnersGroup())) { + if(cfg.getConcordOrgOwnersGroup() != null && groups.contains(cfg.getConcordOrgOwnersGroup())) { concordOrgOwners.add(u); } } @@ -148,7 +150,7 @@ private void deleteUser(UUID userId) { } @Named - private static final class Dao extends AbstractDao { + static class Dao extends AbstractDao { @Inject public Dao(@MainDB Configuration cfg) { @@ -174,7 +176,13 @@ public List listOrgOwners() { } } - private void checkOrgOwnerDiscrepancies(List ldapGroupUsers, List ownerRoleUsers) { + /*** + * Check concordOrgOwners against all owners in DB. Send discrepancy report on slack or email + * + * @param ldapGroupUsers + * @param ownerRoleUsers + */ + Tuple2 checkOrgOwnerDiscrepancies(List ldapGroupUsers, List ownerRoleUsers) { List diffUsersOnlyInLdapGroup = ldapGroupUsers.stream() .filter(item -> !ownerRoleUsers.contains(item)) .toList(); @@ -185,18 +193,19 @@ private void checkOrgOwnerDiscrepancies(List ldapGroupUsers, List done, {} user(s) only in ldapGroup not registered as owners", diffUsersOnlyInLdapGroup.stream().map(Object::toString).collect(Collectors.joining(", "))); - log.info("checkOrgOwnerDiscrepancies -> done, {} user(s) only registered as owners not in ldapGroup", ldapGroupUsers.stream().map(Object::toString).collect(Collectors.joining(", "))); + log.info("checkOrgOwnerDiscrepancies -> done, {} user(s) only registered as owners not in ldapGroup", diffUsersWithOwnerRoleAndNotInLdap.stream().map(Object::toString).collect(Collectors.joining(", "))); + return new Tuple2<>(diffUsersOnlyInLdapGroup, diffUsersWithOwnerRoleAndNotInLdap); } - private static class UserItem implements Comparable { + static class UserItem implements Comparable { private final UUID userId; private final String username; private final String domain; private final boolean expired; - private UserItem(UUID userId, String username, String domain, boolean expired) { + UserItem(UUID userId, String username, String domain, boolean expired) { this.userId = userId; this.username = username; this.domain = domain; @@ -205,10 +214,20 @@ private UserItem(UUID userId, String username, String domain, boolean expired) { @Override public int compareTo(UserItem o) { - if(userId==o.userId) + if (userId == o.userId) return 0; else return userId.compareTo(o.userId); } + + @Override + public String toString() { + return "UserItem{" + + "userId=" + userId + + ", username='" + username + '\'' + + ", domain='" + domain + '\'' + + ", expired=" + expired + + '}'; + } } } diff --git a/server/impl/src/test/java/com/walmartlabs/concord/server/security/ldap/UserLdapGroupSynchronizerTest.java b/server/impl/src/test/java/com/walmartlabs/concord/server/security/ldap/UserLdapGroupSynchronizerTest.java new file mode 100644 index 0000000000..fc850cb544 --- /dev/null +++ b/server/impl/src/test/java/com/walmartlabs/concord/server/security/ldap/UserLdapGroupSynchronizerTest.java @@ -0,0 +1,86 @@ +package com.walmartlabs.concord.server.security.ldap; + +import com.walmartlabs.concord.server.cfg.LdapGroupSyncConfiguration; +import com.walmartlabs.concord.server.user.UserManager; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import scala.Tuple2; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; + +class UserLdapGroupSynchronizerTest { + + private UserLdapGroupSynchronizer userLdapGroupSynchronizer; + + @BeforeEach + public void init() { + userLdapGroupSynchronizer = new UserLdapGroupSynchronizer(mock(UserLdapGroupSynchronizer.Dao.class), + mock(LdapGroupSyncConfiguration.class), + mock(LdapManager.class), + mock(LdapGroupDao.class), + mock(UserManager.class)); + } + + @Test + void checkOrgOwnerDiscrepanciesDiffUsersOnlyInLdap() { + UserLdapGroupSynchronizer.UserItem user1 = new UserLdapGroupSynchronizer.UserItem(UUID.randomUUID(), "admin", "domain", false); + UserLdapGroupSynchronizer.UserItem user2 = new UserLdapGroupSynchronizer.UserItem(UUID.randomUUID(), "testUser", null, false); + + List ldapGroupUsers = new ArrayList<>(); + ldapGroupUsers.add(user1); + ldapGroupUsers.add(user2); + + List ownerRoleUsers = new ArrayList<>(); + ownerRoleUsers.add(user1); + + List usersOnlyInLdapGroup = new ArrayList<>(); + usersOnlyInLdapGroup.add(user2); + + Tuple2 values = userLdapGroupSynchronizer.checkOrgOwnerDiscrepancies(ldapGroupUsers, ownerRoleUsers); + assertTrue(values._1().equals(usersOnlyInLdapGroup)); + assertTrue(values._2().isEmpty()); + } + + @Test + void checkOrgOwnerDiscrepanciesDiffOwnersNotInLdap() { + UserLdapGroupSynchronizer.UserItem user1 = new UserLdapGroupSynchronizer.UserItem(UUID.randomUUID(), "admin", "domain", false); + UserLdapGroupSynchronizer.UserItem user2 = new UserLdapGroupSynchronizer.UserItem(UUID.randomUUID(), "testUser", null, false); + + List ldapGroupUsers = new ArrayList<>(); + ldapGroupUsers.add(user1); + + List ownerRoleUsers = new ArrayList<>(); + ownerRoleUsers.add(user1); + ownerRoleUsers.add(user2); + + List ownersNotInLdapGroup = new ArrayList<>(); + ownersNotInLdapGroup.add(user2); + + Tuple2 values = userLdapGroupSynchronizer.checkOrgOwnerDiscrepancies(ldapGroupUsers, ownerRoleUsers); + assertTrue(values._1().isEmpty()); + assertTrue(values._2().equals(ownersNotInLdapGroup)); + } + + @Test + void checkOrgOwnerDiscrepanciesNoDiff() { + UserLdapGroupSynchronizer.UserItem user1 = new UserLdapGroupSynchronizer.UserItem(UUID.randomUUID(), "admin", "domain", false); + UserLdapGroupSynchronizer.UserItem user2 = new UserLdapGroupSynchronizer.UserItem(UUID.randomUUID(), "testUser", null, false); + + List ldapGroupUsers = new ArrayList<>(); + ldapGroupUsers.add(user1); + ldapGroupUsers.add(user2); + + List ownerRoleUsers = new ArrayList<>(); + ownerRoleUsers.add(user1); + ownerRoleUsers.add(user2); + + Tuple2 values = userLdapGroupSynchronizer.checkOrgOwnerDiscrepancies(ldapGroupUsers, ownerRoleUsers); + assertTrue(values._1().isEmpty()); + assertTrue(values._2().isEmpty()); + } +} \ No newline at end of file From bfd64e62926b0a2990996f25ed7933ad2aff51f3 Mon Sep 17 00:00:00 2001 From: Daniel Kleveros Date: Thu, 14 Dec 2023 14:25:42 -0800 Subject: [PATCH 4/4] Refactoring --- .../ldap/UserLdapGroupSynchronizer.java | 10 ++----- .../ldap/UserLdapGroupSynchronizerTest.java | 29 ++----------------- 2 files changed, 4 insertions(+), 35 deletions(-) diff --git a/server/impl/src/main/java/com/walmartlabs/concord/server/security/ldap/UserLdapGroupSynchronizer.java b/server/impl/src/main/java/com/walmartlabs/concord/server/security/ldap/UserLdapGroupSynchronizer.java index e069c28815..e7e8cb3a8d 100644 --- a/server/impl/src/main/java/com/walmartlabs/concord/server/security/ldap/UserLdapGroupSynchronizer.java +++ b/server/impl/src/main/java/com/walmartlabs/concord/server/security/ldap/UserLdapGroupSynchronizer.java @@ -182,20 +182,14 @@ public List listOrgOwners() { * @param ldapGroupUsers * @param ownerRoleUsers */ - Tuple2 checkOrgOwnerDiscrepancies(List ldapGroupUsers, List ownerRoleUsers) { - List diffUsersOnlyInLdapGroup = ldapGroupUsers.stream() - .filter(item -> !ownerRoleUsers.contains(item)) - .toList(); - + List checkOrgOwnerDiscrepancies(List ldapGroupUsers, List ownerRoleUsers) { List diffUsersWithOwnerRoleAndNotInLdap = ownerRoleUsers.stream() .filter(item -> !ldapGroupUsers.contains(item)) .toList(); - - log.info("checkOrgOwnerDiscrepancies -> done, {} user(s) only in ldapGroup not registered as owners", diffUsersOnlyInLdapGroup.stream().map(Object::toString).collect(Collectors.joining(", "))); log.info("checkOrgOwnerDiscrepancies -> done, {} user(s) only registered as owners not in ldapGroup", diffUsersWithOwnerRoleAndNotInLdap.stream().map(Object::toString).collect(Collectors.joining(", "))); - return new Tuple2<>(diffUsersOnlyInLdapGroup, diffUsersWithOwnerRoleAndNotInLdap); + return diffUsersWithOwnerRoleAndNotInLdap; } static class UserItem implements Comparable { diff --git a/server/impl/src/test/java/com/walmartlabs/concord/server/security/ldap/UserLdapGroupSynchronizerTest.java b/server/impl/src/test/java/com/walmartlabs/concord/server/security/ldap/UserLdapGroupSynchronizerTest.java index fc850cb544..16f051e745 100644 --- a/server/impl/src/test/java/com/walmartlabs/concord/server/security/ldap/UserLdapGroupSynchronizerTest.java +++ b/server/impl/src/test/java/com/walmartlabs/concord/server/security/ldap/UserLdapGroupSynchronizerTest.java @@ -4,7 +4,6 @@ import com.walmartlabs.concord.server.user.UserManager; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import scala.Tuple2; import java.util.ArrayList; import java.util.List; @@ -26,26 +25,6 @@ public void init() { mock(UserManager.class)); } - @Test - void checkOrgOwnerDiscrepanciesDiffUsersOnlyInLdap() { - UserLdapGroupSynchronizer.UserItem user1 = new UserLdapGroupSynchronizer.UserItem(UUID.randomUUID(), "admin", "domain", false); - UserLdapGroupSynchronizer.UserItem user2 = new UserLdapGroupSynchronizer.UserItem(UUID.randomUUID(), "testUser", null, false); - - List ldapGroupUsers = new ArrayList<>(); - ldapGroupUsers.add(user1); - ldapGroupUsers.add(user2); - - List ownerRoleUsers = new ArrayList<>(); - ownerRoleUsers.add(user1); - - List usersOnlyInLdapGroup = new ArrayList<>(); - usersOnlyInLdapGroup.add(user2); - - Tuple2 values = userLdapGroupSynchronizer.checkOrgOwnerDiscrepancies(ldapGroupUsers, ownerRoleUsers); - assertTrue(values._1().equals(usersOnlyInLdapGroup)); - assertTrue(values._2().isEmpty()); - } - @Test void checkOrgOwnerDiscrepanciesDiffOwnersNotInLdap() { UserLdapGroupSynchronizer.UserItem user1 = new UserLdapGroupSynchronizer.UserItem(UUID.randomUUID(), "admin", "domain", false); @@ -61,9 +40,7 @@ void checkOrgOwnerDiscrepanciesDiffOwnersNotInLdap() { List ownersNotInLdapGroup = new ArrayList<>(); ownersNotInLdapGroup.add(user2); - Tuple2 values = userLdapGroupSynchronizer.checkOrgOwnerDiscrepancies(ldapGroupUsers, ownerRoleUsers); - assertTrue(values._1().isEmpty()); - assertTrue(values._2().equals(ownersNotInLdapGroup)); + assertTrue(userLdapGroupSynchronizer.checkOrgOwnerDiscrepancies(ldapGroupUsers, ownerRoleUsers).equals(ownersNotInLdapGroup)); } @Test @@ -79,8 +56,6 @@ void checkOrgOwnerDiscrepanciesNoDiff() { ownerRoleUsers.add(user1); ownerRoleUsers.add(user2); - Tuple2 values = userLdapGroupSynchronizer.checkOrgOwnerDiscrepancies(ldapGroupUsers, ownerRoleUsers); - assertTrue(values._1().isEmpty()); - assertTrue(values._2().isEmpty()); + assertTrue(userLdapGroupSynchronizer.checkOrgOwnerDiscrepancies(ldapGroupUsers, ownerRoleUsers).isEmpty()); } } \ No newline at end of file