You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by jo...@apache.org on 2014/09/10 15:03:39 UTC

[27/39] AMBARI-7230. LDAP Sync Scale issues for thousands of users/100's of groups. (mahadev)

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/LdapUserGroupMemberDto.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/LdapUserGroupMemberDto.java b/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/LdapUserGroupMemberDto.java
new file mode 100644
index 0000000..319b831
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/LdapUserGroupMemberDto.java
@@ -0,0 +1,82 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.security.ldap;
+
+/**
+ * Pojo with information about LDAP membership.
+ */
+public class LdapUserGroupMemberDto {
+  /**
+   * Name of the group.
+   */
+  private final String groupName;
+
+  /**
+   * Name of the user.
+   */
+  private final String userName;
+
+  /**
+   * Constructor.
+   *
+   * @param groupName group name
+   * @param userName user name
+   */
+  public LdapUserGroupMemberDto(String groupName, String userName) {
+    this.groupName = groupName;
+    this.userName = userName;
+  }
+
+  /**
+   * Get the group name.
+   *
+   * @return the group name
+   */
+  public String getGroupName() {
+    return groupName;
+  }
+
+  /**
+   * Get the user name.
+   *
+   * @return the user name
+   */
+  public String getUserName() {
+    return userName;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    LdapUserGroupMemberDto that = (LdapUserGroupMemberDto) o;
+
+    if (userName != null ? !userName.equals(that.userName) : that.userName != null) return false;
+    if (groupName != null ? !groupName.equals(that.groupName) : that.groupName != null) return false;
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = userName != null ? userName.hashCode() : 0;
+    result = 31 * result + (groupName != null ? groupName.hashCode() : 0);
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/main/python/ambari-server.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/python/ambari-server.py b/ambari-server/src/main/python/ambari-server.py
index 81b79d1..35ba17b 100755
--- a/ambari-server/src/main/python/ambari-server.py
+++ b/ambari-server/src/main/python/ambari-server.py
@@ -2940,11 +2940,11 @@ def setup_ldap():
   LDAP_PRIMARY_URL_DEFAULT = get_value_from_properties(properties, ldap_property_list_reqd[0])
   LDAP_SECONDARY_URL_DEFAULT = get_value_from_properties(properties, ldap_property_list_reqd[1])
   LDAP_USE_SSL_DEFAULT = get_value_from_properties(properties, ldap_property_list_reqd[2], "false")
-  LDAP_USER_CLASS_DEFAULT = get_value_from_properties(properties, ldap_property_list_reqd[3], "person")
+  LDAP_USER_CLASS_DEFAULT = get_value_from_properties(properties, ldap_property_list_reqd[3], "posixAccount")
   LDAP_USER_ATT_DEFAULT = get_value_from_properties(properties, ldap_property_list_reqd[4], "uid")
-  LDAP_GROUP_CLASS_DEFAULT = get_value_from_properties(properties, ldap_property_list_reqd[5], "groupOfUniqueNames")
+  LDAP_GROUP_CLASS_DEFAULT = get_value_from_properties(properties, ldap_property_list_reqd[5], "posixGroup")
   LDAP_GROUP_ATT_DEFAULT = get_value_from_properties(properties, ldap_property_list_reqd[6], "cn")
-  LDAP_GROUP_MEMBER_DEFAULT = get_value_from_properties(properties, ldap_property_list_reqd[7], "uniqueMember")
+  LDAP_GROUP_MEMBER_DEFAULT = get_value_from_properties(properties, ldap_property_list_reqd[7], "memberUid")
   LDAP_BASE_DN_DEFAULT = get_value_from_properties(properties, ldap_property_list_reqd[8])
   LDAP_BIND_DEFAULT = get_value_from_properties(properties, ldap_property_list_reqd[9], "false")
   LDAP_MGR_DN_DEFAULT = get_value_from_properties(properties, ldap_property_list_opt[0])

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/main/resources/META-INF/persistence.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/META-INF/persistence.xml b/ambari-server/src/main/resources/META-INF/persistence.xml
index dfbf93e..2d8fedb 100644
--- a/ambari-server/src/main/resources/META-INF/persistence.xml
+++ b/ambari-server/src/main/resources/META-INF/persistence.xml
@@ -75,7 +75,11 @@
       <!--<property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" />-->
       <property name="eclipselink.cache.size.default" value="10000" />
       <property name="eclipselink.jdbc.batch-writing" value="JDBC"/>
+      <property name="eclipselink.jdbc.batch-writing.size" value="4000"/>
+      <property name="eclipselink.jdbc.sequence-connection-pool" value="true" />
       <property name="eclipselink.weaving" value="static" />
+      
+      <!--<property name="eclipselink.logging.level.sql" value="FINEST" />-->
       <!--<property name="eclipselink.id-validation" value="NULL" />-->
 
     </properties>

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapDataPopulatorTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapDataPopulatorTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapDataPopulatorTest.java
deleted file mode 100644
index 23f53cf..0000000
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapDataPopulatorTest.java
+++ /dev/null
@@ -1,261 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.server.security.authorization;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import junit.framework.Assert;
-
-import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.configuration.Configuration;
-import org.apache.ambari.server.orm.entities.GroupEntity;
-import org.apache.ambari.server.orm.entities.MemberEntity;
-import org.apache.ambari.server.orm.entities.PrincipalEntity;
-import org.apache.ambari.server.orm.entities.PrivilegeEntity;
-import org.apache.ambari.server.orm.entities.UserEntity;
-import org.easymock.Capture;
-import org.easymock.EasyMock;
-import org.easymock.IAnswer;
-import org.junit.Test;
-import org.springframework.ldap.core.LdapTemplate;
-
-public class AmbariLdapDataPopulatorTest {
-  private static class AmbariLdapDataPopulatorTestInstance extends AmbariLdapDataPopulator {
-
-    public AmbariLdapDataPopulatorTestInstance(Configuration configuration,
-        Users users) {
-      super(configuration, users);
-      this.ldapServerProperties = EasyMock.createNiceMock(LdapServerProperties.class);
-    }
-
-    final LdapTemplate ldapTemplate = EasyMock.createNiceMock(LdapTemplate.class);
-
-    @Override
-    protected LdapTemplate loadLdapTemplate() {
-      return ldapTemplate;
-    }
-
-    public LdapServerProperties getLdapServerProperties() {
-      return this.ldapServerProperties;
-    }
-  }
-
-  @Test
-  public void testRefreshGroupMembers() throws AmbariException {
-    final Configuration configuration = EasyMock.createNiceMock(Configuration.class);
-    final Users users = EasyMock.createNiceMock(Users.class);
-
-    final GroupEntity ldapGroup = new GroupEntity();
-    ldapGroup.setGroupId(1);
-    ldapGroup.setGroupName("ldapGroup");
-    ldapGroup.setLdapGroup(true);
-    ldapGroup.setMemberEntities(new HashSet<MemberEntity>());
-
-    final User ldapUserWithoutGroup = createLdapUserWithoutGroup();
-    final User ldapUserWithGroup = createLdapUserWithGroup(ldapGroup);
-    final User localUserWithoutGroup = createLocalUserWithoutGroup();
-    final User localUserWithGroup = createLocalUserWithGroup(ldapGroup);
-
-    final AmbariLdapDataPopulator populator = new AmbariLdapDataPopulatorTestInstance(configuration, users) {
-      @Override
-      protected Set<String> getExternalLdapGroupMembers(String groupName) {
-        return new HashSet<String>() {
-          {
-            add(ldapUserWithGroup.getUserName());
-            add(ldapUserWithoutGroup.getUserName());
-          }
-        };
-      }
-
-      @Override
-      protected Map<String, User> getInternalUsers() {
-        return new HashMap<String, User>() {
-          {
-            put(localUserWithGroup.getUserName(), localUserWithGroup);
-            put(localUserWithoutGroup.getUserName(), localUserWithoutGroup);
-          }
-        };
-      }
-
-      @Override
-      protected Map<String, User> getInternalMembers(String groupName) {
-        return new HashMap<String, User>() {
-          {
-            put(localUserWithGroup.getUserName(), localUserWithGroup);
-          }
-        };
-      }
-    };
-
-    users.createUser(EasyMock.<String> anyObject(), EasyMock.<String> anyObject());
-    EasyMock.expectLastCall().times(2);
-
-    users.addMemberToGroup(EasyMock.<String> anyObject(), EasyMock.<String> anyObject());
-    EasyMock.expectLastCall().times(2);
-
-    EasyMock.replay(users);
-
-    populator.refreshGroupMembers(ldapGroup.getGroupName());
-
-    EasyMock.verify(users);
-  }
-
-  @Test
-  public void testIsLdapEnabled_badConfiguration() {
-    final Configuration configuration = EasyMock.createNiceMock(Configuration.class);
-    final Users users = EasyMock.createNiceMock(Users.class);
-
-    final AmbariLdapDataPopulator populator = new AmbariLdapDataPopulatorTestInstance(configuration, users);
-
-    EasyMock.expect(configuration.isLdapConfigured()).andReturn(true);
-    EasyMock.expect(populator.loadLdapTemplate().list(EasyMock. <String>anyObject())).andThrow(new NullPointerException()).once();
-    EasyMock.replay(populator.loadLdapTemplate(), configuration);
-
-    Assert.assertFalse(populator.isLdapEnabled());
-    EasyMock.verify(populator.loadLdapTemplate(), configuration);
-  }
-
-  @Test
-  public void testIsLdapEnabled_reallyEnabled() {
-    final Configuration configuration = EasyMock.createNiceMock(Configuration.class);
-    final Users users = EasyMock.createNiceMock(Users.class);
-
-    final AmbariLdapDataPopulator populator = new AmbariLdapDataPopulatorTestInstance(configuration, users);
-
-    EasyMock.expect(configuration.isLdapConfigured()).andReturn(true);
-    EasyMock.expect(populator.loadLdapTemplate().list(EasyMock. <String>anyObject())).andReturn(Collections.emptyList()).once();
-    EasyMock.replay(populator.loadLdapTemplate(),configuration);
-
-    Assert.assertTrue(populator.isLdapEnabled());
-    EasyMock.verify(populator.loadLdapTemplate(), configuration);
-  }
-
-  @Test
-  public void testIsLdapEnabled_reallyDisabled() {
-    final Configuration configuration = EasyMock.createNiceMock(Configuration.class);
-    final Users users = EasyMock.createNiceMock(Users.class);
-
-    final AmbariLdapDataPopulator populator = new AmbariLdapDataPopulatorTestInstance(configuration, users);
-
-    EasyMock.expect(configuration.isLdapConfigured()).andReturn(false);
-    EasyMock.replay(populator.loadLdapTemplate(), configuration);
-
-    Assert.assertFalse(populator.isLdapEnabled());
-    EasyMock.verify(populator.loadLdapTemplate(), configuration);
-  }
-
-  @Test
-  @SuppressWarnings("serial")
-  public void testCleanUpLdapUsersWithoutGroup() throws AmbariException {
-    final Configuration configuration = EasyMock.createNiceMock(Configuration.class);
-    final Users users = EasyMock.createNiceMock(Users.class);
-
-    final GroupEntity ldapGroup = new GroupEntity();
-    ldapGroup.setGroupId(1);
-    ldapGroup.setGroupName("ldapGroup");
-    ldapGroup.setLdapGroup(true);
-    ldapGroup.setMemberEntities(new HashSet<MemberEntity>());
-
-    final User ldapUserWithoutGroup = createLdapUserWithoutGroup();
-    final User ldapUserWithGroup = createLdapUserWithGroup(ldapGroup);
-    final User localUserWithoutGroup = createLocalUserWithoutGroup();
-    final User localUserWithGroup = createLocalUserWithGroup(ldapGroup);
-
-    final List<User> allUsers = new ArrayList<User>() {
-      {
-        add(ldapUserWithoutGroup);
-        add(ldapUserWithGroup);
-        add(localUserWithoutGroup);
-        add(localUserWithGroup);
-      }
-    };
-    EasyMock.expect(users.getAllUsers()).andReturn(new ArrayList<User>(allUsers));
-
-    final List<User> removedUsers = new ArrayList<User>();
-    final Capture<User> userCapture = new Capture<User>();
-    users.removeUser(EasyMock.capture(userCapture));
-    EasyMock.expectLastCall().andAnswer(new IAnswer<Void>() {
-      @Override
-      public Void answer() throws Throwable {
-        removedUsers.add(userCapture.getValue());
-        allUsers.remove(userCapture.getValue());
-        return null;
-      }
-    });
-
-    EasyMock.replay(users);
-
-    final AmbariLdapDataPopulator populator = new AmbariLdapDataPopulatorTestInstance(configuration, users);
-    populator.cleanUpLdapUsersWithoutGroup();
-
-    Assert.assertEquals(removedUsers.size(), 1);
-    Assert.assertEquals(allUsers.size(), 3);
-    Assert.assertTrue(allUsers.contains(ldapUserWithGroup));
-    Assert.assertTrue(allUsers.contains(localUserWithoutGroup));
-    Assert.assertTrue(allUsers.contains(localUserWithGroup));
-    Assert.assertEquals(removedUsers.get(0), ldapUserWithoutGroup);
-
-    EasyMock.verify(users);
-  }
-
-  private static int userIdCounter = 1;
-
-  private User createUser(String name, boolean ldapUser, GroupEntity group) {
-    final UserEntity userEntity = new UserEntity();
-    userEntity.setUserId(userIdCounter++);
-    userEntity.setUserName(name);
-    userEntity.setCreateTime(new Date());
-    userEntity.setLdapUser(ldapUser);
-    userEntity.setActive(true);
-    userEntity.setMemberEntities(new HashSet<MemberEntity>());
-    final PrincipalEntity principalEntity = new PrincipalEntity();
-    principalEntity.setPrivileges(new HashSet<PrivilegeEntity>());
-    userEntity.setPrincipal(principalEntity);
-    if (group != null) {
-      final MemberEntity member = new MemberEntity();
-      member.setUser(userEntity);
-      member.setGroup(group);
-      group.getMemberEntities().add(member);
-      userEntity.getMemberEntities().add(member);
-    }
-    return new User(userEntity);
-  }
-
-  private User createLdapUserWithoutGroup() {
-    return createUser("LdapUserWithoutGroup", true, null);
-  }
-
-  private User createLocalUserWithoutGroup() {
-    return createUser("LocalUserWithoutGroup", false, null);
-  }
-
-  private User createLdapUserWithGroup(GroupEntity group) {
-    return createUser("LdapUserWithGroup", true, group);
-  }
-
-  private User createLocalUserWithGroup(GroupEntity group) {
-    return createUser("LocalUserWithGroup", false, group);
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/test/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulatorTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulatorTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulatorTest.java
new file mode 100644
index 0000000..906d695
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulatorTest.java
@@ -0,0 +1,202 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.security.ldap;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import junit.framework.Assert;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.orm.entities.GroupEntity;
+import org.apache.ambari.server.orm.entities.MemberEntity;
+import org.apache.ambari.server.orm.entities.PrincipalEntity;
+import org.apache.ambari.server.orm.entities.PrivilegeEntity;
+import org.apache.ambari.server.orm.entities.UserEntity;
+import org.apache.ambari.server.security.authorization.LdapServerProperties;
+import org.apache.ambari.server.security.authorization.User;
+import org.apache.ambari.server.security.authorization.Users;
+import org.apache.ambari.server.security.ldap.AmbariLdapDataPopulator;
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.easymock.IAnswer;
+import org.junit.Test;
+import org.springframework.ldap.core.AttributesMapper;
+import org.springframework.ldap.core.LdapTemplate;
+
+public class AmbariLdapDataPopulatorTest {
+  private static class AmbariLdapDataPopulatorTestInstance extends AmbariLdapDataPopulator {
+
+    public AmbariLdapDataPopulatorTestInstance(Configuration configuration,
+        Users users) {
+      super(configuration, users);
+      this.ldapServerProperties = EasyMock.createNiceMock(LdapServerProperties.class);
+    }
+
+    final LdapTemplate ldapTemplate = EasyMock.createNiceMock(LdapTemplate.class);
+
+    @Override
+    protected LdapTemplate loadLdapTemplate() {
+      return ldapTemplate;
+    }
+
+    public LdapServerProperties getLdapServerProperties() {
+      return this.ldapServerProperties;
+    }
+  }
+
+  @Test
+  public void testIsLdapEnabled_badConfiguration() {
+    final Configuration configuration = EasyMock.createNiceMock(Configuration.class);
+    final Users users = EasyMock.createNiceMock(Users.class);
+
+    final AmbariLdapDataPopulator populator = new AmbariLdapDataPopulatorTestInstance(configuration, users);
+
+    EasyMock.expect(configuration.isLdapConfigured()).andReturn(true);
+    EasyMock.expect(populator.loadLdapTemplate().search(EasyMock. <String>anyObject(), EasyMock. <String>anyObject(), EasyMock. <AttributesMapper>anyObject())).andThrow(new NullPointerException()).once();
+    EasyMock.replay(populator.loadLdapTemplate(), configuration);
+
+    Assert.assertFalse(populator.isLdapEnabled());
+    EasyMock.verify(populator.loadLdapTemplate(), configuration);
+  }
+
+  @Test
+  public void testIsLdapEnabled_reallyEnabled() {
+    final Configuration configuration = EasyMock.createNiceMock(Configuration.class);
+    final Users users = EasyMock.createNiceMock(Users.class);
+
+    final AmbariLdapDataPopulator populator = new AmbariLdapDataPopulatorTestInstance(configuration, users);
+
+    EasyMock.expect(configuration.isLdapConfigured()).andReturn(true);
+    EasyMock.expect(populator.loadLdapTemplate().search(EasyMock. <String>anyObject(), EasyMock. <String>anyObject(), EasyMock. <AttributesMapper>anyObject())).andReturn(Collections.emptyList()).once();
+    EasyMock.replay(populator.loadLdapTemplate(), configuration);
+
+    Assert.assertTrue(populator.isLdapEnabled());
+    EasyMock.verify(populator.loadLdapTemplate(), configuration);
+  }
+
+  @Test
+  public void testIsLdapEnabled_reallyDisabled() {
+    final Configuration configuration = EasyMock.createNiceMock(Configuration.class);
+    final Users users = EasyMock.createNiceMock(Users.class);
+
+    final AmbariLdapDataPopulator populator = new AmbariLdapDataPopulatorTestInstance(configuration, users);
+
+    EasyMock.expect(configuration.isLdapConfigured()).andReturn(false);
+    EasyMock.replay(populator.loadLdapTemplate(), configuration);
+
+    Assert.assertFalse(populator.isLdapEnabled());
+    EasyMock.verify(populator.loadLdapTemplate(), configuration);
+  }
+
+  @Test
+  @SuppressWarnings("serial")
+  public void testCleanUpLdapUsersWithoutGroup() throws AmbariException {
+    final Configuration configuration = EasyMock.createNiceMock(Configuration.class);
+    final Users users = EasyMock.createNiceMock(Users.class);
+
+    final GroupEntity ldapGroup = new GroupEntity();
+    ldapGroup.setGroupId(1);
+    ldapGroup.setGroupName("ldapGroup");
+    ldapGroup.setLdapGroup(true);
+    ldapGroup.setMemberEntities(new HashSet<MemberEntity>());
+
+    final User ldapUserWithoutGroup = createLdapUserWithoutGroup();
+    final User ldapUserWithGroup = createLdapUserWithGroup(ldapGroup);
+    final User localUserWithoutGroup = createLocalUserWithoutGroup();
+    final User localUserWithGroup = createLocalUserWithGroup(ldapGroup);
+
+    final List<User> allUsers = new ArrayList<User>() {
+      {
+        add(ldapUserWithoutGroup);
+        add(ldapUserWithGroup);
+        add(localUserWithoutGroup);
+        add(localUserWithGroup);
+      }
+    };
+    EasyMock.expect(users.getAllUsers()).andReturn(new ArrayList<User>(allUsers));
+
+    final List<User> removedUsers = new ArrayList<User>();
+    final Capture<User> userCapture = new Capture<User>();
+    users.removeUser(EasyMock.capture(userCapture));
+    EasyMock.expectLastCall().andAnswer(new IAnswer<Void>() {
+      @Override
+      public Void answer() throws Throwable {
+        removedUsers.add(userCapture.getValue());
+        allUsers.remove(userCapture.getValue());
+        return null;
+      }
+    });
+
+    EasyMock.replay(users);
+
+    final AmbariLdapDataPopulator populator = new AmbariLdapDataPopulatorTestInstance(configuration, users);
+    populator.cleanUpLdapUsersWithoutGroup();
+
+    Assert.assertEquals(removedUsers.size(), 1);
+    Assert.assertEquals(allUsers.size(), 3);
+    Assert.assertTrue(allUsers.contains(ldapUserWithGroup));
+    Assert.assertTrue(allUsers.contains(localUserWithoutGroup));
+    Assert.assertTrue(allUsers.contains(localUserWithGroup));
+    Assert.assertEquals(removedUsers.get(0), ldapUserWithoutGroup);
+
+    EasyMock.verify(users);
+  }
+
+  private static int userIdCounter = 1;
+
+  private User createUser(String name, boolean ldapUser, GroupEntity group) {
+    final UserEntity userEntity = new UserEntity();
+    userEntity.setUserId(userIdCounter++);
+    userEntity.setUserName(name);
+    userEntity.setCreateTime(new Date());
+    userEntity.setLdapUser(ldapUser);
+    userEntity.setActive(true);
+    userEntity.setMemberEntities(new HashSet<MemberEntity>());
+    final PrincipalEntity principalEntity = new PrincipalEntity();
+    principalEntity.setPrivileges(new HashSet<PrivilegeEntity>());
+    userEntity.setPrincipal(principalEntity);
+    if (group != null) {
+      final MemberEntity member = new MemberEntity();
+      member.setUser(userEntity);
+      member.setGroup(group);
+      group.getMemberEntities().add(member);
+      userEntity.getMemberEntities().add(member);
+    }
+    return new User(userEntity);
+  }
+
+  private User createLdapUserWithoutGroup() {
+    return createUser("LdapUserWithoutGroup", true, null);
+  }
+
+  private User createLocalUserWithoutGroup() {
+    return createUser("LocalUserWithoutGroup", false, null);
+  }
+
+  private User createLdapUserWithGroup(GroupEntity group) {
+    return createUser("LdapUserWithGroup", true, group);
+  }
+
+  private User createLocalUserWithGroup(GroupEntity group) {
+    return createUser("LocalUserWithGroup", false, group);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/test/java/org/apache/ambari/server/security/ldap/LdapPerformanceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/ldap/LdapPerformanceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/ldap/LdapPerformanceTest.java
new file mode 100644
index 0000000..a2cb388
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/ldap/LdapPerformanceTest.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.security.ldap;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.orm.GuiceJpaInitializer;
+import org.apache.ambari.server.security.ClientSecurityType;
+import org.apache.ambari.server.security.authorization.AuthorizationTestModule;
+import org.apache.ambari.server.security.authorization.Users;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import com.google.inject.Guice;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+
+/**
+ * Performs sync request to real LDAP server.
+ */
+@Ignore
+public class LdapPerformanceTest {
+
+  private static Injector injector;
+
+  @Inject
+  private AmbariLdapDataPopulator populator;
+
+  @Inject
+  private Users users;
+
+  @Inject
+  Configuration configuration;
+
+  final String SPRING_CONTEXT_LOCATION = "classpath:webapp/WEB-INF/spring-security.xml";
+
+  @Before
+  public void setUp() {
+    injector = Guice.createInjector(new AuthorizationTestModule());
+
+    injector.injectMembers(this);
+    injector.getInstance(GuiceJpaInitializer.class);
+    configuration.setClientSecurityType(ClientSecurityType.LDAP);
+    configuration.setLdap("c6402.ambari.apache.org:389", "posixAccount", "uid",
+        "posixGroup", "cn", "memberUid", "dc=apache,dc=org", false,
+        "uid=hdfs,ou=people,ou=dev,dc=apache,dc=org", "hdfs");
+  }
+
+  @Test
+  public void testLdapSync() throws AmbariException, InterruptedException {
+    long time = System.currentTimeMillis();
+    Set<LdapGroupDto> groups = populator.getExternalLdapGroupInfo();
+    Set<LdapUserDto> users = populator.getExternalLdapUserInfo();
+    Set<String> userNames = new HashSet<String>();
+    for (LdapUserDto user : users) {
+      userNames.add(user.getUserName());
+    }
+    Set<String> groupNames = new HashSet<String>();
+    for (LdapGroupDto group : groups) {
+      groupNames.add(group.getGroupName());
+    }
+    System.out.println("Data fetch: " + (System.currentTimeMillis() - time));
+    time = System.currentTimeMillis();
+    LdapBatchDto batchDto = populator.synchronizeLdapUsersAndGroups(userNames, groupNames);
+    batchDto = populator.synchronizeLdapUsersAndGroups(userNames, groupNames);
+    this.users.processLdapSync(batchDto);
+    System.out.println("Initial sync: " + (System.currentTimeMillis() - time));
+    time = System.currentTimeMillis();
+    batchDto = populator.synchronizeLdapUsersAndGroups(userNames, groupNames);
+    this.users.processLdapSync(batchDto);
+    System.out.println("Subsequent sync: " + (System.currentTimeMillis() - time));
+    time = System.currentTimeMillis();
+  }
+}