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


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/17b48bf4
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/17b48bf4
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/17b48bf4

Branch: refs/heads/branch-alerts-dev
Commit: 17b48bf40ff58a1bf429d1fbc14b3049ef79391d
Parents: fbe8b87
Author: Mahadev Konar <maha...@apache.org>
Authored: Tue Sep 9 15:09:00 2014 -0700
Committer: Mahadev Konar <maha...@apache.org>
Committed: Tue Sep 9 15:09:08 2014 -0700

----------------------------------------------------------------------
 .../server/configuration/Configuration.java     |  14 +
 .../controller/AmbariManagementController.java  |  16 +-
 .../AmbariManagementControllerImpl.java         |  34 +-
 .../ambari/server/controller/AmbariServer.java  |   6 +-
 .../internal/ControllerResourceProvider.java    |  22 +-
 .../apache/ambari/server/orm/dao/GroupDAO.java  |  30 +-
 .../apache/ambari/server/orm/dao/MemberDAO.java |  34 +-
 .../ambari/server/orm/dao/PrincipalDAO.java     |  27 +-
 .../ambari/server/orm/dao/PrincipalTypeDAO.java |  29 +-
 .../apache/ambari/server/orm/dao/UserDAO.java   |  49 ++-
 .../server/orm/entities/MemberEntity.java       |   7 +-
 .../server/orm/entities/PrincipalEntity.java    |   2 +-
 .../ambari/server/orm/entities/UserEntity.java  |   5 +-
 .../authorization/AmbariLdapDataPopulator.java  | 409 ------------------
 .../server/security/authorization/User.java     |   2 +-
 .../server/security/authorization/Users.java    | 158 ++++++-
 .../security/ldap/AmbariLdapDataPopulator.java  | 430 +++++++++++++++++++
 .../server/security/ldap/LdapBatchDto.java      |  67 +++
 .../server/security/ldap/LdapGroupDto.java      | 113 +++++
 .../server/security/ldap/LdapSyncDto.java       |  72 ++++
 .../server/security/ldap/LdapUserDto.java       | 133 ++++++
 .../security/ldap/LdapUserGroupMemberDto.java   |  82 ++++
 ambari-server/src/main/python/ambari-server.py  |   6 +-
 .../src/main/resources/META-INF/persistence.xml |   4 +
 .../AmbariLdapDataPopulatorTest.java            | 261 -----------
 .../ldap/AmbariLdapDataPopulatorTest.java       | 202 +++++++++
 .../security/ldap/LdapPerformanceTest.java      |  94 ++++
 27 files changed, 1561 insertions(+), 747 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
index ae20d43..a21f98c 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
@@ -576,6 +576,20 @@ public class Configuration {
     properties.setProperty(CLIENT_SECURITY_KEY, type.toString());
   }
 
+  public void setLdap(String host, String userClass, String userNameAttr, 
String groupClass, String groupName, String groupMember,
+      String baseDN, boolean anon, String managerDN, String managerPass) {
+    properties.setProperty(LDAP_PRIMARY_URL_KEY, host);
+    properties.setProperty(LDAP_USER_OBJECT_CLASS_KEY, userClass);
+    properties.setProperty(LDAP_USERNAME_ATTRIBUTE_KEY, userNameAttr);
+    properties.setProperty(LDAP_GROUP_OBJECT_CLASS_KEY, groupClass);
+    properties.setProperty(LDAP_GROUP_NAMING_ATTR_KEY, groupName);
+    properties.setProperty(LDAP_GROUP_MEMEBERSHIP_ATTR_KEY, groupMember);
+    properties.setProperty(LDAP_BASE_DN_KEY, baseDN);
+    properties.setProperty(LDAP_BIND_ANONYMOUSLY_KEY, String.valueOf(anon));
+    properties.setProperty(LDAP_MANAGER_DN_KEY, managerDN);
+    properties.setProperty(LDAP_MANAGER_PASSWORD_KEY, managerPass);
+  }
+
   public String getWebAppDir() {
     LOG.info("Web App DIR test " + properties.getProperty(WEBAPP_DIR));
     return properties.getProperty(WEBAPP_DIR, "web");

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
index 1a5d933..13efd32 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
@@ -24,6 +24,7 @@ import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.controller.internal.RequestStageContainer;
 import org.apache.ambari.server.metadata.RoleCommandOrder;
 import org.apache.ambari.server.scheduler.ExecutionScheduleManager;
+import org.apache.ambari.server.security.ldap.LdapSyncDto;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.ConfigHelper;
@@ -36,6 +37,7 @@ import org.apache.ambari.server.state.ServiceFactory;
 import org.apache.ambari.server.state.State;
 import org.apache.ambari.server.state.configgroup.ConfigGroupFactory;
 import org.apache.ambari.server.state.scheduler.RequestExecutionFactory;
+
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -689,20 +691,12 @@ public interface AmbariManagementController {
   public boolean checkLdapConfigured();
 
   /**
-   * Retrieves users from external LDAP.
-   *
-   * @return key-value pairs UserName-Synced
-   * @throws AmbariException if LDAP is configured incorrectly
-   */
-  public Map<String, Boolean> getLdapUsersSyncInfo() throws AmbariException;
-
-  /**
-   * Retrieves groups from external LDAP.
+   * Retrieves groups and users from external LDAP.
    *
-   * @return key-value pairs GroupName-Synced
+   * @return ldap sync DTO
    * @throws AmbariException if LDAP is configured incorrectly
    */
-  public Map<String, Boolean> getLdapGroupsSyncInfo() throws AmbariException;
+  public LdapSyncDto getLdapSyncInfo() throws AmbariException;
 
   /**
    * Synchronizes local users and groups with given data.

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
index 99552e5..97137a2 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
@@ -91,11 +91,13 @@ import 
org.apache.ambari.server.customactions.ActionDefinition;
 import org.apache.ambari.server.metadata.ActionMetadata;
 import org.apache.ambari.server.metadata.RoleCommandOrder;
 import org.apache.ambari.server.scheduler.ExecutionScheduleManager;
-import org.apache.ambari.server.security.authorization.AmbariLdapDataPopulator;
 import org.apache.ambari.server.security.authorization.AuthorizationHelper;
 import org.apache.ambari.server.security.authorization.Group;
 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.apache.ambari.server.security.ldap.LdapBatchDto;
+import org.apache.ambari.server.security.ldap.LdapSyncDto;
 import org.apache.ambari.server.stageplanner.RoleGraph;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
@@ -143,7 +145,6 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.cache.Cache;
 import com.google.common.cache.CacheBuilder;
-import com.google.common.collect.Multimaps;
 import com.google.gson.Gson;
 import com.google.inject.Inject;
 import com.google.inject.Injector;
@@ -724,11 +725,7 @@ public class AmbariManagementControllerImpl implements 
AmbariManagementControlle
         throw new AmbariException("User already exists.");
       }
 
-      users.createUser(request.getUsername(), request.getPassword(), 
request.isActive(), request.isAdmin());
-
-      if (null != request.isActive() && null != user) {
-        users.setUserActive(user, request.isActive());
-      }
+      users.createUser(request.getUsername(), request.getPassword(), 
request.isActive(), request.isAdmin(), false);
     }
   }
 
@@ -1805,7 +1802,7 @@ public class AmbariManagementControllerImpl implements 
AmbariManagementControlle
             RoleCommand roleCommand;
             State oldSchState = scHost.getState();
             ServiceComponentHostEvent event;
-            
+
             switch (newState) {
               case INSTALLED:
                 if (oldSchState == State.INIT
@@ -1960,7 +1957,7 @@ public class AmbariManagementControllerImpl implements 
AmbariManagementControlle
                     break;
                 }
               }
-              
+
               if (null == requestParameters) {
                 requestParameters = new HashMap<String, String>();
               }
@@ -1972,7 +1969,7 @@ public class AmbariManagementControllerImpl implements 
AmbariManagementControlle
           }
         }
       }
-      
+
       for (String serviceName : smokeTestServices) { // Creates smoke test 
commands
         Service s = cluster.getService(serviceName);
         // find service component host
@@ -3313,7 +3310,7 @@ public class AmbariManagementControllerImpl implements 
AmbariManagementControlle
     }
     return response;
   }
-  
+
   @Override
   public Set<StackConfigurationResponse> getStackLevelConfigurations(
       Set<StackLevelConfigurationRequest> requests) throws AmbariException {
@@ -3322,7 +3319,7 @@ public class AmbariManagementControllerImpl implements 
AmbariManagementControlle
 
       String stackName    = request.getStackName();
       String stackVersion = request.getStackVersion();
-      
+
       Set<StackConfigurationResponse> stackConfigurations = 
getStackLevelConfigurations(request);
 
       for (StackConfigurationResponse stackConfigurationResponse : 
stackConfigurations) {
@@ -3673,19 +3670,14 @@ public class AmbariManagementControllerImpl implements 
AmbariManagementControlle
   }
 
   @Override
-  public Map<String, Boolean> getLdapUsersSyncInfo() throws AmbariException {
-    return ldapDataPopulator.getLdapUsersSyncInfo();
-  }
-
-  @Override
-  public Map<String, Boolean> getLdapGroupsSyncInfo() throws AmbariException {
-    return ldapDataPopulator.getLdapGroupsSyncInfo();
+  public LdapSyncDto getLdapSyncInfo() throws AmbariException {
+    return ldapDataPopulator.getLdapSyncInfo();
   }
 
   @Override
   public synchronized void synchronizeLdapUsersAndGroups(Set<String> users,
       Set<String> groups) throws AmbariException {
-    ldapDataPopulator.synchronizeLdapUsersAndGroups(users, groups);
+    final LdapBatchDto batchInfo = 
ldapDataPopulator.synchronizeLdapUsersAndGroups(users, groups);
+    this.users.processLdapSync(batchInfo);
   }
-
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
index d83138a..4e0d092 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
@@ -76,11 +76,11 @@ import 
org.apache.ambari.server.scheduler.ExecutionScheduleManager;
 import org.apache.ambari.server.security.CertificateManager;
 import org.apache.ambari.server.security.SecurityFilter;
 import 
org.apache.ambari.server.security.authorization.AmbariLdapAuthenticationProvider;
-import org.apache.ambari.server.security.authorization.AmbariLdapDataPopulator;
 import 
org.apache.ambari.server.security.authorization.AmbariLocalUserDetailsService;
 import org.apache.ambari.server.security.authorization.Users;
 import 
org.apache.ambari.server.security.authorization.AmbariAuthorizationFilter;
 import 
org.apache.ambari.server.security.authorization.internal.AmbariInternalAuthenticationProvider;
+import org.apache.ambari.server.security.ldap.AmbariLdapDataPopulator;
 import org.apache.ambari.server.security.unsecured.rest.CertificateDownload;
 import org.apache.ambari.server.security.unsecured.rest.CertificateSign;
 import org.apache.ambari.server.security.unsecured.rest.ConnectionInfo;
@@ -461,8 +461,8 @@ public class AmbariServer {
       LOG.info("Database init needed - creating default data");
       Users users = injector.getInstance(Users.class);
 
-      users.createUser("admin", "admin", true, true);
-      users.createUser("user", "user", true, false);
+      users.createUser("admin", "admin");
+      users.createUser("user", "user");
 
       MetainfoEntity schemaVersion = new MetainfoEntity();
       schemaVersion.setMetainfoName(Configuration.SERVER_VERSION_KEY);

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ControllerResourceProvider.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ControllerResourceProvider.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ControllerResourceProvider.java
index 9434026..a3bd6d5 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ControllerResourceProvider.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ControllerResourceProvider.java
@@ -23,7 +23,6 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Set;
 
 import org.apache.ambari.server.AmbariException;
@@ -40,6 +39,9 @@ import 
org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
 import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.security.ldap.LdapGroupDto;
+import org.apache.ambari.server.security.ldap.LdapSyncDto;
+import org.apache.ambari.server.security.ldap.LdapUserDto;
 import org.apache.commons.lang.StringUtils;
 
 /**
@@ -137,12 +139,14 @@ class ControllerResourceProvider extends 
AbstractControllerResourceProvider {
             ldapConfigured, requestedIds);
         if (ldapConfigured) {
           try {
+            final LdapSyncDto syncInfo = 
getManagementController().getLdapSyncInfo();
+
             final List<String> allUsers = new ArrayList<String>();
             final List<String> syncedUsers = new ArrayList<String>();
-            for (Entry<String, Boolean> user : 
getManagementController().getLdapUsersSyncInfo().entrySet()) {
-              allUsers.add(user.getKey());
-              if (user.getValue()) {
-                syncedUsers.add(user.getKey());
+            for (LdapUserDto user : syncInfo.getUsers()) {
+              allUsers.add(user.getUserName());
+              if (user.isSynced()) {
+                syncedUsers.add(user.getUserName());
               }
             }
             setResourceProperty(resource, CONTROLLER_LDAP_USERS_PROPERTY_ID,
@@ -151,10 +155,10 @@ class ControllerResourceProvider extends 
AbstractControllerResourceProvider {
                 syncedUsers, requestedIds);
             final List<String> allGroups = new ArrayList<String>();
             final List<String> syncedGroups = new ArrayList<String>();
-            for (Entry<String, Boolean> group : 
getManagementController().getLdapGroupsSyncInfo().entrySet()) {
-              allGroups.add(group.getKey());
-              if (group.getValue()) {
-                syncedGroups.add(group.getKey());
+            for (LdapGroupDto group : syncInfo.getGroups()) {
+              allGroups.add(group.getGroupName());
+              if (group.isSynced()) {
+                syncedGroups.add(group.getGroupName());
               }
             }
             setResourceProperty(resource, CONTROLLER_LDAP_GROUPS_PROPERTY_ID,

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/GroupDAO.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/GroupDAO.java 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/GroupDAO.java
index a2caefa..7b300dc 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/GroupDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/GroupDAO.java
@@ -17,8 +17,11 @@
  */
 package org.apache.ambari.server.orm.dao;
 
+import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import javax.persistence.EntityManager;
 import javax.persistence.NoResultException;
@@ -30,6 +33,7 @@ import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
 import com.google.inject.persist.Transactional;
+
 import org.apache.ambari.server.orm.entities.PrincipalEntity;
 
 @Singleton
@@ -79,8 +83,15 @@ public class GroupDAO {
 
   @Transactional
   public void create(GroupEntity group) {
-    group.setGroupName(group.getGroupName().toLowerCase());
-    entityManagerProvider.get().persist(group);
+    create(new HashSet<GroupEntity>(Arrays.asList(group)));
+  }
+
+  @Transactional
+  public void create(Set<GroupEntity> groups) {
+    for (GroupEntity group: groups) {
+      group.setGroupName(group.getGroupName().toLowerCase());
+      entityManagerProvider.get().persist(group);
+    }
   }
 
   @Transactional
@@ -90,12 +101,27 @@ public class GroupDAO {
   }
 
   @Transactional
+  public void merge(Set<GroupEntity> groups) {
+    for (GroupEntity group: groups) {
+      group.setGroupName(group.getGroupName().toLowerCase());
+      entityManagerProvider.get().merge(group);
+    }
+  }
+
+  @Transactional
   public void remove(GroupEntity group) {
     entityManagerProvider.get().remove(merge(group));
     
entityManagerProvider.get().getEntityManagerFactory().getCache().evictAll();
   }
 
   @Transactional
+  public void remove(Set<GroupEntity> groups) {
+    for (GroupEntity groupEntity: groups) {
+      
entityManagerProvider.get().remove(entityManagerProvider.get().merge(groupEntity));
+    }
+  }
+
+  @Transactional
   public void removeByPK(Integer groupPK) {
     remove(findByPK(groupPK));
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/MemberDAO.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/MemberDAO.java 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/MemberDAO.java
index 5788b81..e831db2 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/MemberDAO.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/MemberDAO.java
@@ -17,19 +17,23 @@
  */
 package org.apache.ambari.server.orm.dao;
 
+import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
 import javax.persistence.TypedQuery;
 
 import org.apache.ambari.server.orm.RequiresSession;
 import org.apache.ambari.server.orm.entities.MemberEntity;
+import org.apache.ambari.server.orm.entities.UserEntity;
 
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
 import com.google.inject.persist.Transactional;
-import org.apache.ambari.server.orm.entities.UserEntity;
 
 @Singleton
 public class MemberDAO {
@@ -44,6 +48,18 @@ public class MemberDAO {
   }
 
   @RequiresSession
+  public MemberEntity findByUserAndGroup(String userName, String groupName) {
+    final TypedQuery<MemberEntity> query = 
entityManagerProvider.get().createNamedQuery("memberByUserAndGroup", 
MemberEntity.class);
+    query.setParameter("username", userName.toLowerCase());
+    query.setParameter("groupname", groupName.toLowerCase());
+    try {
+      return query.getSingleResult();
+    } catch (NoResultException e) {
+      return null;
+    }
+  }
+
+  @RequiresSession
   public List<MemberEntity> findAll() {
     final TypedQuery<MemberEntity> query = 
entityManagerProvider.get().createQuery("SELECT m FROM MemberEntity m", 
MemberEntity.class);
     return daoUtils.selectList(query);
@@ -57,7 +73,14 @@ public class MemberDAO {
 
   @Transactional
   public void create(MemberEntity member) {
-    entityManagerProvider.get().persist(member);
+    create(new HashSet<MemberEntity>(Arrays.asList(member)));
+  }
+
+  @Transactional
+  public void create(Set<MemberEntity> members) {
+    for (MemberEntity member: members) {
+      entityManagerProvider.get().persist(member);
+    }
   }
 
   @Transactional
@@ -71,6 +94,13 @@ public class MemberDAO {
   }
 
   @Transactional
+  public void remove(Set<MemberEntity> members) {
+    for (MemberEntity member: members) {
+      
entityManagerProvider.get().remove(entityManagerProvider.get().merge(member));
+    }
+  }
+
+  @Transactional
   public void removeByPK(Integer memberPK) {
     remove(findByPK(memberPK));
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PrincipalDAO.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PrincipalDAO.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PrincipalDAO.java
index 334e978..7ac4f05 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PrincipalDAO.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PrincipalDAO.java
@@ -18,17 +18,18 @@
 
 package org.apache.ambari.server.orm.dao;
 
+import java.util.Arrays;
+import java.util.List;
+import javax.persistence.EntityManager;
+import javax.persistence.TypedQuery;
+
+import org.apache.ambari.server.orm.entities.PrincipalEntity;
+
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
 import com.google.inject.persist.Transactional;
 
-import org.apache.ambari.server.orm.entities.PrincipalEntity;
-import javax.persistence.EntityManager;
-import javax.persistence.TypedQuery;
-
-import java.util.List;
-
 /**
  * Principal Data Access Object.
  */
@@ -82,7 +83,19 @@ public class PrincipalDAO {
    */
   @Transactional
   public void create(PrincipalEntity entity) {
-    entityManagerProvider.get().persist(entity);
+    create(Arrays.asList(entity));
+  }
+
+  /**
+   * Make instances managed and persistent.
+   *
+   * @param entities entities to store
+   */
+  @Transactional
+  public void create(List<PrincipalEntity> entities) {
+    for (PrincipalEntity entity: entities) {
+      entityManagerProvider.get().persist(entity);
+    }
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PrincipalTypeDAO.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PrincipalTypeDAO.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PrincipalTypeDAO.java
index 041ad5c..046345a 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PrincipalTypeDAO.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PrincipalTypeDAO.java
@@ -22,10 +22,11 @@ import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
 import com.google.inject.persist.Transactional;
-import org.apache.ambari.server.orm.entities.PrincipalTypeEntity;
 
+import org.apache.ambari.server.orm.entities.PrincipalTypeEntity;
 import javax.persistence.EntityManager;
 import javax.persistence.TypedQuery;
+
 import java.util.List;
 
 /**
@@ -80,5 +81,31 @@ public class PrincipalTypeDAO {
   public PrincipalTypeEntity merge(PrincipalTypeEntity entity) {
     return entityManagerProvider.get().merge(entity);
   }
+
+  /**
+   * Creates and returns principal type if it wasn't persisted yet.
+   *
+   * @param principalType id of principal type
+   * @return principal type
+   */
+  public PrincipalTypeEntity ensurePrincipalTypeCreated(int principalType) {
+    PrincipalTypeEntity principalTypeEntity = findById(principalType);
+    if (principalTypeEntity == null) {
+      principalTypeEntity = new PrincipalTypeEntity();
+      principalTypeEntity.setId(principalType);
+      switch (principalType) {
+        case PrincipalTypeEntity.USER_PRINCIPAL_TYPE:
+          
principalTypeEntity.setName(PrincipalTypeEntity.USER_PRINCIPAL_TYPE_NAME);
+          break;
+        case PrincipalTypeEntity.GROUP_PRINCIPAL_TYPE:
+          
principalTypeEntity.setName(PrincipalTypeEntity.GROUP_PRINCIPAL_TYPE_NAME);
+          break;
+        default:
+          throw new IllegalArgumentException("Unknown principal type ID=" + 
principalType);
+      }
+      create(principalTypeEntity);
+    }
+    return principalTypeEntity;
+  }
 }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UserDAO.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UserDAO.java 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UserDAO.java
index dcbd64c..06040be 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UserDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UserDAO.java
@@ -17,19 +17,24 @@
  */
 package org.apache.ambari.server.orm.dao;
 
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import com.google.inject.Singleton;
-import com.google.inject.persist.Transactional;
-import org.apache.ambari.server.orm.RequiresSession;
-import org.apache.ambari.server.orm.entities.PrincipalEntity;
-import org.apache.ambari.server.orm.entities.UserEntity;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 
 import javax.persistence.EntityManager;
 import javax.persistence.NoResultException;
 import javax.persistence.TypedQuery;
-import java.util.Collections;
-import java.util.List;
+
+import org.apache.ambari.server.orm.RequiresSession;
+import org.apache.ambari.server.orm.entities.PrincipalEntity;
+import org.apache.ambari.server.orm.entities.UserEntity;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+import com.google.inject.persist.Transactional;
 
 @Singleton
 public class UserDAO {
@@ -90,8 +95,15 @@ public class UserDAO {
 
   @Transactional
   public void create(UserEntity user) {
-    user.setUserName(user.getUserName().toLowerCase());
-    entityManagerProvider.get().persist(user);
+    create(new HashSet<UserEntity>(Arrays.asList(user)));
+  }
+
+  @Transactional
+  public void create(Set<UserEntity> users) {
+    for (UserEntity user: users) {
+      user.setUserName(user.getUserName().toLowerCase());
+      entityManagerProvider.get().persist(user);
+    }
   }
 
   @Transactional
@@ -101,12 +113,27 @@ public class UserDAO {
   }
 
   @Transactional
+  public void merge(Set<UserEntity> users) {
+    for (UserEntity user: users) {
+      user.setUserName(user.getUserName().toLowerCase());
+      entityManagerProvider.get().merge(user);
+    }
+  }
+
+  @Transactional
   public void remove(UserEntity user) {
     entityManagerProvider.get().remove(merge(user));
     
entityManagerProvider.get().getEntityManagerFactory().getCache().evictAll();
   }
 
   @Transactional
+  public void remove(Set<UserEntity> users) {
+    for (UserEntity userEntity: users) {
+      
entityManagerProvider.get().remove(entityManagerProvider.get().merge(userEntity));
+    }
+  }
+
+  @Transactional
   public void removeByPK(Integer userPK) {
     remove(findByPK(userPK));
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/MemberEntity.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/MemberEntity.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/MemberEntity.java
index 5d9e6b1..4e80a08 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/MemberEntity.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/MemberEntity.java
@@ -24,19 +24,24 @@ import javax.persistence.GenerationType;
 import javax.persistence.Id;
 import javax.persistence.JoinColumn;
 import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
 import javax.persistence.Table;
 import javax.persistence.TableGenerator;
 import javax.persistence.UniqueConstraint;
 
 @Entity
 @Table(name = "members", uniqueConstraints = {@UniqueConstraint(columnNames = 
{"group_id", "user_id"})})
+@NamedQueries({
+  @NamedQuery(name = "memberByUserAndGroup", query = "SELECT memberEnt FROM 
MemberEntity memberEnt where lower(memberEnt.user.userName)=:username AND 
lower(memberEnt.group.groupName)=:groupname")
+})
 @TableGenerator(name = "member_id_generator",
     table = "ambari_sequences",
     pkColumnName = "sequence_name",
     valueColumnName = "sequence_value",
     pkColumnValue = "member_id_seq",
     initialValue = 1,
-    allocationSize = 1
+    allocationSize = 500
     )
 public class MemberEntity {
   @Id

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/PrincipalEntity.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/PrincipalEntity.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/PrincipalEntity.java
index d05ff5c..4b826df 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/PrincipalEntity.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/PrincipalEntity.java
@@ -44,7 +44,7 @@ import javax.persistence.TableGenerator;
     table = "ambari_sequences", pkColumnName = "sequence_name", 
valueColumnName = "sequence_value"
     , pkColumnValue = "principal_id_seq"
     , initialValue = 2
-    , allocationSize = 1
+    , allocationSize = 500
 )
 @NamedQueries({
   @NamedQuery(name = "principalByPrivilegeId", query = "SELECT principal FROM 
PrincipalEntity principal JOIN principal.privileges privilege WHERE 
privilege.permission.id=:permission_id")

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UserEntity.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UserEntity.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UserEntity.java
index 4e1f1f3..e551c38 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UserEntity.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UserEntity.java
@@ -20,6 +20,7 @@ package org.apache.ambari.server.orm.entities;
 import javax.persistence.*;
 
 import java.util.Date;
+import java.util.HashSet;
 import java.util.Set;
 
 @Table(name = "users", uniqueConstraints = {@UniqueConstraint(columnNames = 
{"user_name", "ldap_user"})})
@@ -32,7 +33,7 @@ import java.util.Set;
     table = "ambari_sequences", pkColumnName = "sequence_name", 
valueColumnName = "sequence_value"
     , pkColumnValue = "user_id_seq"
     , initialValue = 2
-    , allocationSize = 1
+    , allocationSize = 500
     )
 public class UserEntity {
 
@@ -60,7 +61,7 @@ public class UserEntity {
   private Integer active = 1;
 
   @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
-  private Set<MemberEntity> memberEntities;
+  private Set<MemberEntity> memberEntities = new HashSet<MemberEntity>();
 
   @OneToOne
   @JoinColumns({

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapDataPopulator.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapDataPopulator.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapDataPopulator.java
deleted file mode 100644
index a160716..0000000
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapDataPopulator.java
+++ /dev/null
@@ -1,409 +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.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import javax.naming.NamingException;
-import javax.naming.directory.Attributes;
-
-import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.configuration.Configuration;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.ldap.core.AttributesMapper;
-import org.springframework.ldap.core.ContextMapper;
-import org.springframework.ldap.core.DirContextAdapter;
-import org.springframework.ldap.core.LdapTemplate;
-import org.springframework.ldap.core.support.LdapContextSource;
-import org.springframework.ldap.filter.AndFilter;
-import org.springframework.ldap.filter.EqualsFilter;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
-
-import com.google.inject.Inject;
-
-/**
- * Provides users, groups and membership population from LDAP catalog.
- */
-public class AmbariLdapDataPopulator {
-  /**
-   * Log.
-   */
-  private static final Log LOG = 
LogFactory.getLog(AmbariLdapDataPopulator.class);
-
-  /**
-   * Ambari configuration.
-   */
-  private Configuration configuration;
-
-  /**
-   * Highlevel facade for management of users and groups.
-   */
-  private Users users;
-
-  /**
-   * LDAP specific properties.
-   */
-  protected LdapServerProperties ldapServerProperties;
-
-  /**
-   * LDAP template for making search queries.
-   */
-  private LdapTemplate ldapTemplate;
-
-  @Inject
-  public AmbariLdapDataPopulator(Configuration configuration, Users users) {
-    this.configuration = configuration;
-    this.users = users;
-  }
-
-  /**
-   * Check if LDAP is enabled in server properties.
-   *
-   * @return true if enabled
-   */
-  public boolean isLdapEnabled() {
-    if (!configuration.isLdapConfigured()) {
-      return false;
-    }
-    try {
-      final LdapTemplate ldapTemplate = loadLdapTemplate();
-      ldapTemplate.list(ldapServerProperties.getBaseDN());
-      return true;
-    } catch (Exception ex) {
-      LOG.error("Could not connect to LDAP server - " + ex.getMessage());
-      return false;
-    }
-  }
-
-  /**
-   * Retrieves a key-value map of all LDAP groups.
-   *
-   * @return map of GroupName-Synced pairs
-   */
-  public Map<String, Boolean> getLdapGroupsSyncInfo() {
-    final Map<String, Boolean> ldapGroups = new HashMap<String, Boolean>();
-    final Map<String, Group> internalGroupsMap = getInternalGroups();
-    final Set<String> externalGroups = getExternalLdapGroupNames();
-    for (String externalGroup : externalGroups) {
-      if (internalGroupsMap.containsKey(externalGroup)
-          && internalGroupsMap.get(externalGroup).isLdapGroup()) {
-        ldapGroups.put(externalGroup, true);
-      } else {
-        ldapGroups.put(externalGroup, false);
-      }
-    }
-
-    return ldapGroups;
-  }
-
-  /**
-   * Retrieves a key-value map of all LDAP users.
-   *
-   * @return map of UserName-Synced pairs.
-   */
-  public Map<String, Boolean> getLdapUsersSyncInfo() {
-    final Map<String, Boolean> ldapUsers = new HashMap<String, Boolean>();
-    final List<User> internalUsers = users.getAllUsers();
-    final Map<String, User> internalUsersMap = new HashMap<String, User>();
-    for (User user : internalUsers) {
-      internalUsersMap.put(user.getUserName(), user);
-    }
-    final Set<String> externalUsers = getExternalLdapUserNames();
-    for (String externalUser : externalUsers) {
-      if (internalUsersMap.containsKey(externalUser)
-          && internalUsersMap.get(externalUser).isLdapUser()) {
-        ldapUsers.put(externalUser, true);
-      } else {
-        ldapUsers.put(externalUser, false);
-      }
-    }
-
-    return ldapUsers;
-  }
-
-  /**
-   * Performs synchronization of given sets of usernames and groupnames.
-   *
-   * @param users set of users to synchronize
-   * @param groups set of groups to synchronize
-   * @throws AmbariException if synchronization failed for any reason
-   */
-  public void synchronizeLdapUsersAndGroups(Set<String> users,
-      Set<String> groups) throws AmbariException {
-    // validate request
-    final Set<String> externalUsers = getExternalLdapUserNames();
-    for (String user : users) {
-      if (!externalUsers.contains(user)) {
-        throw new AmbariException("Couldn't sync LDAP user " + user
-            + ", it doesn't exist");
-      }
-    }
-    final Set<String> externalGroups = getExternalLdapGroupNames();
-    for (String group : groups) {
-      if (!externalGroups.contains(group)) {
-        throw new AmbariException("Couldn't sync LDAP group " + group
-            + ", it doesn't exist");
-      }
-    }
-
-    // processing groups
-    final Map<String, Group> internalGroupsMap = getInternalGroups();
-    for (String groupName : groups) {
-      if (internalGroupsMap.containsKey(groupName)) {
-        final Group group = internalGroupsMap.get(groupName);
-        if (!group.isLdapGroup()) {
-          this.users.setGroupLdap(groupName);
-        }
-      } else {
-        this.users.createGroup(groupName);
-        this.users.setGroupLdap(groupName);
-      }
-      refreshGroupMembers(groupName);
-      internalGroupsMap.remove(groupName);
-    }
-    for (Entry<String, Group> internalGroup : internalGroupsMap.entrySet()) {
-      if (internalGroup.getValue().isLdapGroup()) {
-        this.users.removeGroup(internalGroup.getValue());
-      }
-    }
-
-    cleanUpLdapUsersWithoutGroup();
-
-    // processing users
-    final Map<String, User> internalUsersMap = getInternalUsers();
-    for (String userName : users) {
-      if (internalUsersMap.containsKey(userName)) {
-        final User user = internalUsersMap.get(userName);
-        if (!user.isLdapUser()) {
-          this.users.setUserLdap(userName);
-        }
-      } else {
-        this.users.createUser(userName, "", true, false);
-        this.users.setUserLdap(userName);
-      }
-    }
-
-  }
-
-  /**
-   * Check group members of the synced group: add missing ones and remove the 
ones absent in external LDAP.
-   *
-   * @param groupName group name
-   * @throws AmbariException if group refresh failed
-   */
-  protected void refreshGroupMembers(String groupName) throws AmbariException {
-    final Set<String> externalMembers = getExternalLdapGroupMembers(groupName);
-    final Map<String, User> internalUsers = getInternalUsers();
-    final Map<String, User> internalMembers = getInternalMembers(groupName);
-    for (String externalMember: externalMembers) {
-      if (internalUsers.containsKey(externalMember)) {
-        final User user = internalUsers.get(externalMember);
-        if (!user.isLdapUser()) {
-          users.setUserLdap(externalMember);
-        }
-        if (!internalMembers.containsKey(externalMember)) {
-          users.addMemberToGroup(groupName, externalMember);
-        }
-        internalMembers.remove(externalMember);
-        internalUsers.remove(externalMember);
-      } else {
-        users.createUser(externalMember, "");
-        users.setUserLdap(externalMember);
-        users.addMemberToGroup(groupName, externalMember);
-      }
-    }
-    for (Entry<String, User> userToBeUnsynced: internalMembers.entrySet()) {
-      final User user = userToBeUnsynced.getValue();
-      users.removeMemberFromGroup(groupName, user.getUserName());
-    }
-  }
-
-  /**
-   * Removes synced users which are not present in any of group.
-   *
-   * @throws AmbariException
-   */
-  protected void cleanUpLdapUsersWithoutGroup() throws AmbariException {
-    final List<User> allUsers = users.getAllUsers();
-    for (User user: allUsers) {
-      if (user.isLdapUser() && user.getGroups().isEmpty()) {
-        users.removeUser(user);
-      }
-    }
-  }
-
-  // Utility methods
-
-  /**
-   * Retrieves groups from external LDAP server.
-   *
-   * @return set of user names
-   */
-  protected Set<String> getExternalLdapGroupNames() {
-    final Set<String> groups = new HashSet<String>();
-    final LdapTemplate ldapTemplate = loadLdapTemplate();
-    final EqualsFilter equalsFilter = new EqualsFilter("objectClass",
-        ldapServerProperties.getGroupObjectClass());
-    String baseDn = ldapServerProperties.getBaseDN();
-    ldapTemplate.search(baseDn, equalsFilter.encode(), new AttributesMapper() {
-
-      public Object mapFromAttributes(Attributes attributes)
-          throws NamingException {
-        groups.add(attributes.get(ldapServerProperties.getGroupNamingAttr())
-            .get().toString().toLowerCase());
-        return null;
-      }
-    });
-    return groups;
-  }
-
-  /**
-   * Retrieves users from external LDAP server.
-   *
-   * @return set of user names
-   */
-  protected Set<String> getExternalLdapUserNames() {
-    final Set<String> users = new HashSet<String>();
-    final LdapTemplate ldapTemplate = loadLdapTemplate();
-    final EqualsFilter equalsFilter = new EqualsFilter("objectClass",
-        ldapServerProperties.getUserObjectClass());
-    String baseDn = ldapServerProperties.getBaseDN();
-    ldapTemplate.search(baseDn, equalsFilter.encode(), new AttributesMapper() {
-
-      public Object mapFromAttributes(Attributes attributes)
-          throws NamingException {
-        users.add(attributes.get(ldapServerProperties.getUsernameAttribute())
-            .get().toString().toLowerCase());
-        return null;
-      }
-    });
-    return users;
-  }
-
-  /**
-   * Retrieves members of the specified group from external LDAP server.
-   *
-   * @param groupName group name
-   * @return set of group names
-   */
-  protected Set<String> getExternalLdapGroupMembers(String groupName) {
-    final Set<String> members = new HashSet<String>();
-    final LdapTemplate ldapTemplate = loadLdapTemplate();
-    final AndFilter andFilter = new AndFilter();
-    andFilter.and(new EqualsFilter("objectClass", 
ldapServerProperties.getGroupObjectClass()));
-    andFilter.and(new EqualsFilter(ldapServerProperties.getGroupNamingAttr(), 
groupName));
-    String baseDn = ldapServerProperties.getBaseDN();
-    ldapTemplate.search(baseDn, andFilter.encode(), new ContextMapper() {
-
-      public Object mapFromContext(Object ctx) {
-        final DirContextAdapter adapter  = (DirContextAdapter) ctx;
-        for (String uniqueMember: 
adapter.getStringAttributes(ldapServerProperties.getGroupMembershipAttr())) {
-          final DirContextAdapter userAdapter = (DirContextAdapter) 
ldapTemplate.lookup(uniqueMember);
-          
members.add(userAdapter.getStringAttribute(ldapServerProperties.getUsernameAttribute()).toLowerCase());
-        }
-        return null;
-      }
-    });
-    return members;
-  }
-
-  /**
-   * Creates a map of internal groups.
-   *
-   * @return map of GroupName-Group pairs
-   */
-  protected Map<String, Group> getInternalGroups() {
-    final List<Group> internalGroups = users.getAllGroups();
-    final Map<String, Group> internalGroupsMap = new HashMap<String, Group>();
-    for (Group group : internalGroups) {
-      internalGroupsMap.put(group.getGroupName(), group);
-    }
-    return internalGroupsMap;
-  }
-
-  /**
-   * Creates a map of internal users.
-   *
-   * @return map of UserName-User pairs
-   */
-  protected Map<String, User> getInternalUsers() {
-    final List<User> internalUsers = users.getAllUsers();
-    final Map<String, User> internalUsersMap = new HashMap<String, User>();
-    for (User user : internalUsers) {
-      internalUsersMap.put(user.getUserName(), user);
-    }
-    return internalUsersMap;
-  }
-
-  /**
-   * Creates a map of internal users present in specified group.
-   *
-   * @param groupName group name
-   * @return map of UserName-User pairs
-   */
-  protected Map<String, User> getInternalMembers(String groupName) {
-    final Collection<User> internalMembers = users.getGroupMembers(groupName);
-    final Map<String, User> internalMembersMap = new HashMap<String, User>();
-    for (User user : internalMembers) {
-      internalMembersMap.put(user.getUserName(), user);
-    }
-    return internalMembersMap;
-  }
-
-  /**
-   * Checks LDAP configuration for changes and reloads LDAP template if they 
occured.
-   *
-   * @return LdapTemplate instance
-   */
-  protected LdapTemplate loadLdapTemplate() {
-    final LdapServerProperties properties = configuration
-        .getLdapServerProperties();
-    if (ldapTemplate == null || !properties.equals(ldapServerProperties)) {
-      LOG.info("Reloading properties");
-      ldapServerProperties = properties;
-
-      final LdapContextSource ldapContextSource = new LdapContextSource();
-      final List<String> ldapUrls = ldapServerProperties.getLdapUrls();
-      ldapContextSource.setUrls(ldapUrls.toArray(new String[ldapUrls.size()]));
-
-      if (!ldapServerProperties.isAnonymousBind()) {
-        ldapContextSource.setUserDn(ldapServerProperties.getManagerDn());
-        ldapContextSource
-            .setPassword(ldapServerProperties.getManagerPassword());
-      }
-
-      try {
-        ldapContextSource.afterPropertiesSet();
-      } catch (Exception e) {
-        LOG.error("LDAP Context Source not loaded ", e);
-        throw new UsernameNotFoundException("LDAP Context Source not loaded", 
e);
-      }
-
-      ldapTemplate = new LdapTemplate(ldapContextSource);
-    }
-    return ldapTemplate;
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/User.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/User.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/User.java
index db8ad19..e72d958 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/User.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/User.java
@@ -38,7 +38,7 @@ public class User {
   final Collection<String> groups = new ArrayList<String>();
   boolean admin = false;
 
-  User(UserEntity userEntity) {
+  public User(UserEntity userEntity) {
     userId = userEntity.getUserId();
     userName = userEntity.getUserName();
     createTime = userEntity.getCreateTime();

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java
index 4fd5f47..1cd5b95 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java
@@ -19,10 +19,14 @@ package org.apache.ambari.server.security.authorization;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
+import javax.persistence.EntityManager;
+
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.orm.dao.GroupDAO;
@@ -40,6 +44,8 @@ import org.apache.ambari.server.orm.entities.PrincipalEntity;
 import org.apache.ambari.server.orm.entities.PrincipalTypeEntity;
 import org.apache.ambari.server.orm.entities.PrivilegeEntity;
 import org.apache.ambari.server.orm.entities.UserEntity;
+import org.apache.ambari.server.security.ldap.LdapBatchDto;
+import org.apache.ambari.server.security.ldap.LdapUserGroupMemberDto;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.security.authentication.BadCredentialsException;
@@ -49,6 +55,7 @@ import 
org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.crypto.password.PasswordEncoder;
 
 import com.google.inject.Inject;
+import com.google.inject.Provider;
 import com.google.inject.Singleton;
 import com.google.inject.persist.Transactional;
 
@@ -61,6 +68,8 @@ public class Users {
   private final static Logger LOG = LoggerFactory.getLogger(Users.class);
 
   @Inject
+  Provider<EntityManager> entityManagerProvider;
+  @Inject
   protected UserDAO userDAO;
   @Inject
   protected GroupDAO groupDAO;
@@ -227,7 +236,7 @@ public class Users {
    * Creates new local user with provided userName and password.
    */
   public void createUser(String userName, String password) {
-    createUser(userName, password, true, false);
+    createUser(userName, password, true, false, false);
   }
 
   /**
@@ -237,9 +246,10 @@ public class Users {
    * @param password password
    * @param active is user active
    * @param admin is user admin
+   * @param ldapUser is user LDAP
    */
   @Transactional
-  public synchronized void createUser(String userName, String password, 
Boolean active, Boolean admin) {
+  public synchronized void createUser(String userName, String password, 
Boolean active, Boolean admin, Boolean ldapUser) {
 
     // create an admin principal to represent this user
     PrincipalTypeEntity principalTypeEntity = 
principalTypeDAO.findById(PrincipalTypeEntity.USER_PRINCIPAL_TYPE);
@@ -260,6 +270,9 @@ public class Users {
     if (active != null) {
       userEntity.setActive(active);
     }
+    if (ldapUser != null) {
+      userEntity.setLdapUser(ldapUser);
+    }
 
     userDAO.create(userEntity);
 
@@ -510,4 +523,145 @@ public class Users {
     return false;
   }
 
+  /**
+   * Executes batch queries to database to insert large amounts of LDAP data.
+   *
+   * @param batchInfo DTO with batch information
+   */
+  public void processLdapSync(LdapBatchDto batchInfo) {
+    final Map<String, UserEntity> allUsers = new HashMap<String, UserEntity>();
+    final Map<String, GroupEntity> allGroups = new HashMap<String, 
GroupEntity>();
+
+    // prefetch all user and group data to avoid heavy queries in membership 
creation
+
+    for (UserEntity userEntity: userDAO.findAll()) {
+      allUsers.put(userEntity.getUserName(), userEntity);
+    }
+
+    for (GroupEntity groupEntity: groupDAO.findAll()) {
+      allGroups.put(groupEntity.getGroupName(), groupEntity);
+    }
+
+    final PrincipalTypeEntity userPrincipalType = principalTypeDAO
+        .ensurePrincipalTypeCreated(PrincipalTypeEntity.USER_PRINCIPAL_TYPE);
+    final PrincipalTypeEntity groupPrincipalType = principalTypeDAO
+        .ensurePrincipalTypeCreated(PrincipalTypeEntity.GROUP_PRINCIPAL_TYPE);
+
+    // remove users
+    final Set<UserEntity> usersToRemove = new HashSet<UserEntity>();
+    for (String userName: batchInfo.getUsersToBeRemoved()) {
+      UserEntity userEntity = userDAO.findLocalUserByName(userName);
+      if (userEntity == null) {
+        userEntity = userDAO.findLdapUserByName(userName);
+        if (userEntity == null) {
+          continue;
+        }
+      }
+      allUsers.remove(userEntity.getUserName());
+      usersToRemove.add(userEntity);
+    }
+    userDAO.remove(usersToRemove);
+
+    // remove groups
+    final Set<GroupEntity> groupsToRemove = new HashSet<GroupEntity>();
+    for (String groupName: batchInfo.getGroupsToBeRemoved()) {
+      final GroupEntity groupEntity = groupDAO.findGroupByName(groupName);
+      allGroups.remove(groupEntity.getGroupName());
+      groupsToRemove.add(groupEntity);
+    }
+    groupDAO.remove(groupsToRemove);
+
+    // update users
+    final Set<UserEntity> usersToBecomeLdap = new HashSet<UserEntity>();
+    for (String userName: batchInfo.getUsersToBecomeLdap()) {
+      UserEntity userEntity = userDAO.findLocalUserByName(userName);
+      if (userEntity == null) {
+        userEntity = userDAO.findLdapUserByName(userName);
+        if (userEntity == null) {
+          continue;
+        }
+      }
+      userEntity.setLdapUser(true);
+      allUsers.put(userEntity.getUserName(), userEntity);
+      usersToBecomeLdap.add(userEntity);
+    }
+    userDAO.merge(usersToBecomeLdap);
+
+    // update groups
+    final Set<GroupEntity> groupsToBecomeLdap = new HashSet<GroupEntity>();
+    for (String groupName: batchInfo.getGroupsToBecomeLdap()) {
+      final GroupEntity groupEntity = groupDAO.findGroupByName(groupName);
+      groupEntity.setLdapGroup(true);
+      allGroups.put(groupEntity.getGroupName(), groupEntity);
+      groupsToBecomeLdap.add(groupEntity);
+    }
+    groupDAO.merge(groupsToBecomeLdap);
+
+    // prepare create principals
+    final List<PrincipalEntity> principalsToCreate = new 
ArrayList<PrincipalEntity>();
+
+    // prepare create users
+    final Set<UserEntity> usersToCreate = new HashSet<UserEntity>();
+    for (String userName: batchInfo.getUsersToBeCreated()) {
+      final PrincipalEntity principalEntity = new PrincipalEntity();
+      principalEntity.setPrincipalType(userPrincipalType);
+      principalsToCreate.add(principalEntity);
+
+      final UserEntity userEntity = new UserEntity();
+      userEntity.setUserName(userName);
+      userEntity.setUserPassword("");
+      userEntity.setPrincipal(principalEntity);
+      userEntity.setLdapUser(true);
+
+      allUsers.put(userEntity.getUserName(), userEntity);
+      usersToCreate.add(userEntity);
+    }
+
+    // prepare create groups
+    final Set<GroupEntity> groupsToCreate = new HashSet<GroupEntity>();
+    for (String groupName: batchInfo.getGroupsToBeCreated()) {
+      final PrincipalEntity principalEntity = new PrincipalEntity();
+      principalEntity.setPrincipalType(groupPrincipalType);
+      principalsToCreate.add(principalEntity);
+
+      final GroupEntity groupEntity = new GroupEntity();
+      groupEntity.setGroupName(groupName);
+      groupEntity.setPrincipal(principalEntity);
+      groupEntity.setLdapGroup(true);
+
+      allGroups.put(groupEntity.getGroupName(), groupEntity);
+      groupsToCreate.add(groupEntity);
+    }
+
+    // create users and groups
+    principalDAO.create(principalsToCreate);
+    userDAO.create(usersToCreate);
+    groupDAO.create(groupsToCreate);
+
+    // remove membership
+    final Set<MemberEntity> membersToRemove = new HashSet<MemberEntity>();
+    for (LdapUserGroupMemberDto member: batchInfo.getMembershipToRemove()) {
+      membersToRemove.add(memberDAO.findByUserAndGroup(member.getUserName(), 
member.getGroupName()));
+    }
+    memberDAO.remove(membersToRemove);
+
+    // create membership
+    final Set<MemberEntity> membersToCreate = new HashSet<MemberEntity>();
+    final Set<GroupEntity> groupsToUpdate = new HashSet<GroupEntity>();
+    for (LdapUserGroupMemberDto member: batchInfo.getMembershipToAdd()) {
+      final MemberEntity memberEntity = new MemberEntity();
+      final GroupEntity groupEntity = allGroups.get(member.getGroupName());
+      memberEntity.setGroup(groupEntity);
+      memberEntity.setUser(allUsers.get(member.getUserName()));
+      groupEntity.getMemberEntities().add(memberEntity);
+      groupsToUpdate.add(groupEntity);
+      membersToCreate.add(memberEntity);
+    }
+    memberDAO.create(membersToCreate);
+    groupDAO.merge(groupsToUpdate); // needed for Derby DB as it doesn't fetch 
newly added members automatically
+
+    // clear cached entities
+    
entityManagerProvider.get().getEntityManagerFactory().getCache().evictAll();
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulator.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulator.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulator.java
new file mode 100644
index 0000000..2342bd4
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulator.java
@@ -0,0 +1,430 @@
+/**
+ * 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.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import javax.naming.NamingException;
+import javax.naming.directory.Attributes;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.security.authorization.Group;
+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.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.ldap.core.AttributesMapper;
+import org.springframework.ldap.core.ContextMapper;
+import org.springframework.ldap.core.DirContextAdapter;
+import org.springframework.ldap.core.LdapTemplate;
+import org.springframework.ldap.core.support.LdapContextSource;
+import org.springframework.ldap.filter.EqualsFilter;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+
+import com.google.inject.Inject;
+
+/**
+ * Provides users, groups and membership population from LDAP catalog.
+ */
+public class AmbariLdapDataPopulator {
+  /**
+   * Log.
+   */
+  private static final Log LOG = 
LogFactory.getLog(AmbariLdapDataPopulator.class);
+
+  /**
+   * Ambari configuration.
+   */
+  private Configuration configuration;
+
+  /**
+   * Highlevel facade for management of users and groups.
+   */
+  private Users users;
+
+  /**
+   * LDAP specific properties.
+   */
+  protected LdapServerProperties ldapServerProperties;
+
+  /**
+   * LDAP template for making search queries.
+   */
+  private LdapTemplate ldapTemplate;
+
+  @Inject
+  public AmbariLdapDataPopulator(Configuration configuration, Users users) {
+    this.configuration = configuration;
+    this.users = users;
+  }
+
+  /**
+   * Check if LDAP is enabled in server properties.
+   *
+   * @return true if enabled
+   */
+  public boolean isLdapEnabled() {
+    if (!configuration.isLdapConfigured()) {
+      return false;
+    }
+    try {
+      final LdapTemplate ldapTemplate = loadLdapTemplate();
+      ldapTemplate.search(ldapServerProperties.getBaseDN(), 
"uid=dummy_search", new AttributesMapper() {
+
+        @Override
+        public Object mapFromAttributes(Attributes arg0) throws 
NamingException {
+          return null;
+        }
+      });
+      return true;
+    } catch (Exception ex) {
+      LOG.error("Could not connect to LDAP server - " + ex.getMessage());
+      return false;
+    }
+  }
+
+  /**
+   * Retrieves information about external groups and users and their 
synced/unsynced state.
+   *
+   * @return dto with information
+   */
+  public LdapSyncDto getLdapSyncInfo() {
+    final LdapSyncDto syncInfo = new LdapSyncDto();
+
+    final Map<String, Group> internalGroupsMap = getInternalGroups();
+    final Set<LdapGroupDto> externalGroups = getExternalLdapGroupInfo();
+    for (LdapGroupDto externalGroup : externalGroups) {
+      if (internalGroupsMap.containsKey(externalGroup.getGroupName())
+          && 
internalGroupsMap.get(externalGroup.getGroupName()).isLdapGroup()) {
+        externalGroup.setSynced(true);
+      } else {
+        externalGroup.setSynced(false);
+      }
+    }
+
+    final Map<String, User> internalUsersMap = getInternalUsers();
+    final Set<LdapUserDto> externalUsers = getExternalLdapUserInfo();
+    for (LdapUserDto externalUser : externalUsers) {
+      if (internalUsersMap.containsKey(externalUser)
+          && internalUsersMap.get(externalUser).isLdapUser()) {
+        externalUser.setSynced(true);
+      } else {
+        externalUser.setSynced(false);
+      }
+    }
+
+    syncInfo.setGroups(externalGroups);
+    syncInfo.setUsers(externalUsers);
+    return syncInfo;
+  }
+
+  /**
+   * Performs synchronization of given sets of usernames and groupnames.
+   *
+   * @param users set of users to synchronize
+   * @param groups set of groups to synchronize
+   * @throws AmbariException if synchronization failed for any reason
+   */
+  public LdapBatchDto synchronizeLdapUsersAndGroups(Set<String> users,
+      Set<String> groups) throws AmbariException {
+    final LdapBatchDto batchInfo = new LdapBatchDto();
+
+    // validate request
+    final Set<LdapUserDto> externalUsers = getExternalLdapUserInfo();
+    final Map<String, LdapUserDto> externalUsersMap = new HashMap<String, 
LdapUserDto>();
+    for (LdapUserDto user: externalUsers) {
+      externalUsersMap.put(user.getUserName(), user);
+    }
+    for (String user : users) {
+      if (!externalUsersMap.containsKey(user)) {
+        throw new AmbariException("Couldn't sync LDAP user " + user
+            + ", it doesn't exist");
+      }
+    }
+    final Set<LdapGroupDto> externalGroups = getExternalLdapGroupInfo();
+    final Map<String, LdapGroupDto> externalGroupsMap = new HashMap<String, 
LdapGroupDto>();
+    for (LdapGroupDto group: externalGroups) {
+      externalGroupsMap.put(group.getGroupName(), group);
+    }
+    for (String group : groups) {
+      if (!externalGroupsMap.containsKey(group)) {
+        throw new AmbariException("Couldn't sync LDAP group " + group
+            + ", it doesn't exist");
+      }
+    }
+
+    final Map<String, Group> internalGroupsMap = getInternalGroups();
+    final Map<String, User> internalUsersMap = getInternalUsers();
+
+    // processing groups
+    for (String groupName : groups) {
+      if (internalGroupsMap.containsKey(groupName)) {
+        final Group group = internalGroupsMap.get(groupName);
+        if (!group.isLdapGroup()) {
+          batchInfo.getGroupsToBecomeLdap().add(groupName);
+        }
+      } else {
+        batchInfo.getGroupsToBeCreated().add(groupName);
+      }
+      refreshGroupMembers(batchInfo, externalGroupsMap.get(groupName), 
internalUsersMap, externalUsers);
+      internalGroupsMap.remove(groupName);
+    }
+    for (Entry<String, Group> internalGroup : internalGroupsMap.entrySet()) {
+      if (internalGroup.getValue().isLdapGroup()) {
+        
batchInfo.getGroupsToBeRemoved().add(internalGroup.getValue().getGroupName());
+      }
+    }
+
+    // processing users
+    for (String userName : users) {
+      if (internalUsersMap.containsKey(userName)) {
+        final User user = internalUsersMap.get(userName);
+        if (user != null && !user.isLdapUser()) {
+          batchInfo.getUsersToBecomeLdap().add(userName);
+        }
+      } else {
+        batchInfo.getUsersToBeCreated().add(userName);
+      }
+    }
+
+    return batchInfo;
+  }
+
+  /**
+   * Check group members of the synced group: add missing ones and remove the 
ones absent in external LDAP.
+   *
+   * @param groupName group name
+   * @param internalUsers map of internal users
+   * @param externalUsers set of external users
+   * @throws AmbariException if group refresh failed
+   */
+  protected void refreshGroupMembers(LdapBatchDto batchInfo, LdapGroupDto 
group, Map<String, User> internalUsers, Set<LdapUserDto> externalUsers) throws 
AmbariException {
+    final Set<String> externalMembers = new HashSet<String>();
+    for (String memberAttribute: group.getMemberAttributes()) {
+      for (LdapUserDto externalUser: externalUsers) {
+        // memberAttribute may be either DN or UID, check both
+        if (externalUser.getDn().equals(memberAttribute) || 
externalUser.getUid().equals(memberAttribute)) {
+          externalMembers.add(externalUser.getUserName());
+          break;
+        }
+      }
+    }
+    final Map<String, User> internalMembers = 
getInternalMembers(group.getGroupName());
+    for (String externalMember: externalMembers) {
+      if (internalUsers.containsKey(externalMember)) {
+        final User user = internalUsers.get(externalMember);
+        if (user == null) {
+          // user is fresh and is already added to batch info
+          if (!internalMembers.containsKey(externalMember)) {
+            batchInfo.getMembershipToAdd().add(new 
LdapUserGroupMemberDto(group.getGroupName(), externalMember));
+          }
+          continue;
+        }
+        if (!user.isLdapUser()) {
+          batchInfo.getUsersToBecomeLdap().add(externalMember);
+        }
+        if (!internalMembers.containsKey(externalMember)) {
+          batchInfo.getMembershipToAdd().add(new 
LdapUserGroupMemberDto(group.getGroupName(), externalMember));
+        }
+        internalMembers.remove(externalMember);
+      } else {
+        batchInfo.getUsersToBeCreated().add(externalMember);
+        batchInfo.getMembershipToAdd().add(new 
LdapUserGroupMemberDto(group.getGroupName(), externalMember));
+        internalUsers.put(externalMember, null);
+      }
+    }
+    for (Entry<String, User> userToBeUnsynced: internalMembers.entrySet()) {
+      final User user = userToBeUnsynced.getValue();
+      batchInfo.getMembershipToRemove().add(new 
LdapUserGroupMemberDto(group.getGroupName(), user.getUserName()));
+    }
+  }
+
+  /**
+   * Removes synced users which are not present in any of group.
+   *
+   * @throws AmbariException
+   */
+  protected void cleanUpLdapUsersWithoutGroup() throws AmbariException {
+    final List<User> allUsers = users.getAllUsers();
+    for (User user: allUsers) {
+      if (user.isLdapUser() && user.getGroups().isEmpty()) {
+        users.removeUser(user);
+      }
+    }
+  }
+
+  // Utility methods
+
+  /**
+   * Retrieves groups from external LDAP server.
+   *
+   * @return set of info about LDAP groups
+   */
+  protected Set<LdapGroupDto> getExternalLdapGroupInfo() {
+    final Set<LdapGroupDto> groups = new HashSet<LdapGroupDto>();
+    final LdapTemplate ldapTemplate = loadLdapTemplate();
+    final EqualsFilter equalsFilter = new EqualsFilter("objectClass",
+        ldapServerProperties.getGroupObjectClass());
+    String baseDn = ldapServerProperties.getBaseDN();
+    ldapTemplate.search(baseDn, equalsFilter.encode(), new ContextMapper() {
+
+      @Override
+      public Object mapFromContext(Object ctx) {
+        final DirContextAdapter adapter = (DirContextAdapter) ctx;
+
+        final LdapGroupDto group = new LdapGroupDto();
+        final String groupNameAttribute = 
adapter.getStringAttribute(ldapServerProperties.getGroupNamingAttr());
+        group.setGroupName(groupNameAttribute.toLowerCase());
+
+        final String[] uniqueMembers = 
adapter.getStringAttributes(ldapServerProperties.getGroupMembershipAttr());
+        if (uniqueMembers != null) {
+          for (String uniqueMember: uniqueMembers) {
+            group.getMemberAttributes().add(uniqueMember.toLowerCase());
+          }
+        }
+
+        groups.add(group);
+        return null;
+      }
+    });
+    return groups;
+  }
+
+  /**
+   * Retrieves users from external LDAP server.
+   *
+   * @return set of info about LDAP users
+   */
+  protected Set<LdapUserDto> getExternalLdapUserInfo() {
+    final Set<LdapUserDto> users = new HashSet<LdapUserDto>();
+    final LdapTemplate ldapTemplate = loadLdapTemplate();
+    final EqualsFilter equalsFilter = new EqualsFilter("objectClass",
+        ldapServerProperties.getUserObjectClass());
+    String baseDn = ldapServerProperties.getBaseDN();
+    ldapTemplate.search(baseDn, equalsFilter.encode(), new ContextMapper() {
+
+      @Override
+      public Object mapFromContext(Object ctx) {
+        final LdapUserDto user = new LdapUserDto();
+        final DirContextAdapter adapter  = (DirContextAdapter) ctx;
+        final String usernameAttribute = 
adapter.getStringAttribute(ldapServerProperties.getUsernameAttribute());
+        final String uidAttribute = adapter.getStringAttribute("uid");
+        if (usernameAttribute != null && uidAttribute != null) {
+          user.setUserName(usernameAttribute.toLowerCase());
+          user.setUid(uidAttribute.toLowerCase());
+          user.setDn(adapter.getNameInNamespace().toLowerCase());
+        } else {
+          LOG.warn("Ignoring LDAP user " + adapter.getNameInNamespace() + " as 
it doesn't have required" +
+              " attributes uid and " + 
ldapServerProperties.getUsernameAttribute());
+        }
+        users.add(user);
+        return null;
+      }
+    });
+    return users;
+  }
+
+  /**
+   * Creates a map of internal groups.
+   *
+   * @return map of GroupName-Group pairs
+   */
+  protected Map<String, Group> getInternalGroups() {
+    final List<Group> internalGroups = users.getAllGroups();
+    final Map<String, Group> internalGroupsMap = new HashMap<String, Group>();
+    for (Group group : internalGroups) {
+      internalGroupsMap.put(group.getGroupName(), group);
+    }
+    return internalGroupsMap;
+  }
+
+  /**
+   * Creates a map of internal users.
+   *
+   * @return map of UserName-User pairs
+   */
+  protected Map<String, User> getInternalUsers() {
+    final List<User> internalUsers = users.getAllUsers();
+    final Map<String, User> internalUsersMap = new HashMap<String, User>();
+    for (User user : internalUsers) {
+      internalUsersMap.put(user.getUserName(), user);
+    }
+    return internalUsersMap;
+  }
+
+  /**
+   * Creates a map of internal users present in specified group.
+   *
+   * @param groupName group name
+   * @return map of UserName-User pairs
+   */
+  protected Map<String, User> getInternalMembers(String groupName) {
+    final Collection<User> internalMembers = users.getGroupMembers(groupName);
+    if (internalMembers == null) {
+      return Collections.emptyMap();
+    }
+    final Map<String, User> internalMembersMap = new HashMap<String, User>();
+    for (User user : internalMembers) {
+      internalMembersMap.put(user.getUserName(), user);
+    }
+    return internalMembersMap;
+  }
+
+  /**
+   * Checks LDAP configuration for changes and reloads LDAP template if they 
occurred.
+   *
+   * @return LdapTemplate instance
+   */
+  protected LdapTemplate loadLdapTemplate() {
+    final LdapServerProperties properties = configuration
+        .getLdapServerProperties();
+    if (ldapTemplate == null || !properties.equals(ldapServerProperties)) {
+      LOG.info("Reloading properties");
+      ldapServerProperties = properties;
+
+      final LdapContextSource ldapContextSource = new LdapContextSource();
+      final List<String> ldapUrls = ldapServerProperties.getLdapUrls();
+      ldapContextSource.setUrls(ldapUrls.toArray(new String[ldapUrls.size()]));
+
+      if (!ldapServerProperties.isAnonymousBind()) {
+        ldapContextSource.setUserDn(ldapServerProperties.getManagerDn());
+        
ldapContextSource.setPassword(ldapServerProperties.getManagerPassword());
+      }
+
+      try {
+        ldapContextSource.afterPropertiesSet();
+      } catch (Exception e) {
+        LOG.error("LDAP Context Source not loaded ", e);
+        throw new UsernameNotFoundException("LDAP Context Source not loaded", 
e);
+      }
+
+      ldapTemplate = new LdapTemplate(ldapContextSource);
+    }
+    return ldapTemplate;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/LdapBatchDto.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/LdapBatchDto.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/LdapBatchDto.java
new file mode 100644
index 0000000..9247f38
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/LdapBatchDto.java
@@ -0,0 +1,67 @@
+/**
+ * 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;
+
+/**
+ * Contains information for batch database update on LDAP synchronization.
+ */
+public class LdapBatchDto {
+  private final Set<String> groupsToBecomeLdap = new HashSet<String>();
+  private final Set<String> groupsToBeCreated = new HashSet<String>();
+  private final Set<String> groupsToBeRemoved = new HashSet<String>();
+  private final Set<String> usersToBecomeLdap = new HashSet<String>();
+  private final Set<String> usersToBeCreated = new HashSet<String>();
+  private final Set<String> usersToBeRemoved = new HashSet<String>();
+  private final Set<LdapUserGroupMemberDto> membershipToAdd = new 
HashSet<LdapUserGroupMemberDto>();
+  private final Set<LdapUserGroupMemberDto> membershipToRemove = new 
HashSet<LdapUserGroupMemberDto>();
+
+  public Set<String> getGroupsToBecomeLdap() {
+    return groupsToBecomeLdap;
+  }
+
+  public Set<String> getGroupsToBeCreated() {
+    return groupsToBeCreated;
+  }
+
+  public Set<String> getUsersToBecomeLdap() {
+    return usersToBecomeLdap;
+  }
+
+  public Set<String> getUsersToBeCreated() {
+    return usersToBeCreated;
+  }
+
+  public Set<LdapUserGroupMemberDto> getMembershipToAdd() {
+    return membershipToAdd;
+  }
+
+  public Set<LdapUserGroupMemberDto> getMembershipToRemove() {
+    return membershipToRemove;
+  }
+
+  public Set<String> getGroupsToBeRemoved() {
+    return groupsToBeRemoved;
+  }
+
+  public Set<String> getUsersToBeRemoved() {
+    return usersToBeRemoved;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/LdapGroupDto.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/LdapGroupDto.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/LdapGroupDto.java
new file mode 100644
index 0000000..132cbe5
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/LdapGroupDto.java
@@ -0,0 +1,113 @@
+/**
+ * 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;
+
+/**
+ * Pojo with information about LDAP group of users.
+ */
+public class LdapGroupDto {
+  /**
+   * Name of the group.
+   */
+  private String groupName;
+
+  /**
+   * Set of member attributes. Usually it's either UID or DN of users.
+   */
+  private Set<String> memberAttributes = new HashSet<String>();
+
+  /**
+   * Determines if the LDAP group is synchronized with internal group in 
database.
+   */
+  private boolean synced;
+
+  /**
+   * Get the group name.
+   *
+   * @return the group name
+   */
+  public String getGroupName() {
+    return groupName;
+  }
+
+  /**
+   * Set the group name.
+   *
+   * @param groupName the group name
+   */
+  public void setGroupName(String groupName) {
+    this.groupName = groupName;
+  }
+
+  /**
+   * Get the member attributes.
+   *
+   * @return the set of member attributes
+   */
+  public Set<String> getMemberAttributes() {
+    return memberAttributes;
+  }
+
+  /**
+   * Set the member attributes.
+   *
+   * @param memberAttributes the member attributes
+   */
+  public void setMemberAttributes(Set<String> memberAttributes) {
+    this.memberAttributes = memberAttributes;
+  }
+
+  /**
+   * Get the synced flag.
+   *
+   * @return the synced flag
+   */
+  public boolean isSynced() {
+    return synced;
+  }
+
+  /**
+   * Set the synced flag
+   *
+   * @param synced the synced flag
+   */
+  public void setSynced(boolean synced) {
+    this.synced = synced;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = groupName != null ? groupName.hashCode() : 0;
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    LdapGroupDto that = (LdapGroupDto) o;
+
+    if (groupName != null ? !groupName.equals(that.getGroupName()) : 
that.getGroupName() != null) return false;
+
+    return true;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/LdapSyncDto.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/LdapSyncDto.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/LdapSyncDto.java
new file mode 100644
index 0000000..6bd2ab9
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/LdapSyncDto.java
@@ -0,0 +1,72 @@
+/**
+ * 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;
+
+/**
+ * Pojo with information about LDAP groups and users.
+ */
+public class LdapSyncDto {
+  /**
+   * LDAP groups.
+   */
+  private Set<LdapGroupDto> groups = new HashSet<LdapGroupDto>();
+
+  /**
+   * LDAP users.
+   */
+  private Set<LdapUserDto> users = new HashSet<LdapUserDto>();
+
+  /**
+   * Get the LDAP groups.
+   *
+   * @return the LDAP groups
+   */
+  public Set<LdapGroupDto> getGroups() {
+    return groups;
+  }
+
+  /**
+   * Set the LDAP groups.
+   *
+   * @param groups the LDAP groups
+   */
+  public void setGroups(Set<LdapGroupDto> groups) {
+    this.groups = groups;
+  }
+
+  /**
+   * Get the LDAP users.
+   *
+   * @return the LDAP users
+   */
+  public Set<LdapUserDto> getUsers() {
+    return users;
+  }
+
+  /**
+   * Set the LDAP users.
+   *
+   * @param users the LDAP users
+   */
+  public void setUsers(Set<LdapUserDto> users) {
+    this.users = users;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b48bf4/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/LdapUserDto.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/LdapUserDto.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/LdapUserDto.java
new file mode 100644
index 0000000..dbb13bf
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/LdapUserDto.java
@@ -0,0 +1,133 @@
+/**
+ * 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 user.
+ */
+public class LdapUserDto {
+  /**
+   * Name of the user. Should be always unique.
+   */
+  private String userName;
+
+  /**
+   * Determines if the LDAP user is synchronized with internal user in 
database.
+   */
+  private boolean synced;
+
+  /**
+   * Unique identifier from LDAP.
+   */
+  private String uid;
+
+  /**
+   * Distinguished name from LDAP.
+   */
+  private String dn;
+
+  /**
+   * Get the user name.
+   *
+   * @return the user name
+   */
+  public String getUserName() {
+    return userName;
+  }
+
+  /**
+   * Set the user name.
+   *
+   * @param userName the user name
+   */
+  public void setUserName(String userName) {
+    this.userName = userName;
+  }
+
+  /**
+   * Get the synced flag.
+   *
+   * @return the synced flag
+   */
+  public boolean isSynced() {
+    return synced;
+  }
+
+  /**
+   * Set the synced flag
+   *
+   * @param synced the synced flag
+   */
+  public void setSynced(boolean synced) {
+    this.synced = synced;
+  }
+
+  /**
+   * Get the UID.
+   *
+   * @return the UID
+   */
+  public String getUid() {
+    return uid;
+  }
+
+  /**
+   * Set the UID.
+   *
+   * @param uid the UID
+   */
+  public void setUid(String uid) {
+    this.uid = uid;
+  }
+
+  /**
+   * Get the DN.
+   *
+   * @return the DN
+   */
+  public String getDn() {
+    return dn;
+  }
+
+  /**
+   * Set the DN.
+   *
+   * @param dn the DN
+   */
+  public void setDn(String dn) {
+    this.dn = dn;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = userName != null ? userName.hashCode() : 0;
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    LdapUserDto that = (LdapUserDto) o;
+
+    if (userName != null ? !userName.equals(that.getUserName()) : 
that.getUserName() != null) return false;
+
+    return true;
+  }
+}

Reply via email to