Repository: ambari Updated Branches: refs/heads/branch-2.4 36226da09 -> f613941aa
AMBARI-19632. Ldap sync fails when there are special characters in distinguished names (rlevas) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/f613941a Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/f613941a Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/f613941a Branch: refs/heads/branch-2.4 Commit: f613941aabb78b600ea627f89bb78aa014bf1e79 Parents: 36226da Author: Robert Levas <rle...@hortonworks.com> Authored: Tue Apr 18 16:08:55 2017 -0400 Committer: Robert Levas <rle...@hortonworks.com> Committed: Tue Apr 18 16:08:55 2017 -0400 ---------------------------------------------------------------------- ambari-project/pom.xml | 4 +- .../security/authorization/AmbariLdapUtils.java | 71 +++++++++-- .../security/ldap/AmbariLdapDataPopulator.java | 100 ++++++++-------- .../server/security/AmbariLdapUtilsTest.java | 118 ++++++++++++++----- .../ldap/AmbariLdapDataPopulatorTest.java | 9 +- 5 files changed, 200 insertions(+), 102 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/f613941a/ambari-project/pom.xml ---------------------------------------------------------------------- diff --git a/ambari-project/pom.xml b/ambari-project/pom.xml index 8825032..be00c9f 100644 --- a/ambari-project/pom.xml +++ b/ambari-project/pom.xml @@ -140,12 +140,12 @@ <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-ldap</artifactId> - <version>3.1.2.RELEASE</version> + <version>4.0.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.ldap</groupId> <artifactId>spring-ldap-core</artifactId> - <version>1.3.1.RELEASE</version> + <version>2.0.4.RELEASE</version> </dependency> <dependency> <groupId>org.apache.directory.server</groupId> http://git-wip-us.apache.org/repos/asf/ambari/blob/f613941a/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 6d20de3..a1c7009 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 @@ -1,4 +1,4 @@ -/** +/* * 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 @@ -7,7 +7,7 @@ * "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 + * 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, @@ -19,13 +19,17 @@ 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 org.springframework.ldap.support.LdapUtils; +import javax.naming.Context; +import javax.naming.InvalidNameException; import javax.naming.Name; +import javax.naming.NamingException; + import java.util.regex.Pattern; /** @@ -42,8 +46,9 @@ public class AmbariLdapUtils { /** * Returns true if the given user name contains domain name as well (e.g. username@domain) + * * @param loginName the login name to verify if it contains domain information. - * @return + * @return true if the given user name contains domain name as well; false otherwise */ public static boolean isUserPrincipalNameFormat(String loginName) { return UPN_FORMAT.matcher(loginName).matches(); @@ -52,9 +57,10 @@ 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 + * @param baseDn the base distinguished name + * @return true if the object is out of scope; false otherwise */ public static boolean isLdapObjectOutOfScopeFromBaseDn(DirContextAdapter adapter, String baseDn) { boolean isOutOfScope = true; @@ -62,9 +68,9 @@ public class AmbariLdapUtils { 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)) { + Name fullDn = getFullDn(dn, adapter); + Name base = LdapUtils.newLdapName(baseDn); + if (fullDn.startsWith(base)) { isOutOfScope = false; } } catch (Exception e) { @@ -72,4 +78,49 @@ public class AmbariLdapUtils { } return isOutOfScope; } + + /** + * Ensures the given distinguished name is an absolute value rather than a name relative to the context. + * + * @param dn a distinguished name + * @param context the context containing the base distinguished name + * @return the absolute distinguished name + */ + public static Name getFullDn(String dn, Context context) throws NamingException { + return getFullDn(LdapUtils.newLdapName(dn), context); + } + + /** + * Ensures the given distinguished name is an absolute value rather than a name relative to the context. + * + * @param dn a distinguished name + * @param context the context containing the base distinguished name + * @return the absolute distinguished name + */ + public static Name getFullDn(Name dn, Context context) throws NamingException { + return getFullDn(LdapUtils.newLdapName(dn), LdapUtils.newLdapName(context.getNameInNamespace())); + } + + /** + * Ensures the given distinguished name is an absolute value rather than a name relative to the context. + * + * @param dn a distinguished name + * @param baseDn the base distinguished name + * @return the absolute distinguished name + */ + public static Name getFullDn(Name dn, Name baseDn) { + + if (dn.startsWith(baseDn)) { + return dn; + } else { + try { + //Copy the baseDN so we do not change the one that is passed in... + baseDn = LdapUtils.newLdapName(baseDn); + baseDn.addAll(dn); + } catch (InvalidNameException e) { + LOG.error(e.getMessage()); + } + return baseDn; + } + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/f613941a/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 91ef97a..c91f53b 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 @@ -1,4 +1,4 @@ -/** +/* * 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 @@ -32,7 +32,6 @@ 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; @@ -45,6 +44,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.Sets; + import org.springframework.ldap.control.PagedResultsDirContextProcessor; import org.springframework.ldap.core.AttributesMapper; import org.springframework.ldap.core.ContextMapper; @@ -57,6 +57,7 @@ import org.springframework.ldap.filter.Filter; import org.springframework.ldap.filter.HardcodedFilter; import org.springframework.ldap.filter.LikeFilter; import org.springframework.ldap.filter.OrFilter; +import org.springframework.ldap.support.LdapUtils; import org.springframework.security.core.userdetails.UsernameNotFoundException; import com.google.inject.Inject; @@ -90,13 +91,8 @@ 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 UID_ATTRIBUTE = "uid"; private static final String OBJECT_CLASS_ATTRIBUTE = "objectClass"; private static final int USERS_PAGE_SIZE = 500; @@ -109,8 +105,8 @@ public class AmbariLdapDataPopulator { /** * Construct an AmbariLdapDataPopulator. * - * @param configuration the Ambari configuration - * @param users utility that provides access to Users + * @param configuration the Ambari configuration + * @param users utility that provides access to Users */ @Inject public AmbariLdapDataPopulator(Configuration configuration, Users users) { @@ -355,11 +351,11 @@ public class AmbariLdapDataPopulator { /** * Check group members of the synced group: add missing ones and remove the ones absent in external LDAP. * - * @param batchInfo batch update object - * @param group ldap group - * @param internalUsers map of internal users - * @param groupMemberAttributes set of group member attributes that have already been refreshed - * @param recursive if disabled, it won't refresh members recursively (its not needed in case of all groups are processed) + * @param batchInfo batch update object + * @param group ldap group + * @param internalUsers map of internal users + * @param groupMemberAttributes set of group member attributes that have already been refreshed + * @param recursive if disabled, it won't refresh members recursively (its not needed in case of all groups are processed) * @throws AmbariException if group refresh failed */ protected void refreshGroupMembers(LdapBatchDto batchInfo, LdapGroupDto group, Map<String, User> internalUsers, @@ -371,7 +367,7 @@ public class AmbariLdapDataPopulator { groupMemberAttributes = new HashSet<String>(); } - for (String memberAttributeValue: group.getMemberAttributes()) { + for (String memberAttributeValue : group.getMemberAttributes()) { LdapUserDto groupMember = getLdapUserByMemberAttr(memberAttributeValue); if (groupMember != null) { externalMembers.add(groupMember.getUserName()); @@ -390,7 +386,7 @@ public class AmbariLdapDataPopulator { } String groupName = group.getGroupName(); final Map<String, User> internalMembers = getInternalMembers(groupName); - for (String externalMember: externalMembers) { + for (String externalMember : externalMembers) { if (internalUsers.containsKey(externalMember)) { final User user = internalUsers.get(externalMember); if (user == null) { @@ -412,7 +408,7 @@ public class AmbariLdapDataPopulator { batchInfo.getMembershipToAdd().add(new LdapUserGroupMemberDto(groupName, externalMember)); } } - for (Entry<String, User> userToBeUnsynced: internalMembers.entrySet()) { + for (Entry<String, User> userToBeUnsynced : internalMembers.entrySet()) { final User user = userToBeUnsynced.getValue(); batchInfo.getMembershipToRemove().add(new LdapUserGroupMemberDto(groupName, user.getUserName())); } @@ -421,8 +417,7 @@ public class AmbariLdapDataPopulator { /** * Get the set of LDAP groups for the given group name. * - * @param groupName the group name - * + * @param groupName the group name * @return the set of LDAP groups for the given name */ protected Set<LdapGroupDto> getLdapGroups(String groupName) { @@ -435,8 +430,7 @@ public class AmbariLdapDataPopulator { /** * Get the set of LDAP users for the given user name. * - * @param username the user name - * + * @param username the user name * @return the set of LDAP users for the given name */ protected Set<LdapUserDto> getLdapUsers(String username) { @@ -448,31 +442,30 @@ public class AmbariLdapDataPopulator { /** * Get the LDAP user member for the given member attribute. * - * @param memberAttributeValue the member attribute value - * + * @param memberAttributeValue the member attribute value * @return the user for the given member attribute; null if not found */ protected LdapUserDto getLdapUserByMemberAttr(String memberAttributeValue) { - Set<LdapUserDto> filteredLdapUsers = new HashSet<LdapUserDto>(); + Set<LdapUserDto> filteredLdapUsers; memberAttributeValue = getUniqueIdByMemberPattern(memberAttributeValue, - ldapServerProperties.getSyncUserMemberReplacePattern()); + ldapServerProperties.getSyncUserMemberReplacePattern()); Filter syncMemberFilter = createCustomMemberFilter(memberAttributeValue, - ldapServerProperties.getSyncUserMemberFilter()); + ldapServerProperties.getSyncUserMemberFilter()); if (memberAttributeValue != null && syncMemberFilter != null) { LOG.trace("Use custom filter '{}' for getting member user with default baseDN ('{}')", - syncMemberFilter.encode(), ldapServerProperties.getBaseDN()); + syncMemberFilter.encode(), ldapServerProperties.getBaseDN()); filteredLdapUsers = getFilteredLdapUsers(ldapServerProperties.getBaseDN(), syncMemberFilter); - } else if (memberAttributeValue!= null && isMemberAttributeBaseDn(memberAttributeValue)) { + } else 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)); + .and(new EqualsFilter(OBJECT_CLASS_ATTRIBUTE, ldapServerProperties.getUserObjectClass())) + .and(new EqualsFilter(ldapServerProperties.getUsernameAttribute(), memberAttributeValue)); filteredLdapUsers = getFilteredLdapUsers(ldapServerProperties.getBaseDN(), filter); } return (filteredLdapUsers.isEmpty()) ? null : filteredLdapUsers.iterator().next(); @@ -481,21 +474,20 @@ public class AmbariLdapDataPopulator { /** * Get the LDAP group member for the given member attribute. * - * @param memberAttributeValue the member attribute value - * + * @param memberAttributeValue the member attribute value * @return the group for the given member attribute; null if not found */ protected LdapGroupDto getLdapGroupByMemberAttr(String memberAttributeValue) { - Set<LdapGroupDto> filteredLdapGroups = new HashSet<LdapGroupDto>(); + Set<LdapGroupDto> filteredLdapGroups; memberAttributeValue = getUniqueIdByMemberPattern(memberAttributeValue, - ldapServerProperties.getSyncGroupMemberReplacePattern()); + ldapServerProperties.getSyncGroupMemberReplacePattern()); Filter syncMemberFilter = createCustomMemberFilter(memberAttributeValue, - ldapServerProperties.getSyncGroupMemberFilter()); + ldapServerProperties.getSyncGroupMemberFilter()); if (memberAttributeValue != null && syncMemberFilter != null) { LOG.trace("Use custom filter '{}' for getting member group with default baseDN ('{}')", - syncMemberFilter.encode(), ldapServerProperties.getBaseDN()); + syncMemberFilter.encode(), ldapServerProperties.getBaseDN()); filteredLdapGroups = getFilteredLdapGroups(ldapServerProperties.getBaseDN(), syncMemberFilter); } else if (memberAttributeValue != null && isMemberAttributeBaseDn(memberAttributeValue)) { LOG.trace("Member can be used as baseDn: {}", memberAttributeValue); @@ -504,8 +496,8 @@ public class AmbariLdapDataPopulator { } else { LOG.trace("Member cannot be used as baseDn: {}", memberAttributeValue); filteredLdapGroups = getFilteredLdapGroups(ldapServerProperties.getBaseDN(), - new EqualsFilter(OBJECT_CLASS_ATTRIBUTE, ldapServerProperties.getGroupObjectClass()), - getMemberFilter(memberAttributeValue)); + new EqualsFilter(OBJECT_CLASS_ATTRIBUTE, ldapServerProperties.getGroupObjectClass()), + getMemberFilter(memberAttributeValue)); } return (filteredLdapGroups.isEmpty()) ? null : filteredLdapGroups.iterator().next(); @@ -554,7 +546,7 @@ public class AmbariLdapDataPopulator { */ protected void cleanUpLdapUsersWithoutGroup() throws AmbariException { final List<User> allUsers = users.getAllUsers(); - for (User user: allUsers) { + for (User user : allUsers) { if (user.isLdapUser() && user.getGroups().isEmpty()) { users.removeUser(user); } @@ -584,7 +576,7 @@ public class AmbariLdapDataPopulator { */ protected boolean isMemberAttributeBaseDn(String memberAttributeValue) { Pattern pattern = Pattern.compile(String.format(IS_MEMBER_DN_REGEXP, - ldapServerProperties.getUsernameAttribute(), ldapServerProperties.getGroupNamingAttr())); + ldapServerProperties.getUsernameAttribute(), ldapServerProperties.getGroupNamingAttr())); return pattern.matcher(memberAttributeValue).find(); } @@ -604,10 +596,10 @@ public class AmbariLdapDataPopulator { String dnAttribute = ldapServerProperties.getDnAttribute(); return new OrFilter().or(new EqualsFilter(dnAttribute, memberAttributeValue)). - or(new EqualsFilter(UID_ATTRIBUTE, memberAttributeValue)); + or(new EqualsFilter(UID_ATTRIBUTE, memberAttributeValue)); } - private Set<LdapGroupDto> getFilteredLdapGroups(String baseDn, Filter...filters) { + private Set<LdapGroupDto> getFilteredLdapGroups(String baseDn, Filter... filters) { AndFilter andFilter = new AndFilter(); for (Filter filter : filters) { andFilter.and(filter); @@ -620,7 +612,7 @@ public class AmbariLdapDataPopulator { final LdapTemplate ldapTemplate = loadLdapTemplate(); LOG.trace("LDAP Group Query - Base DN: '{}' ; Filter: '{}'", baseDn, filter.encode()); ldapTemplate.search(baseDn, filter.encode(), - new LdapGroupContextMapper(groups, ldapServerProperties)); + new LdapGroupContextMapper(groups, ldapServerProperties)); return groups; } @@ -635,7 +627,7 @@ public class AmbariLdapDataPopulator { return getFilteredLdapUsers(ldapServerProperties.getBaseDN(), userObjectFilter); } - private Set<LdapUserDto> getFilteredLdapUsers(String baseDn, Filter...filters) { + private Set<LdapUserDto> getFilteredLdapUsers(String baseDn, Filter... filters) { AndFilter andFilter = new AndFilter(); for (Filter filter : filters) { andFilter.and(filter); @@ -656,15 +648,15 @@ public class AmbariLdapDataPopulator { do { LOG.trace("LDAP User Query - Base DN: '{}' ; Filter: '{}'", baseDn, encodedFilter); List dtos = configuration.getLdapServerProperties().isPaginationEnabled() ? - ldapTemplate.search(baseDn, encodedFilter, searchControls, ldapUserContextMapper, processor) : - ldapTemplate.search(baseDn, encodedFilter, searchControls, ldapUserContextMapper); + ldapTemplate.search(LdapUtils.newLdapName(baseDn), encodedFilter, searchControls, ldapUserContextMapper, processor) : + ldapTemplate.search(LdapUtils.newLdapName(baseDn), encodedFilter, searchControls, ldapUserContextMapper); for (Object dto : dtos) { if (dto != null) { - users.add((LdapUserDto)dto); + users.add((LdapUserDto) dto); } } } while (configuration.getLdapServerProperties().isPaginationEnabled() - && processor.getCookie().getCookie() != null); + && processor.getCookie().getCookie() != null); return users; } @@ -728,7 +720,7 @@ public class AmbariLdapDataPopulator { ldapServerProperties = properties; final LdapContextSource ldapContextSource = createLdapContextSource(); - + // The LdapTemplate by design will close the connection after each call to the LDAP Server // In order to have the interaction work with large/paged results, said connection must be pooled and reused ldapContextSource.setPooled(true); @@ -768,6 +760,7 @@ public class AmbariLdapDataPopulator { /** * PagedResultsDirContextProcessor factory method. + * * @return new processor; */ protected PagedResultsDirContextProcessor createPagingProcessor() { @@ -777,8 +770,7 @@ public class AmbariLdapDataPopulator { /** * LdapTemplate factory method. * - * @param ldapContextSource the LDAP context source - * + * @param ldapContextSource the LDAP context source * @return new LDAP template */ protected LdapTemplate createLdapTemplate(LdapContextSource ldapContextSource) { @@ -813,7 +805,7 @@ public class AmbariLdapDataPopulator { group.setGroupName(groupNameAttribute.toLowerCase()); final String[] uniqueMembers = adapter.getStringAttributes(ldapServerProperties.getGroupMembershipAttr()); if (uniqueMembers != null) { - for (String uniqueMember: uniqueMembers) { + for (String uniqueMember : uniqueMembers) { group.getMemberAttributes().add(uniqueMember.toLowerCase()); } } @@ -833,7 +825,7 @@ public class AmbariLdapDataPopulator { @Override public Object mapFromContext(Object ctx) { - final DirContextAdapter adapter = (DirContextAdapter) ctx; + final DirContextAdapter adapter = (DirContextAdapter) ctx; final String usernameAttribute = adapter.getStringAttribute(ldapServerProperties.getUsernameAttribute()); final String uidAttribute = adapter.getStringAttribute(UID_ATTRIBUTE); http://git-wip-us.apache.org/repos/asf/ambari/blob/f613941a/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 5bcdf48..b05fa15 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 @@ -1,4 +1,4 @@ -/** +/* * 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 @@ -7,7 +7,7 @@ * "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 + * 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, @@ -15,33 +15,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.apache.ambari.server.security; +import junit.framework.Assert; + 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 org.springframework.ldap.support.LdapUtils; -import javax.naming.Context; +import javax.naming.Name; 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.createStrictMock; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; -@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"; + private static final String USER_BASE_DN = "ou=hdp,ou=Users,dc=apache,dc=org"; + private static final String USER_RELATIVE_DN = "uid=myuser"; + private static final String USER_DN = USER_RELATIVE_DN + "," + USER_BASE_DN; @Test public void testIsUserPrincipalNameFormat_True() throws Exception { @@ -106,46 +105,101 @@ public class AmbariLdapUtilsTest { @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(); + Name fullDn = LdapUtils.newLdapName(USER_DN); + DirContextAdapter adapter = createNiceMock(DirContextAdapter.class); expect(adapter.getDn()).andReturn(fullDn); - expect(context.getNameInNamespace()).andReturn(USER_DN); + expect(adapter.getNameInNamespace()).andReturn(USER_DN); - replay(adapter, context); - PowerMock.replayAll(); + replay(adapter); // WHEN boolean isOutOfScopeFromBaseDN = AmbariLdapUtils.isLdapObjectOutOfScopeFromBaseDn(adapter, "dc=apache,dc=org"); // THEN assertFalse(isOutOfScopeFromBaseDN); + + verify(adapter); } @Test public void testIsLdapObjectOutOfScopeFromBaseDn_dnOutOfScope() throws NamingException { // GIVEN - DistinguishedName fullDn = new DistinguishedName(USER_DN); - Context context = createNiceMock(Context.class); + Name fullDn = LdapUtils.newLdapName(USER_DN); 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); + expect(adapter.getNameInNamespace()).andReturn(USER_DN); - replay(adapter, context); - PowerMock.replayAll(); + replay(adapter); // WHEN boolean isOutOfScopeFromBaseDN = AmbariLdapUtils.isLdapObjectOutOfScopeFromBaseDn(adapter, "dc=apache,dc=org,ou=custom"); // THEN assertTrue(isOutOfScopeFromBaseDN); + + verify(adapter); + } + + @Test + public void testGetFullDn() throws Exception { + + DirContextAdapter adapterFullDn = createStrictMock(DirContextAdapter.class); + expect(adapterFullDn.getNameInNamespace()).andReturn(USER_DN).anyTimes(); + + DirContextAdapter adapterBaseDn = createStrictMock(DirContextAdapter.class); + expect(adapterBaseDn.getNameInNamespace()).andReturn(USER_BASE_DN).anyTimes(); + + Name absoluteDn = LdapUtils.newLdapName(USER_DN); + Name relativeDn = LdapUtils.newLdapName(USER_RELATIVE_DN); + + replay(adapterFullDn, adapterBaseDn); + + Name fullDn; + + // **************************** + // getFullDn(Name, Context) + fullDn = AmbariLdapUtils.getFullDn(absoluteDn, adapterFullDn); + Assert.assertEquals(absoluteDn, fullDn); + + fullDn = AmbariLdapUtils.getFullDn(absoluteDn, adapterBaseDn); + Assert.assertEquals(absoluteDn, fullDn); + + fullDn = AmbariLdapUtils.getFullDn(relativeDn, adapterBaseDn); + Assert.assertEquals(absoluteDn, fullDn); + // **************************** + + + // **************************** + // getFullDn(String, Context) + fullDn = AmbariLdapUtils.getFullDn(absoluteDn.toString(), adapterFullDn); + Assert.assertEquals(absoluteDn, fullDn); + + fullDn = AmbariLdapUtils.getFullDn(absoluteDn.toString(), adapterBaseDn); + Assert.assertEquals(absoluteDn, fullDn); + + fullDn = AmbariLdapUtils.getFullDn(relativeDn.toString(), adapterBaseDn); + Assert.assertEquals(absoluteDn, fullDn); + // **************************** + + // **************************** + // getFullDn(Name, Name) + Name nameInNamespaceFullDn = LdapUtils.newLdapName(adapterFullDn.getNameInNamespace()); + Name nameInNamespaceBaseDn = LdapUtils.newLdapName(adapterBaseDn.getNameInNamespace()); + + fullDn = AmbariLdapUtils.getFullDn(absoluteDn, nameInNamespaceFullDn); + Assert.assertEquals(absoluteDn, fullDn); + + fullDn = AmbariLdapUtils.getFullDn(absoluteDn, nameInNamespaceBaseDn); + Assert.assertEquals(absoluteDn, fullDn); + + fullDn = AmbariLdapUtils.getFullDn(relativeDn, nameInNamespaceBaseDn); + Assert.assertEquals(absoluteDn, fullDn); + + // Make sure nameInNamespace was not altered + Assert.assertEquals(adapterFullDn.getNameInNamespace(), nameInNamespaceFullDn.toString()); + Assert.assertEquals(adapterBaseDn.getNameInNamespace(), nameInNamespaceBaseDn.toString()); + // **************************** + + verify(adapterFullDn, adapterBaseDn); } } http://git-wip-us.apache.org/repos/asf/ambari/blob/f613941a/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 34eadad..f31468a 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 @@ -57,6 +57,7 @@ import org.springframework.ldap.core.DirContextAdapter; import org.springframework.ldap.core.LdapTemplate; import org.springframework.ldap.core.support.LdapContextSource; import org.springframework.ldap.filter.Filter; +import org.springframework.ldap.support.LdapUtils; import javax.naming.directory.SearchControls; @@ -1585,12 +1586,12 @@ public class AmbariLdapDataPopulatorTest { expect(ldapServerProperties.isPaginationEnabled()).andReturn(true).anyTimes(); expect(ldapServerProperties.getUserObjectClass()).andReturn("objectClass").anyTimes(); expect(ldapServerProperties.getDnAttribute()).andReturn("dn").anyTimes(); - expect(ldapServerProperties.getBaseDN()).andReturn("baseDN").anyTimes(); + expect(ldapServerProperties.getBaseDN()).andReturn("cn=testUser,ou=Ambari,dc=SME,dc=support,dc=com").anyTimes(); expect(ldapServerProperties.getUsernameAttribute()).andReturn("uid").anyTimes(); expect(processor.getCookie()).andReturn(cookie).anyTimes(); expect(cookie.getCookie()).andReturn(null).anyTimes(); - expect(ldapTemplate.search(eq("baseDN"), eq("(&(objectClass=objectClass)(uid=foo))"), anyObject(SearchControls.class), capture(contextMapperCapture), eq(processor))).andReturn(list); + expect(ldapTemplate.search(eq(LdapUtils.newLdapName("cn=testUser,ou=Ambari,dc=SME,dc=support,dc=com")), eq("(&(objectClass=objectClass)(uid=foo))"), anyObject(SearchControls.class), capture(contextMapperCapture), eq(processor))).andReturn(list); replay(ldapTemplate, ldapServerProperties, users, configuration, processor, cookie); @@ -1625,9 +1626,9 @@ public class AmbariLdapDataPopulatorTest { expect(ldapServerProperties.getUserObjectClass()).andReturn("objectClass").anyTimes(); expect(ldapServerProperties.getUsernameAttribute()).andReturn("uid").anyTimes(); expect(ldapServerProperties.getDnAttribute()).andReturn("dn").anyTimes(); - expect(ldapServerProperties.getBaseDN()).andReturn("baseDN").anyTimes(); + expect(ldapServerProperties.getBaseDN()).andReturn("cn=testUser,ou=Ambari,dc=SME,dc=support,dc=com").anyTimes(); - expect(ldapTemplate.search(eq("baseDN"), eq("(&(objectClass=objectClass)(uid=foo))"), anyObject(SearchControls.class), capture(contextMapperCapture))).andReturn(list); + expect(ldapTemplate.search(eq(LdapUtils.newLdapName("cn=testUser,ou=Ambari,dc=SME,dc=support,dc=com") ), eq("(&(objectClass=objectClass)(uid=foo))"), anyObject(SearchControls.class), capture(contextMapperCapture))).andReturn(list); replay(ldapTemplate, ldapServerProperties, users, configuration, processor, cookie);