Repository: ambari
Updated Branches:
  refs/heads/trunk 6f61de093 -> a6f0fbfb4


AMBARI-15383. Cleanup Ldap Sync Process (oleewere)


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

Branch: refs/heads/trunk
Commit: a6f0fbfb48e27e0199ade5eb4d9cfdfb7d5807c5
Parents: 6f61de0
Author: oleewere <[email protected]>
Authored: Thu Mar 31 19:10:58 2016 +0200
Committer: oleewere <[email protected]>
Committed: Thu Mar 31 19:10:58 2016 +0200

----------------------------------------------------------------------
 .../security/authorization/AmbariLdapUtils.java |  32 ++++
 .../server/security/authorization/Users.java    |   7 +-
 .../security/ldap/AmbariLdapDataPopulator.java  |  73 ++++++---
 .../server/security/AmbariLdapUtilsTest.java    |  64 ++++++++
 .../ldap/AmbariLdapDataPopulatorTest.java       | 156 +++++++++++++++++--
 5 files changed, 300 insertions(+), 32 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/a6f0fbfb/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapUtils.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapUtils.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapUtils.java
index ffebd45..6d20de3 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapUtils.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapUtils.java
@@ -18,6 +18,14 @@
 
 package org.apache.ambari.server.security.authorization;
 
+import com.google.common.base.Preconditions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.ldap.core.DirContextAdapter;
+import org.springframework.ldap.core.DistinguishedName;
+import org.springframework.security.ldap.LdapUtils;
+
+import javax.naming.Name;
 import java.util.regex.Pattern;
 
 /**
@@ -25,6 +33,8 @@ import java.util.regex.Pattern;
  */
 public class AmbariLdapUtils {
 
+  private static final Logger LOG = 
LoggerFactory.getLogger(AmbariLdapUtils.class);
+
   /**
    * Regexp to verify if user login name beside user contains domain 
information as well (User principal name format).
    */
@@ -40,4 +50,26 @@ public class AmbariLdapUtils {
   }
 
 
+  /**
+   * Determine that the full DN of an LDAP object is in/out of the base DN 
scope.
+   * @param adapter used for get the full dn from the ldap query response
+   * @param baseDn
+   * @return
+   */
+  public static boolean isLdapObjectOutOfScopeFromBaseDn(DirContextAdapter 
adapter, String baseDn) {
+    boolean isOutOfScope = true;
+    try {
+      Name dn = adapter.getDn();
+      Preconditions.checkArgument(dn != null, "DN cannot be null in LDAP 
response object");
+
+      DistinguishedName full = LdapUtils.getFullDn((DistinguishedName) dn, 
adapter);
+      DistinguishedName base = new DistinguishedName(baseDn);
+      if (full.startsWith(base)) {
+        isOutOfScope = false;
+      }
+    } catch (Exception e) {
+      LOG.error(e.getMessage());
+    }
+    return isOutOfScope;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/a6f0fbfb/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 c2bc22f..d80edf3 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
@@ -360,7 +360,12 @@ public class Users {
     } else {
       final Set<User> users = new HashSet<User>();
       for (MemberEntity memberEntity: groupEntity.getMemberEntities()) {
-        users.add(new User(memberEntity.getUser()));
+        if (memberEntity.getUser() != null) {
+          users.add(new User(memberEntity.getUser()));
+        } else {
+          LOG.error("Wrong state, not found user for member '{}' (group: 
'{}')",
+            memberEntity.getMemberId(), 
memberEntity.getGroup().getGroupName());
+        }
       }
       return users;
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/a6f0fbfb/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
index 75df9cc..9a66456 100644
--- 
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
@@ -25,19 +25,22 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
+import java.util.regex.Pattern;
 
 import javax.naming.NamingException;
 import javax.naming.directory.Attributes;
 import javax.naming.directory.SearchControls;
 
+import com.google.common.collect.Lists;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.security.authorization.AmbariLdapUtils;
 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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.collect.Sets;
 import org.springframework.ldap.control.PagedResultsDirContextProcessor;
@@ -62,7 +65,7 @@ public class AmbariLdapDataPopulator {
   /**
    * Log.
    */
-  private static final Log LOG = 
LogFactory.getLog(AmbariLdapDataPopulator.class);
+  private static final Logger LOG = 
LoggerFactory.getLogger(AmbariLdapDataPopulator.class);
 
   /**
    * Ambari configuration.
@@ -84,11 +87,19 @@ public class AmbariLdapDataPopulator {
    */
   private LdapTemplate ldapTemplate;
 
+  /**
+   * List for organizationUnits from the base DN
+   */
+  private List<String> baseOrganizationUnits = Lists.newArrayList();
+
   // Constants
   private static final String UID_ATTRIBUTE          = "uid";
   private static final String OBJECT_CLASS_ATTRIBUTE = "objectClass";
   private static final int USERS_PAGE_SIZE = 500;
 
+  // REGEXP to check member attribute starts with "cn=" or "uid=" - case 
insensitive
+  private static final String IS_MEMBER_DN_REGEXP = "^(?i)(%s|%s)=.*$";
+
   /**
    * Construct an AmbariLdapDataPopulator.
    *
@@ -169,7 +180,7 @@ public class AmbariLdapDataPopulator {
    * @throws AmbariException if synchronization failed for any reason
    */
   public LdapBatchDto synchronizeAllLdapGroups(LdapBatchDto batchInfo) throws 
AmbariException {
-
+    LOG.trace("Synchronize All LDAP groups...");
     Set<LdapGroupDto> externalLdapGroupInfo = getExternalLdapGroupInfo();
 
     final Map<String, Group> internalGroupsMap = getInternalGroups();
@@ -178,7 +189,7 @@ public class AmbariLdapDataPopulator {
     for (LdapGroupDto groupDto : externalLdapGroupInfo) {
       String groupName = groupDto.getGroupName();
       addLdapGroup(batchInfo, internalGroupsMap, groupName);
-      refreshGroupMembers(batchInfo, groupDto, internalUsersMap, 
internalGroupsMap, null);
+      refreshGroupMembers(batchInfo, groupDto, internalUsersMap, 
internalGroupsMap, null, false);
     }
     for (Entry<String, Group> internalGroup : internalGroupsMap.entrySet()) {
       if (internalGroup.getValue().isLdapGroup()) {
@@ -195,7 +206,7 @@ public class AmbariLdapDataPopulator {
    * @throws AmbariException if synchronization failed for any reason
    */
   public LdapBatchDto synchronizeAllLdapUsers(LdapBatchDto batchInfo) throws 
AmbariException {
-
+    LOG.trace("Synchronize All LDAP users...");
     Set<LdapUserDto> externalLdapUserInfo = getExternalLdapUserInfo();
     Map<String, User> internalUsersMap = getInternalUsers();
 
@@ -205,6 +216,7 @@ public class AmbariLdapDataPopulator {
         final User user = internalUsersMap.get(userName);
         if (user != null && !user.isLdapUser()) {
           batchInfo.getUsersToBecomeLdap().add(userName);
+          LOG.trace("Convert user '{}' to LDAP user.", userName);
         }
         internalUsersMap.remove(userName);
       } else {
@@ -227,7 +239,7 @@ public class AmbariLdapDataPopulator {
    * @throws AmbariException if synchronization failed for any reason
    */
   public LdapBatchDto synchronizeLdapGroups(Set<String> groups, LdapBatchDto 
batchInfo) throws AmbariException {
-
+    LOG.trace("Synchronize LDAP groups...");
     final Set<LdapGroupDto> specifiedGroups = new HashSet<LdapGroupDto>();
     for (String group : groups) {
       Set<LdapGroupDto> groupDtos = getLdapGroups(group);
@@ -244,7 +256,7 @@ public class AmbariLdapDataPopulator {
     for (LdapGroupDto groupDto : specifiedGroups) {
       String groupName = groupDto.getGroupName();
       addLdapGroup(batchInfo, internalGroupsMap, groupName);
-      refreshGroupMembers(batchInfo, groupDto, internalUsersMap, 
internalGroupsMap, null);
+      refreshGroupMembers(batchInfo, groupDto, internalUsersMap, 
internalGroupsMap, null, true);
     }
 
     return batchInfo;
@@ -257,7 +269,7 @@ public class AmbariLdapDataPopulator {
    * @throws AmbariException if synchronization failed for any reason
    */
   public LdapBatchDto synchronizeLdapUsers(Set<String> users, LdapBatchDto 
batchInfo) throws AmbariException {
-
+    LOG.trace("Synchronize LDAP users...");
     final Set<LdapUserDto> specifiedUsers = new HashSet<LdapUserDto>();
 
     for (String user : users) {
@@ -292,6 +304,7 @@ public class AmbariLdapDataPopulator {
    * @throws AmbariException if synchronization failed for any reason
    */
   public LdapBatchDto synchronizeExistingLdapGroups(LdapBatchDto batchInfo) 
throws AmbariException {
+    LOG.trace("Synchronize Existing LDAP groups...");
     final Map<String, Group> internalGroupsMap = getInternalGroups();
     final Map<String, User> internalUsersMap = getInternalUsers();
 
@@ -304,7 +317,7 @@ public class AmbariLdapDataPopulator {
           batchInfo.getGroupsToBeRemoved().add(group.getGroupName());
         } else {
           LdapGroupDto groupDto = groupDtos.iterator().next();
-          refreshGroupMembers(batchInfo, groupDto, internalUsersMap, 
internalGroupsMap, null);
+          refreshGroupMembers(batchInfo, groupDto, internalUsersMap, 
internalGroupsMap, null, true);
         }
       }
     }
@@ -318,6 +331,7 @@ public class AmbariLdapDataPopulator {
    * @throws AmbariException if synchronization failed for any reason
    */
   public LdapBatchDto synchronizeExistingLdapUsers(LdapBatchDto batchInfo) 
throws AmbariException {
+    LOG.trace("Synchronize Existing LDAP users...");
     final Map<String, User> internalUsersMap = getInternalUsers();
 
     for (User user : internalUsersMap.values()) {
@@ -339,10 +353,11 @@ public class AmbariLdapDataPopulator {
    * @param group ldap group
    * @param internalUsers map of internal users
    * @param groupMemberAttributes  set of group member attributes that have 
already been refreshed
+   * @param recursive if disabled, it won't refresh members recursively (its 
not needed in case of all groups are processed)
    * @throws AmbariException if group refresh failed
    */
   protected void refreshGroupMembers(LdapBatchDto batchInfo, LdapGroupDto 
group, Map<String, User> internalUsers,
-                                     Map<String, Group> internalGroupsMap, 
Set<String> groupMemberAttributes)
+                                     Map<String, Group> internalGroupsMap, 
Set<String> groupMemberAttributes, boolean recursive)
       throws AmbariException {
     Set<String> externalMembers = new HashSet<String>();
 
@@ -356,13 +371,13 @@ public class AmbariLdapDataPopulator {
         externalMembers.add(groupMember.getUserName());
       } else {
         // if we haven't already processed this group
-        if (!groupMemberAttributes.contains(memberAttributeValue)) {
+        if (recursive && 
!groupMemberAttributes.contains(memberAttributeValue)) {
           // if the member is another group then add all of its members
           LdapGroupDto subGroup = 
getLdapGroupByMemberAttr(memberAttributeValue);
           if (subGroup != null) {
             groupMemberAttributes.add(memberAttributeValue);
             addLdapGroup(batchInfo, internalGroupsMap, 
subGroup.getGroupName());
-            refreshGroupMembers(batchInfo, subGroup, internalUsers, 
internalGroupsMap, groupMemberAttributes);
+            refreshGroupMembers(batchInfo, subGroup, internalUsers, 
internalGroupsMap, groupMemberAttributes, true);
           }
         }
       }
@@ -434,9 +449,11 @@ public class AmbariLdapDataPopulator {
   protected LdapUserDto getLdapUserByMemberAttr(String memberAttributeValue) {
     Set<LdapUserDto> filteredLdapUsers = new HashSet<LdapUserDto>();
     if (memberAttributeValue!= null && 
isMemberAttributeBaseDn(memberAttributeValue)) {
+      LOG.trace("Member can be used as baseDn: {}", memberAttributeValue);
       Filter filter = new EqualsFilter(OBJECT_CLASS_ATTRIBUTE, 
ldapServerProperties.getUserObjectClass());
       filteredLdapUsers = getFilteredLdapUsers(memberAttributeValue, filter);
     } else {
+      LOG.trace("Member cannot be used as baseDn: {}", memberAttributeValue);
       Filter filter = new AndFilter()
         .and(new EqualsFilter(OBJECT_CLASS_ATTRIBUTE, 
ldapServerProperties.getUserObjectClass()))
         .and(new EqualsFilter(ldapServerProperties.getUsernameAttribute(), 
memberAttributeValue));
@@ -455,9 +472,11 @@ public class AmbariLdapDataPopulator {
   protected LdapGroupDto getLdapGroupByMemberAttr(String memberAttributeValue) 
{
     Set<LdapGroupDto> filteredLdapGroups = new HashSet<LdapGroupDto>();
     if (memberAttributeValue != null && 
isMemberAttributeBaseDn(memberAttributeValue)) {
+      LOG.trace("Member can be used as baseDn: {}", memberAttributeValue);
       Filter filter = new EqualsFilter(OBJECT_CLASS_ATTRIBUTE, 
ldapServerProperties.getGroupObjectClass());
       filteredLdapGroups = getFilteredLdapGroups(memberAttributeValue, filter);
     } else {
+      LOG.trace("Member cannot be used as baseDn: {}", memberAttributeValue);
       filteredLdapGroups = 
getFilteredLdapGroups(ldapServerProperties.getBaseDN(),
         new EqualsFilter(OBJECT_CLASS_ATTRIBUTE, 
ldapServerProperties.getGroupObjectClass()),
         getMemberFilter(memberAttributeValue));
@@ -482,11 +501,12 @@ public class AmbariLdapDataPopulator {
 
   // Utility methods
 
-  private void addLdapGroup(LdapBatchDto batchInfo, Map<String, Group> 
internalGroupsMap, String groupName) {
+  protected void addLdapGroup(LdapBatchDto batchInfo, Map<String, Group> 
internalGroupsMap, String groupName) {
     if (internalGroupsMap.containsKey(groupName)) {
       final Group group = internalGroupsMap.get(groupName);
       if (!group.isLdapGroup()) {
         batchInfo.getGroupsToBecomeLdap().add(groupName);
+        LOG.trace("Convert group '{}' to LDAP group.", groupName);
       }
       internalGroupsMap.remove(groupName);
       batchInfo.getGroupsProcessedInternal().add(groupName);
@@ -500,9 +520,10 @@ public class AmbariLdapDataPopulator {
   /**
    * Determines that the member attribute can be used as a 'dn'
    */
-  private boolean isMemberAttributeBaseDn(String memberAttributeValue) {
-    return 
memberAttributeValue.startsWith(ldapServerProperties.getUsernameAttribute() + 
"=")
-      || 
memberAttributeValue.startsWith(ldapServerProperties.getGroupNamingAttr() + 
"=");
+  protected boolean isMemberAttributeBaseDn(String memberAttributeValue) {
+    Pattern pattern = Pattern.compile(String.format(IS_MEMBER_DN_REGEXP,
+      ldapServerProperties.getUsernameAttribute(), 
ldapServerProperties.getGroupNamingAttr()));
+    return pattern.matcher(memberAttributeValue).find();
   }
 
   /**
@@ -535,7 +556,9 @@ public class AmbariLdapDataPopulator {
   private Set<LdapGroupDto> getFilteredLdapGroups(String baseDn, Filter 
filter) {
     final Set<LdapGroupDto> groups = new HashSet<LdapGroupDto>();
     final LdapTemplate ldapTemplate = loadLdapTemplate();
-    ldapTemplate.search(baseDn, filter.encode(), new 
LdapGroupContextMapper(groups, ldapServerProperties));
+    LOG.trace("LDAP Group Query - Base DN: '{}' ; Filter: '{}'", baseDn, 
filter.encode());
+    ldapTemplate.search(baseDn, filter.encode(),
+      new LdapGroupContextMapper(groups, ldapServerProperties));
     return groups;
   }
 
@@ -572,6 +595,7 @@ public class AmbariLdapDataPopulator {
       List dtos = 
configuration.getLdapServerProperties().isPaginationEnabled() ?
         ldapTemplate.search(baseDn, encodedFilter, searchControls, 
ldapUserContextMapper, processor) :
         ldapTemplate.search(baseDn, encodedFilter, searchControls, 
ldapUserContextMapper);
+      LOG.trace("LDAP User Query - Base DN: '{}' ; Filter: '{}'", baseDn, 
encodedFilter);
       for (Object dto : dtos) {
         if (dto != null) {
           users.add((LdapUserDto)dto);
@@ -604,6 +628,7 @@ public class AmbariLdapDataPopulator {
   protected Map<String, User> getInternalUsers() {
     final List<User> internalUsers = users.getAllUsers();
     final Map<String, User> internalUsersMap = new HashMap<String, User>();
+    LOG.trace("Get all users from Ambari Server.");
     for (User user : internalUsers) {
       internalUsersMap.put(user.getUserName(), user);
     }
@@ -716,6 +741,11 @@ public class AmbariLdapDataPopulator {
     public Object mapFromContext(Object ctx) {
       final DirContextAdapter adapter = (DirContextAdapter) ctx;
       final String groupNameAttribute = 
adapter.getStringAttribute(ldapServerProperties.getGroupNamingAttr());
+      boolean outOfScope = 
AmbariLdapUtils.isLdapObjectOutOfScopeFromBaseDn(adapter, 
ldapServerProperties.getBaseDN());
+      if (outOfScope) {
+        LOG.warn("Group '{}' is out of scope of the base DN. It will be 
skipped.", groupNameAttribute);
+        return null;
+      }
       if (groupNameAttribute != null) {
         final LdapGroupDto group = new LdapGroupDto();
         group.setGroupName(groupNameAttribute.toLowerCase());
@@ -744,6 +774,13 @@ public class AmbariLdapDataPopulator {
       final DirContextAdapter adapter  = (DirContextAdapter) ctx;
       final String usernameAttribute = 
adapter.getStringAttribute(ldapServerProperties.getUsernameAttribute());
       final String uidAttribute = adapter.getStringAttribute(UID_ATTRIBUTE);
+
+      boolean outOfScope = 
AmbariLdapUtils.isLdapObjectOutOfScopeFromBaseDn(adapter, 
ldapServerProperties.getBaseDN());
+      if (outOfScope) {
+        LOG.warn("User '{}' is out of scope of the base DN. It will be 
skipped.", usernameAttribute);
+        return null;
+      }
+
       if (usernameAttribute != null || uidAttribute != null) {
         final LdapUserDto user = new LdapUserDto();
         user.setUserName(usernameAttribute != null ? 
usernameAttribute.toLowerCase() : null);

http://git-wip-us.apache.org/repos/asf/ambari/blob/a6f0fbfb/ambari-server/src/test/java/org/apache/ambari/server/security/AmbariLdapUtilsTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/security/AmbariLdapUtilsTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/security/AmbariLdapUtilsTest.java
index b2778ae..5bcdf48 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/security/AmbariLdapUtilsTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/security/AmbariLdapUtilsTest.java
@@ -19,12 +19,30 @@ package org.apache.ambari.server.security;
 
 import org.apache.ambari.server.security.authorization.AmbariLdapUtils;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.api.easymock.PowerMock;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.springframework.ldap.core.DirContextAdapter;
+import org.springframework.ldap.core.DistinguishedName;
+import org.springframework.security.ldap.LdapUtils;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
 
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.createNiceMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
 
+@RunWith(PowerMockRunner.class)
+@PrepareForTest(LdapUtils.class)
 public class AmbariLdapUtilsTest {
 
+  private static final String USER_DN = 
"uid=myuser,ou=hdp,ou=Users,dc=apache,dc=org";
+
   @Test
   public void testIsUserPrincipalNameFormat_True() throws Exception {
     // Given
@@ -84,4 +102,50 @@ public class AmbariLdapUtilsTest {
     // Then
     assertFalse(isUserPrincipalNameFormat);
   }
+
+  @Test
+  public void testIsLdapObjectOutOfScopeFromBaseDn() throws NamingException {
+    // GIVEN
+    DistinguishedName fullDn = new DistinguishedName(USER_DN);
+    Context context = createNiceMock(Context.class);
+    DirContextAdapter adapter = createNiceMock(DirContextAdapter.class);
+
+    PowerMock.mockStatic(LdapUtils.class);
+    expect(LdapUtils.getFullDn(anyObject(DistinguishedName.class), 
anyObject(Context.class)))
+      .andReturn(fullDn).anyTimes();
+
+    expect(adapter.getDn()).andReturn(fullDn);
+    expect(context.getNameInNamespace()).andReturn(USER_DN);
+
+    replay(adapter, context);
+    PowerMock.replayAll();
+
+    // WHEN
+    boolean isOutOfScopeFromBaseDN = 
AmbariLdapUtils.isLdapObjectOutOfScopeFromBaseDn(adapter, "dc=apache,dc=org");
+    // THEN
+    assertFalse(isOutOfScopeFromBaseDN);
+  }
+
+  @Test
+  public void testIsLdapObjectOutOfScopeFromBaseDn_dnOutOfScope() throws 
NamingException {
+    // GIVEN
+    DistinguishedName fullDn = new DistinguishedName(USER_DN);
+    Context context = createNiceMock(Context.class);
+    DirContextAdapter adapter = createNiceMock(DirContextAdapter.class);
+
+    PowerMock.mockStatic(LdapUtils.class);
+    expect(LdapUtils.getFullDn(anyObject(DistinguishedName.class), 
anyObject(Context.class)))
+      .andReturn(fullDn).anyTimes();
+
+    expect(adapter.getDn()).andReturn(fullDn);
+    expect(context.getNameInNamespace()).andReturn(USER_DN);
+
+    replay(adapter, context);
+    PowerMock.replayAll();
+
+    // WHEN
+    boolean isOutOfScopeFromBaseDN = 
AmbariLdapUtils.isLdapObjectOutOfScopeFromBaseDn(adapter, 
"dc=apache,dc=org,ou=custom");
+    // THEN
+    assertTrue(isOutOfScopeFromBaseDN);
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/a6f0fbfb/ambari-server/src/test/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulatorTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulatorTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulatorTest.java
index ffff3ea..eef91c1 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulatorTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulatorTest.java
@@ -36,6 +36,7 @@ import org.apache.ambari.server.orm.entities.MemberEntity;
 import org.apache.ambari.server.orm.entities.PrincipalEntity;
 import org.apache.ambari.server.orm.entities.PrivilegeEntity;
 import org.apache.ambari.server.orm.entities.UserEntity;
+import org.apache.ambari.server.security.authorization.AmbariLdapUtils;
 import org.apache.ambari.server.security.authorization.Group;
 import org.apache.ambari.server.security.authorization.LdapServerProperties;
 import org.apache.ambari.server.security.authorization.User;
@@ -44,6 +45,10 @@ import org.easymock.Capture;
 import org.easymock.EasyMock;
 import org.easymock.IAnswer;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.api.easymock.PowerMock;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
 import org.springframework.ldap.control.PagedResultsCookie;
 import org.springframework.ldap.control.PagedResultsDirContextProcessor;
 import org.springframework.ldap.core.AttributesMapper;
@@ -56,8 +61,11 @@ import javax.naming.directory.SearchControls;
 
 import static junit.framework.Assert.*;
 import static org.easymock.EasyMock.*;
+import static org.easymock.EasyMock.anyBoolean;
 import static org.easymock.EasyMock.createNiceMock;
 
+@RunWith(PowerMockRunner.class)
+@PrepareForTest(AmbariLdapUtils.class)
 public class AmbariLdapDataPopulatorTest {
   public static class AmbariLdapDataPopulatorTestInstance extends 
TestAmbariLdapDataPopulator {
     public AmbariLdapDataPopulatorTestInstance(Configuration configuration, 
Users users) {
@@ -250,7 +258,7 @@ public class AmbariLdapDataPopulatorTest {
     expect(populator.getLdapGroups("group2")).andReturn(Collections.EMPTY_SET);
     LdapGroupDto externalGroup1 = createNiceMock(LdapGroupDto.class);
     LdapBatchDto batchInfo = new LdapBatchDto();
-    populator.refreshGroupMembers(eq(batchInfo), eq(externalGroup1), 
anyObject(Map.class), anyObject(Map.class), anyObject(Set.class));
+    populator.refreshGroupMembers(eq(batchInfo), eq(externalGroup1), 
anyObject(Map.class), anyObject(Map.class), anyObject(Set.class), anyBoolean());
     expectLastCall();
     
expect(populator.getLdapGroups("group4")).andReturn(Collections.singleton(externalGroup1));
     expect(populator.getLdapGroups("group5")).andReturn(Collections.EMPTY_SET);
@@ -373,12 +381,15 @@ public class AmbariLdapDataPopulatorTest {
     LdapBatchDto batchInfo = new LdapBatchDto();
     Set<LdapGroupDto> externalGroups = createSet(externalGroup3, 
externalGroup4);
     for (LdapGroupDto externalGroup : externalGroups) {
-      populator.refreshGroupMembers(eq(batchInfo), eq(externalGroup), 
anyObject(Map.class), anyObject(Map.class), anyObject(Set.class));
+      populator.refreshGroupMembers(eq(batchInfo), eq(externalGroup),
+        anyObject(Map.class), anyObject(Map.class), anyObject(Set.class), 
anyBoolean());
       expectLastCall();
     }
-    populator.refreshGroupMembers(eq(batchInfo), eq(externalGroup1), 
anyObject(Map.class), anyObject(Map.class), anyObject(Set.class));
+    populator.refreshGroupMembers(eq(batchInfo), eq(externalGroup1),
+      anyObject(Map.class), anyObject(Map.class), anyObject(Set.class), 
anyBoolean());
     expectLastCall();
-    populator.refreshGroupMembers(eq(batchInfo), eq(externalGroup2), 
anyObject(Map.class), anyObject(Map.class), anyObject(Set.class));
+    populator.refreshGroupMembers(eq(batchInfo), eq(externalGroup2), 
anyObject(Map.class),
+      anyObject(Map.class), anyObject(Set.class), anyBoolean());
     expectLastCall();
     expect(populator.getLdapGroups("x*")).andReturn(externalGroups);
     
expect(populator.getLdapGroups("group1")).andReturn(Collections.singleton(externalGroup1));
@@ -456,10 +467,12 @@ public class AmbariLdapDataPopulatorTest {
     LdapBatchDto batchInfo = new LdapBatchDto();
     Set<LdapGroupDto> externalGroups = createSet(externalGroup3, 
externalGroup4);
     for (LdapGroupDto externalGroup : externalGroups) {
-      populator.refreshGroupMembers(eq(batchInfo), eq(externalGroup), 
anyObject(Map.class), anyObject(Map.class), anyObject(Set.class));
+      populator.refreshGroupMembers(eq(batchInfo), eq(externalGroup), 
anyObject(Map.class), anyObject(Map.class),
+        anyObject(Set.class), anyBoolean());
       expectLastCall();
     }
-    populator.refreshGroupMembers(eq(batchInfo), eq(externalGroup2), 
anyObject(Map.class), anyObject(Map.class), anyObject(Set.class));
+    populator.refreshGroupMembers(eq(batchInfo), eq(externalGroup2), 
anyObject(Map.class),
+      anyObject(Map.class), anyObject(Set.class), anyBoolean());
     expectLastCall();
     expect(populator.getLdapGroups("x*")).andReturn(externalGroups);
     
expect(populator.getLdapGroups("group2")).andReturn(Collections.singleton(externalGroup2));
@@ -530,7 +543,8 @@ public class AmbariLdapDataPopulatorTest {
     LdapBatchDto batchInfo = new LdapBatchDto();
     Set<LdapGroupDto> externalGroups = createSet(externalGroup1, 
externalGroup2, externalGroup3, externalGroup4);
     for (LdapGroupDto externalGroup : externalGroups) {
-      populator.refreshGroupMembers(eq(batchInfo), eq(externalGroup), 
anyObject(Map.class), anyObject(Map.class), anyObject(Set.class));
+      populator.refreshGroupMembers(eq(batchInfo), eq(externalGroup), 
anyObject(Map.class),
+        anyObject(Map.class), anyObject(Set.class), anyBoolean());
       expectLastCall();
     }
     expect(populator.getLdapGroups("group*")).andReturn(externalGroups);
@@ -660,7 +674,8 @@ public class AmbariLdapDataPopulatorTest {
     LdapBatchDto batchInfo = new LdapBatchDto();
     Set<LdapGroupDto> externalGroups = createSet(externalGroup1, 
externalGroup2, externalGroup3, externalGroup4);
     for (LdapGroupDto externalGroup : externalGroups) {
-      populator.refreshGroupMembers(eq(batchInfo), eq(externalGroup), 
anyObject(Map.class), anyObject(Map.class), anyObject(Set.class));
+      populator.refreshGroupMembers(eq(batchInfo), eq(externalGroup), 
anyObject(Map.class),
+        anyObject(Map.class), anyObject(Set.class), anyBoolean());
       expectLastCall();
     }
 
@@ -721,7 +736,8 @@ public class AmbariLdapDataPopulatorTest {
     LdapBatchDto batchInfo = new LdapBatchDto();
     Set<LdapGroupDto> externalGroups = createSet(externalGroup1, 
externalGroup2);
     for (LdapGroupDto externalGroup : externalGroups) {
-      populator.refreshGroupMembers(eq(batchInfo), eq(externalGroup), 
anyObject(Map.class), anyObject(Map.class), anyObject(Set.class));
+      populator.refreshGroupMembers(eq(batchInfo), eq(externalGroup), 
anyObject(Map.class),
+        anyObject(Map.class), anyObject(Set.class), anyBoolean());
       expectLastCall();
     }
     expect(populator.getExternalLdapGroupInfo()).andReturn(externalGroups);
@@ -785,7 +801,8 @@ public class AmbariLdapDataPopulatorTest {
     LdapBatchDto batchInfo = new LdapBatchDto();
     Set<LdapGroupDto> externalGroups = createSet(externalGroup1);
     for (LdapGroupDto externalGroup : externalGroups) {
-      populator.refreshGroupMembers(eq(batchInfo), eq(externalGroup), 
anyObject(Map.class), anyObject(Map.class), anyObject(Set.class));
+      populator.refreshGroupMembers(eq(batchInfo), eq(externalGroup), 
anyObject(Map.class),
+        anyObject(Map.class), anyObject(Set.class), anyBoolean());
       expectLastCall();
     }
     expect(populator.getExternalLdapGroupInfo()).andReturn(externalGroups);
@@ -848,7 +865,8 @@ public class AmbariLdapDataPopulatorTest {
     LdapBatchDto batchInfo = new LdapBatchDto();
     Set<LdapGroupDto> externalGroups = createSet(externalGroup1, 
externalGroup2);
     for (LdapGroupDto externalGroup : externalGroups) {
-      populator.refreshGroupMembers(eq(batchInfo), eq(externalGroup), 
anyObject(Map.class), anyObject(Map.class), anyObject(Set.class));
+      populator.refreshGroupMembers(eq(batchInfo), eq(externalGroup), 
anyObject(Map.class),
+        anyObject(Map.class), anyObject(Set.class), anyBoolean());
       expectLastCall();
     }
     expect(populator.getExternalLdapGroupInfo()).andReturn(externalGroups);
@@ -1461,7 +1479,7 @@ public class AmbariLdapDataPopulatorTest {
     Map<String, Group> internalGroups = new HashMap<String, Group>();
     internalGroups.put("group2", group2);
 
-    populator.refreshGroupMembers(batchInfo, externalGroup, internalUsers, 
internalGroups, null);
+    populator.refreshGroupMembers(batchInfo, externalGroup, internalUsers, 
internalGroups, null, true);
 
     Set<String> groupMembersToAdd = new HashSet<String>();
     for (LdapUserGroupMemberDto ldapUserGroupMemberDto : 
batchInfo.getMembershipToAdd()) {
@@ -1624,12 +1642,18 @@ public class AmbariLdapDataPopulatorTest {
   public void testLdapUserContextMapper_uidIsNull() throws Exception {
     LdapServerProperties ldapServerProperties = 
createNiceMock(LdapServerProperties.class);
     expect(ldapServerProperties.getUsernameAttribute()).andReturn("cn").once();
+    
expect(ldapServerProperties.getBaseDN()).andReturn("dc=SME,dc=support,dc=com").anyTimes();
     DirContextAdapter adapter = createNiceMock(DirContextAdapter.class);
     expect(adapter.getStringAttribute("cn")).andReturn("testUser");
     expect(adapter.getStringAttribute("uid")).andReturn(null);
     
expect(adapter.getNameInNamespace()).andReturn("cn=testUser,ou=Ambari,dc=SME,dc=support,dc=com");
 
-    replay(ldapServerProperties, adapter);
+    PowerMock.mockStatic(AmbariLdapUtils.class);
+    expect(AmbariLdapUtils.isLdapObjectOutOfScopeFromBaseDn(adapter, 
"dc=SME,dc=support,dc=com"))
+      .andReturn(false).anyTimes();
+
+    replay(adapter, ldapServerProperties);
+    PowerMock.replayAll();
 
     AmbariLdapDataPopulator.LdapUserContextMapper ldapUserContextMapper = new 
AmbariLdapDataPopulator.LdapUserContextMapper(ldapServerProperties);
     LdapUserDto userDto = (LdapUserDto) 
ldapUserContextMapper.mapFromContext(adapter);
@@ -1659,12 +1683,18 @@ public class AmbariLdapDataPopulatorTest {
   public void testLdapUserContextMapper() throws Exception {
     LdapServerProperties ldapServerProperties = 
createNiceMock(LdapServerProperties.class);
     expect(ldapServerProperties.getUsernameAttribute()).andReturn("cn").once();
+    
expect(ldapServerProperties.getBaseDN()).andReturn("dc=SME,dc=support,dc=com").anyTimes();
     DirContextAdapter adapter = createNiceMock(DirContextAdapter.class);
     expect(adapter.getStringAttribute("cn")).andReturn("testUser");
     expect(adapter.getStringAttribute("uid")).andReturn("UID1");
     
expect(adapter.getNameInNamespace()).andReturn("cn=testUser,ou=Ambari,dc=SME,dc=support,dc=com");
 
+    PowerMock.mockStatic(AmbariLdapUtils.class);
+    expect(AmbariLdapUtils.isLdapObjectOutOfScopeFromBaseDn(adapter, 
"dc=SME,dc=support,dc=com"))
+      .andReturn(false).anyTimes();
+
     replay(ldapServerProperties, adapter);
+    PowerMock.replayAll();
 
     AmbariLdapDataPopulator.LdapUserContextMapper ldapUserContextMapper = new 
AmbariLdapDataPopulator.LdapUserContextMapper(ldapServerProperties);
     LdapUserDto userDto = (LdapUserDto) 
ldapUserContextMapper.mapFromContext(adapter);
@@ -1675,6 +1705,106 @@ public class AmbariLdapDataPopulatorTest {
     assertEquals("cn=testuser,ou=ambari,dc=sme,dc=support,dc=com", 
userDto.getDn());
   }
 
+  @Test
+  public void testIsMemberAttributeBaseDn() {
+    // GIVEN
+    Configuration configuration = createNiceMock(Configuration.class);
+    Users users = createNiceMock(Users.class);
+    LdapServerProperties ldapServerProperties = 
createNiceMock(LdapServerProperties.class);
+
+    
expect(configuration.getLdapServerProperties()).andReturn(ldapServerProperties).anyTimes();
+    expect(ldapServerProperties.getUsernameAttribute()).andReturn("UID");
+    expect(ldapServerProperties.getGroupNamingAttr()).andReturn("CN");
+
+    replay(configuration, users, ldapServerProperties);
+
+    // WHEN
+    AmbariLdapDataPopulatorTestInstance populator = new 
AmbariLdapDataPopulatorTestInstance(configuration, users);
+    boolean result = 
populator.isMemberAttributeBaseDn("CN=mygroupname,OU=myOrganizationUnit,DC=apache,DC=org");
+    // THEN
+    assertTrue(result);
+  }
+
+  @Test
+  public void testIsMemberAttributeBaseDn_withUidMatch() {
+    // GIVEN
+    Configuration configuration = createNiceMock(Configuration.class);
+    Users users = createNiceMock(Users.class);
+    LdapServerProperties ldapServerProperties = 
createNiceMock(LdapServerProperties.class);
+
+    
expect(configuration.getLdapServerProperties()).andReturn(ldapServerProperties).anyTimes();
+    expect(ldapServerProperties.getUsernameAttribute()).andReturn("UID");
+    expect(ldapServerProperties.getGroupNamingAttr()).andReturn("CN");
+
+    replay(configuration, users, ldapServerProperties);
+
+    // WHEN
+    AmbariLdapDataPopulatorTestInstance populator = new 
AmbariLdapDataPopulatorTestInstance(configuration, users);
+    boolean result = 
populator.isMemberAttributeBaseDn("uid=myuid,OU=myOrganizationUnit,DC=apache,DC=org");
+    // THEN
+    assertTrue(result);
+  }
+
+  @Test
+  public void testIsMemberAttributeBaseDn_withLowerAndUpperCaseValue() {
+    // GIVEN
+    Configuration configuration = createNiceMock(Configuration.class);
+    Users users = createNiceMock(Users.class);
+    LdapServerProperties ldapServerProperties = 
createNiceMock(LdapServerProperties.class);
+
+    
expect(configuration.getLdapServerProperties()).andReturn(ldapServerProperties).anyTimes();
+    expect(ldapServerProperties.getUsernameAttribute()).andReturn("uid");
+    expect(ldapServerProperties.getGroupNamingAttr()).andReturn("CN");
+
+    replay(configuration, users, ldapServerProperties);
+
+    // WHEN
+    AmbariLdapDataPopulatorTestInstance populator = new 
AmbariLdapDataPopulatorTestInstance(configuration, users);
+    boolean result = 
populator.isMemberAttributeBaseDn("cn=mygroupname,OU=myOrganizationUnit,DC=apache,DC=org");
+    // THEN
+    assertTrue(result);
+  }
+
+  @Test
+  public void testIsMemberAttributeBaseDn_withWrongAttribute() {
+    // GIVEN
+    Configuration configuration = createNiceMock(Configuration.class);
+    Users users = createNiceMock(Users.class);
+    LdapServerProperties ldapServerProperties = 
createNiceMock(LdapServerProperties.class);
+
+    
expect(configuration.getLdapServerProperties()).andReturn(ldapServerProperties).anyTimes();
+    expect(ldapServerProperties.getUsernameAttribute()).andReturn("uid");
+    expect(ldapServerProperties.getGroupNamingAttr()).andReturn("CN");
+
+    replay(configuration, users, ldapServerProperties);
+
+    // WHEN
+    AmbariLdapDataPopulatorTestInstance populator = new 
AmbariLdapDataPopulatorTestInstance(configuration, users);
+    boolean result = 
populator.isMemberAttributeBaseDn("cnn=mygroupname,OU=myOrganizationUnit,DC=apache,DC=org");
+    // THEN
+    assertFalse(result);
+  }
+
+  @Test
+  public void testIsMemberAttributeBaseDn_withEmptyValues() {
+    // GIVEN
+    Configuration configuration = createNiceMock(Configuration.class);
+    Users users = createNiceMock(Users.class);
+    LdapServerProperties ldapServerProperties = 
createNiceMock(LdapServerProperties.class);
+
+    
expect(configuration.getLdapServerProperties()).andReturn(ldapServerProperties).anyTimes();
+    expect(ldapServerProperties.getUsernameAttribute()).andReturn("");
+    expect(ldapServerProperties.getGroupNamingAttr()).andReturn(null);
+
+    replay(configuration, users, ldapServerProperties);
+
+    // WHEN
+    AmbariLdapDataPopulatorTestInstance populator = new 
AmbariLdapDataPopulatorTestInstance(configuration, users);
+    boolean result = 
populator.isMemberAttributeBaseDn("cnn=mygroupname,OU=myOrganizationUnit,DC=apache,DC=org");
+    // THEN
+    assertFalse(result);
+  }
+
   private static int userIdCounter = 1;
 
   private User createUser(String name, boolean ldapUser, GroupEntity group) {

Reply via email to