protected void refreshGroupMembers(LdapBatchDto batchInfo, LdapGroupDto group, Map<String, User> internalUsers,
                                     Map<String, Group> internalGroupsMap, Set<String> groupMemberAttributes, boolean recursive,
                                     boolean collectIgnoredUsers)
      throws AmbariException {
    Set<LdapUserDto> externalMembers = new HashSet<>();

    if (groupMemberAttributes == null) {
      groupMemberAttributes = new HashSet<>();
    }

    for (String memberAttributeValue : group.getMemberAttributes()) {
      LdapUserDto groupMember = getLdapUserByMemberAttr(memberAttributeValue);
      if (groupMember != null) {
        externalMembers.add(groupMember);
      } else {
        // if we haven't already processed this group
        if (recursive && !groupMemberAttributes.contains(memberAttributeValue)) {
          // if the member is another group then add all of its members
          LdapGroupDto subGroup = getLdapGroupByMemberAttr(memberAttributeValue);
          if (subGroup != null) {
            groupMemberAttributes.add(memberAttributeValue);
            addLdapGroup(batchInfo, internalGroupsMap, subGroup);
            refreshGroupMembers(batchInfo, subGroup, internalUsers, internalGroupsMap, groupMemberAttributes, true, collectIgnoredUsers);
          }
        }
      }
    }
    String groupName = group.getGroupName();
    final Map<String, User> internalMembers = getInternalMembers(groupName);
    for (LdapUserDto externalMember : externalMembers) {
      String userName = externalMember.getUserName();
      if (internalUsers.containsKey(userName)) {
        final User user = internalUsers.get(userName);
        if (user == null) {
          // user is fresh and is already added to batch info
          if (!internalMembers.containsKey(userName)) {
            batchInfo.getMembershipToAdd().add(new LdapUserGroupMemberDto(groupName, externalMember.getUserName()));
          }
          continue;
        }
        if (!user.isLdapUser()) {
          if (LdapUsernameCollisionHandlingBehavior.SKIP == getConfiguration().syncCollisionHandlingBehavior()) {
            // existing user can not be converted to ldap user, so skip it
            LOG.info("User '{}' skipped because it is local user", userName);
            batchInfo.getUsersSkipped().add(externalMember);
            continue; // and remove from group
          } else {
            batchInfo.getUsersToBecomeLdap().add(externalMember);
          }
        } else if (collectIgnoredUsers) {
          batchInfo.getUsersIgnored().add(externalMember);
        }
        if (!internalMembers.containsKey(userName)) {
          batchInfo.getMembershipToAdd().add(new LdapUserGroupMemberDto(groupName, externalMember.getUserName()));
        }
        internalMembers.remove(userName);
      } else {
        batchInfo.getUsersToBeCreated().add(externalMember);
        batchInfo.getMembershipToAdd().add(new LdapUserGroupMemberDto(groupName, externalMember.getUserName()));
      }
    }
    for (Entry<String, User> userToBeUnsynced : internalMembers.entrySet()) {
      final User user = userToBeUnsynced.getValue();
      batchInfo.getMembershipToRemove().add(new LdapUserGroupMemberDto(groupName, user.getUserName()));
    }
  }
Check group members of the synced group: add missing ones and remove the ones absent in external LDAP.

@param batchInfo             batch update object
@param group                 ldap group
@param internalUsers         map of internal users
@param groupMemberAttributes set of group member attributes that have already been refreshed
@param recursive             if disabled, it won't refresh members recursively (its not needed in case of all groups are processed)
@param collectIgnoredUsers   true, to collect the set of existing users that would normally be ignored;
                             false, to continue to ignore them
@throws AmbariException if group refresh failed
ambari-server/src/main/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulator.java