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; + } +}