diff --git a/ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/XUserInfo.java b/ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/XUserInfo.java index 8012f15d97..c4a2490a39 100644 --- a/ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/XUserInfo.java +++ b/ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/model/XUserInfo.java @@ -28,6 +28,7 @@ public class XUserInfo { private String id; private String name; private String firstName; + private String lastName; private String description; private String otherAttributes; private String syncSource; @@ -58,6 +59,10 @@ public void setName(String name) { public void setFirstName(String firstName) { this.firstName = firstName; } + public String getLastName() { return lastName; } + + public void setLastName(String lastName) { this.lastName = lastName; } + public String getDescription() { return description; } @@ -140,7 +145,8 @@ public void setOtherAttributes(String otherAttributes) { @Override public String toString() { - return "XUserInfo [id=" + id + ", name=" + name + ", firstName=" + firstName + ", description=" + return "XUserInfo [id=" + id + ", name=" + name + ", firstName=" + firstName + + ", lastName=" + lastName + ", description=" + description + ", groupNameList=" + groupNameList + ", userRoleList=" + userRoleList + "]"; } diff --git a/ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/util/UgsyncCommonConstants.java b/ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/util/UgsyncCommonConstants.java index f20bf91967..0e6ec282a0 100644 --- a/ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/util/UgsyncCommonConstants.java +++ b/ugsync-util/src/main/java/org/apache/ranger/ugsyncutil/util/UgsyncCommonConstants.java @@ -25,5 +25,7 @@ public class UgsyncCommonConstants { public static final String FULL_NAME = "full_name"; public static final String SYNC_SOURCE = "sync_source"; public static final String LDAP_URL = "ldap_url"; + public static final String FIRST_NAME = "first_name"; + public static final String LAST_NAME = "last_name"; } diff --git a/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapUserGroupBuilder.java b/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapUserGroupBuilder.java index 09bf3c1ff6..862fb6c421 100644 --- a/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapUserGroupBuilder.java +++ b/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapUserGroupBuilder.java @@ -91,6 +91,8 @@ public class LdapUserGroupBuilder implements UserGroupSource { private String[] userSearchBase; private String userNameAttribute; + private String userFirstNameAttribute; + private String userLastNameAttribute; private String userCloudIdAttribute; private int userSearchScope; private String userObjectClass; @@ -232,10 +234,14 @@ private void setConfig() throws Throwable { userObjectClass = config.getUserObjectClass(); userSearchFilter = config.getUserSearchFilter(); userNameAttribute = config.getUserNameAttribute(); + userFirstNameAttribute = config.getUserFirstNameAttribute(); + userLastNameAttribute = config.getUserLastNameAttribute(); userCloudIdAttribute = config.getUserCloudIdAttribute(); Set userSearchAttributes = new HashSet(); userSearchAttributes.add(userNameAttribute); + userSearchAttributes.add(userFirstNameAttribute); + userSearchAttributes.add(userLastNameAttribute); userGroupNameAttributeSet = config.getUserGroupNameAttributeSet(); for (String useGroupNameAttribute : userGroupNameAttributeSet) { userSearchAttributes.add(useGroupNameAttribute); @@ -319,6 +325,8 @@ private void setConfig() throws Throwable { + ", userSearchFilter: " + userSearchFilter + ", extendedUserSearchFilter: " + extendedUserSearchFilter + ", userNameAttribute: " + userNameAttribute + + ", userFirstNameAttribute: " + userFirstNameAttribute + + ", userLastNameAttribute: " + userLastNameAttribute + ", userSearchAttributes: " + userSearchAttributes + ", userGroupNameAttributeSet: " + userGroupNameAttributeSet + ", otherUserAttributes: " + otherUserAttributes @@ -578,6 +586,8 @@ private long getUsers(boolean computeDeletes) throws Throwable { userAttrMap.put(UgsyncCommonConstants.FULL_NAME, userFullName); userAttrMap.put(UgsyncCommonConstants.SYNC_SOURCE, currentSyncSource); userAttrMap.put(UgsyncCommonConstants.LDAP_URL, config.getLdapUrl()); + addNameAttrToMap(attributes, userFirstNameAttribute, UgsyncCommonConstants.FIRST_NAME, userAttrMap); + addNameAttrToMap(attributes, userLastNameAttribute, UgsyncCommonConstants.LAST_NAME, userAttrMap); Attribute userCloudIdAttr = attributes.get(userCloudIdAttribute); if (userCloudIdAttr != null) { addToAttrMap(userAttrMap, "cloud_id", userCloudIdAttr, config.getUserCloudIdAttributeDataType()); @@ -1056,6 +1066,24 @@ private void goUpGroupHierarchyLdap(Set groupDNs, int groupHierarchyLeve goUpGroupHierarchyLdap(nextLevelGroups, groupHierarchyLevels-1); } + private void addNameAttrToMap(Attributes attributes, String ldapAttrName, String mapKey, Map userAttrMap) throws NamingException { + if (StringUtils.isEmpty(ldapAttrName) || attributes == null) { + return; + } + Attribute attr = attributes.get(ldapAttrName); + if (attr == null) { + return; + } + Object val = attr.get(); + if (val == null) { + return; + } + String strVal = val.toString().trim(); + if (!strVal.isEmpty()) { + userAttrMap.put(mapKey, strVal); + } + } + private void addToAttrMap(Map userAttrMap, String attrName, Attribute attr, String attrType) throws Throwable{ if (attrType.equals(DATA_TYPE_BYTEARRAY)) { try { diff --git a/ugsync/src/main/java/org/apache/ranger/unixusersync/config/UserGroupSyncConfig.java b/ugsync/src/main/java/org/apache/ranger/unixusersync/config/UserGroupSyncConfig.java index 8703a52c64..51fa911824 100644 --- a/ugsync/src/main/java/org/apache/ranger/unixusersync/config/UserGroupSyncConfig.java +++ b/ugsync/src/main/java/org/apache/ranger/unixusersync/config/UserGroupSyncConfig.java @@ -150,6 +150,12 @@ public class UserGroupSyncConfig { private static final String LGSYNC_USER_NAME_ATTRIBUTE = "ranger.usersync.ldap.user.nameattribute"; private static final String DEFAULT_USER_NAME_ATTRIBUTE = "cn"; + private static final String LGSYNC_USER_FIRST_NAME_ATTRIBUTE = "ranger.usersync.ldap.user.firstnameattribute"; + private static final String DEFAULT_USER_FIRST_NAME_ATTRIBUTE = "givenName"; + + private static final String LGSYNC_USER_LAST_NAME_ATTRIBUTE = "ranger.usersync.ldap.user.lastnameattribute"; + private static final String DEFAULT_USER_LAST_NAME_ATTRIBUTE = "sn"; + private static final String LGSYNC_USER_GROUP_NAME_ATTRIBUTE = "ranger.usersync.ldap.user.groupnameattribute"; private static final String DEFAULT_USER_GROUP_NAME_ATTRIBUTE = "memberof,ismemberof"; @@ -707,6 +713,22 @@ public String getUserNameAttribute() { return val; } + public String getUserFirstNameAttribute() { + String val = prop.getProperty(LGSYNC_USER_FIRST_NAME_ATTRIBUTE); + if (val == null || val.trim().isEmpty()) { + return DEFAULT_USER_FIRST_NAME_ATTRIBUTE; + } + return val.trim(); + } + + public String getUserLastNameAttribute() { + String val = prop.getProperty(LGSYNC_USER_LAST_NAME_ATTRIBUTE); + if (val == null || val.trim().isEmpty()) { + return DEFAULT_USER_LAST_NAME_ATTRIBUTE; + } + return val.trim(); + } + public String getUserGroupNameAttribute() { String val = prop.getProperty(LGSYNC_USER_GROUP_NAME_ATTRIBUTE); if(val == null || val.trim().isEmpty()) { @@ -1248,6 +1270,16 @@ public void setUserNameAttribute(String userNameAttr) { prop.setProperty(LGSYNC_USER_NAME_ATTRIBUTE, userNameAttr); } + /* Used only for unit testing */ + public void setUserFirstNameAttribute(String userFirstNameAttr) { + prop.setProperty(LGSYNC_USER_FIRST_NAME_ATTRIBUTE, userFirstNameAttr); + } + + /* Used only for unit testing */ + public void setUserLastNameAttribute(String userLastNameAttr) { + prop.setProperty(LGSYNC_USER_LAST_NAME_ATTRIBUTE, userLastNameAttr); + } + /* Used only for unit testing */ public void setGroupHierarchyLevel(int groupHierarchyLevel) { prop.setProperty(LGSYNC_GROUP_HIERARCHY_LEVELS, String.valueOf(groupHierarchyLevel)); diff --git a/ugsync/src/main/java/org/apache/ranger/unixusersync/process/PolicyMgrUserGroupBuilder.java b/ugsync/src/main/java/org/apache/ranger/unixusersync/process/PolicyMgrUserGroupBuilder.java index 8c33baf80d..d2a6ea255f 100644 --- a/ugsync/src/main/java/org/apache/ranger/unixusersync/process/PolicyMgrUserGroupBuilder.java +++ b/ugsync/src/main/java/org/apache/ranger/unixusersync/process/PolicyMgrUserGroupBuilder.java @@ -639,6 +639,16 @@ private T setOtherAttributes(T uginfo, String syncSource, Map computeGroupUsersDelta(Map> sour private XUserInfo addXUserInfo(String aUserName, Map otherAttrsMap, String otherAttributes) { XUserInfo xuserInfo = new XUserInfo(); xuserInfo.setName(aUserName); - xuserInfo.setFirstName(aUserName); + String firstName = otherAttrsMap != null ? otherAttrsMap.get(UgsyncCommonConstants.FIRST_NAME) : null; + String lastName = otherAttrsMap != null ? otherAttrsMap.get(UgsyncCommonConstants.LAST_NAME) : null; + xuserInfo.setFirstName(StringUtils.isNotBlank(firstName) ? firstName : aUserName); + if (StringUtils.isNotBlank(lastName)) { + xuserInfo.setLastName(lastName); + } xuserInfo.setDescription(aUserName + " - add from Unix box"); xuserInfo.setUserSource(SOURCE_EXTERNAL); xuserInfo.setStatus(STATUS_ENABLED); diff --git a/ugsync/src/test/java/org/apache/ranger/usergroupsync/PolicyMgrUserGroupBuilderTest.java b/ugsync/src/test/java/org/apache/ranger/usergroupsync/PolicyMgrUserGroupBuilderTest.java index fd8181be93..7014081c02 100644 --- a/ugsync/src/test/java/org/apache/ranger/usergroupsync/PolicyMgrUserGroupBuilderTest.java +++ b/ugsync/src/test/java/org/apache/ranger/usergroupsync/PolicyMgrUserGroupBuilderTest.java @@ -32,6 +32,7 @@ public class PolicyMgrUserGroupBuilderTest extends PolicyMgrUserGroupBuilder { private Map> groupUsers; private Set invalidGroups; private Set invalidUsers; + private Map> userAttrsByName; public PolicyMgrUserGroupBuilderTest() { super(); @@ -44,6 +45,11 @@ public void init() throws Throwable { groupUsers = new HashMap<>(); invalidGroups = new HashSet<>(); invalidUsers = new HashSet<>(); + userAttrsByName = new HashMap<>(); + } + + public Map getUserAttrs(String username) { + return userAttrsByName.get(username); } public int getTotalUsers() { @@ -97,8 +103,10 @@ public void addOrUpdateUsersGroups(Map> sourceGroups for (String userdn : sourceUsers.keySet()) { //System.out.println("Username: " + sourceUsers.get(userdn).get("original_name")); - String username = userNameTransform(sourceUsers.get(userdn).get("original_name")); + Map userAttrs = sourceUsers.get(userdn); + String username = userNameTransform(userAttrs.get("original_name")); allUsers.add(username); + userAttrsByName.put(username, userAttrs); if (!isValidString(username)) { invalidUsers.add(username); } diff --git a/ugsync/src/test/java/org/apache/ranger/usergroupsync/TestLdapUserGroup.java b/ugsync/src/test/java/org/apache/ranger/usergroupsync/TestLdapUserGroup.java index 2011b5b75b..4f235428b2 100644 --- a/ugsync/src/test/java/org/apache/ranger/usergroupsync/TestLdapUserGroup.java +++ b/ugsync/src/test/java/org/apache/ranger/usergroupsync/TestLdapUserGroup.java @@ -21,6 +21,12 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.util.Map; + +import org.apache.ranger.ugsyncutil.util.UgsyncCommonConstants; import org.apache.directory.server.annotations.CreateLdapConnectionPool; import org.apache.directory.server.core.annotations.ApplyLdifFiles; @@ -466,6 +472,62 @@ public void testGroupsWithNoUsers() throws Throwable { assertEquals(2, sink.getGroupsWithNoUsers()); } + @Test + public void testUserFirstAndLastNameMapping() throws Throwable { + config.setUserNameAttribute("sAMAccountName"); + config.setUserFirstNameAttribute("cn"); + config.setUserLastNameAttribute("sn"); + config.setUserSearchBase("cn=users,DC=ranger,DC=qe,DC=hortonworks,DC=com"); + config.setUserSearchFilter(""); + config.setGroupSearchBase("OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com"); + config.setUserGroupMemberAttributeName("member"); + config.setUserObjectClass("organizationalPerson"); + config.setGroupObjectClass("groupOfNames"); + config.setGroupSearchEnabled(false); + config.setPagedResultsEnabled(true); + config.setGroupSearchFirstEnabled(false); + config.setUserSearchEnabled(true); + // clear any group-name filter leftover from prior tests in this suite + config.setGroupnames(""); + ldapBuilder.init(); + sink.init(); + ldapBuilder.updateSink(sink); + + // sAMAccountName for cn=User1000 entry is "U1000"; cn/sn provide first/last name + Map u1000Attrs = sink.getUserAttrs("U1000"); + assertNotNull("U1000 should have been synced", u1000Attrs); + assertEquals("User1000", u1000Attrs.get(UgsyncCommonConstants.FIRST_NAME)); + assertEquals("User1000", u1000Attrs.get(UgsyncCommonConstants.LAST_NAME)); + } + + @Test + public void testUserNameMappingWithoutFirstNameAttribute() throws Throwable { + config.setUserNameAttribute("sAMAccountName"); + // firstName attribute defaults to givenName which is not present in the test LDIF + config.setUserFirstNameAttribute("givenName"); + config.setUserLastNameAttribute("sn"); + config.setUserSearchBase("cn=users,DC=ranger,DC=qe,DC=hortonworks,DC=com"); + config.setUserSearchFilter(""); + config.setGroupSearchBase("OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com"); + config.setUserGroupMemberAttributeName("member"); + config.setUserObjectClass("organizationalPerson"); + config.setGroupObjectClass("groupOfNames"); + config.setGroupSearchEnabled(false); + config.setPagedResultsEnabled(true); + config.setGroupSearchFirstEnabled(false); + config.setUserSearchEnabled(true); + // clear any group-name filter leftover from prior tests in this suite + config.setGroupnames(""); + ldapBuilder.init(); + sink.init(); + ldapBuilder.updateSink(sink); + + Map u1000Attrs = sink.getUserAttrs("U1000"); + assertNotNull("U1000 should have been synced", u1000Attrs); + assertNull("givenName is absent in the test LDIF", u1000Attrs.get(UgsyncCommonConstants.FIRST_NAME)); + assertEquals("User1000", u1000Attrs.get(UgsyncCommonConstants.LAST_NAME)); + } + @After public void shutdown() throws Exception { if (getService().isStarted()) {