You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by ve...@apache.org on 2015/10/10 18:29:07 UTC
[1/3] incubator-ranger git commit: RANGER-652: Adding support for
ldap connection check tool
Repository: incubator-ranger
Updated Branches:
refs/heads/master a2c4bb294 -> 9474fe9d5
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/5ce7cc38/ugsync/ldapconfigchecktool/ldapconfigcheck/src/main/java/org/apache/ranger/ldapconfigcheck/UserSync.java
----------------------------------------------------------------------
diff --git a/ugsync/ldapconfigchecktool/ldapconfigcheck/src/main/java/org/apache/ranger/ldapconfigcheck/UserSync.java b/ugsync/ldapconfigchecktool/ldapconfigcheck/src/main/java/org/apache/ranger/ldapconfigcheck/UserSync.java
new file mode 100644
index 0000000..53da9f2
--- /dev/null
+++ b/ugsync/ldapconfigchecktool/ldapconfigcheck/src/main/java/org/apache/ranger/ldapconfigcheck/UserSync.java
@@ -0,0 +1,860 @@
+/*
+ * 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.ranger.ldapconfigcheck;
+
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+import javax.naming.ldap.LdapContext;
+import javax.naming.ldap.Control;
+import javax.naming.ldap.PagedResultsResponseControl;
+import javax.naming.ldap.PagedResultsControl;
+import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
+public class UserSync {
+ private static String[] userNameAttrValues = { "sAMAccountName", "uid", "cn" };
+ private static String[] userObjClassValues = { "person", "posixAccount" }; //Not needed as this is read from the second occurence of objectClass attribute from user entry
+ private static String[] userGroupMemAttrValues = { "memberOf", "ismemberOf"};
+
+ private static String[] groupObjectClassValues = { "group", "groupOfNames", "posixGroup" };
+ private static String[] groupNameAttrValues = { "distinguishedName", "cn" };
+ private static String[] groupMemAttrValues = { "member", "memberUid" };
+
+ private String userNameAttribute = null;
+ private String userObjClassName = null;
+ private String userGroupMemberName = null;
+ private String groupMemberName = null;
+ private String groupNameAttrName = null;
+ private String groupObjClassName = null;
+ private String groupSearchBase = null;
+ private String groupSearchFilter = null;
+ private String userSearchBase = null;
+ private String userSearchFilter = null;
+ private String searchBase = null;
+ private String groupName = null;
+ private PrintStream logFile = null;
+ private PrintStream ambariProps = null;
+ private PrintStream installProps = null;
+
+ private LdapConfig config = null;
+
+ public String getUserNameAttribute() {
+ return userNameAttribute;
+ }
+
+ public String getUserObjClassName() {
+ return userObjClassName;
+ }
+
+ public String getUserGroupMemberName() {
+ return userGroupMemberName;
+ }
+
+ public String getGroupMemberName() {
+ return groupMemberName;
+ }
+
+ public String getGroupNameAttrName() {
+ return groupNameAttrName;
+ }
+
+ public String getGroupObjClassName() {
+ return groupObjClassName;
+ }
+
+ public String getGroupSearchBase() { return groupSearchBase; }
+
+ public String getUserSearchBase() { return userSearchBase; }
+
+ public String getSearchBase() {
+ return searchBase;
+ }
+
+ public UserSync(LdapConfig config, PrintStream logFile, PrintStream ambariProps, PrintStream installProps) {
+ this.config = config;
+ this.logFile = logFile;
+ this.ambariProps = ambariProps;
+ this.installProps = installProps;
+ initUserSync();
+ }
+
+ private void initUserSync() {
+ try {
+ String bindDn = config.getLdapBindDn();
+ userObjClassName = config.getUserObjectClass();
+ userNameAttribute = config.getUserNameAttribute();
+ userGroupMemberName = config.getUserGroupNameAttribute();
+ userSearchBase = config.getUserSearchBase();
+ userSearchFilter = config.getUserSearchFilter();
+ groupObjClassName = config.getGroupObjectClass();
+ groupNameAttrName = config.getGroupNameAttribute();
+ groupMemberName = config.getUserGroupMemberAttributeName();
+ groupSearchBase = config.getGroupSearchBase();
+ groupSearchFilter = config.getGroupSearchFilter();
+
+ //String userName = null;
+ if (bindDn.contains("@")) {
+ //userName = bindDn.substring(0, bindDn.indexOf("@"));
+ searchBase = bindDn.substring(bindDn.indexOf("@") + 1);
+ searchBase = "dc=".concat(searchBase);
+ searchBase = searchBase.replaceAll("\\.", ",dc=");
+ } else {
+ int dcIndex = bindDn.toLowerCase().indexOf("dc=");
+ //userName = bindDn.substring(bindDn.indexOf("=") + 1, dcIndex - 1);
+ searchBase = bindDn.substring(dcIndex);
+ }
+ } catch (Throwable t) {
+ logFile.println("ERROR: Failed to initialize the user sync properties " + t);
+ }
+ }
+
+ public void findUserProperties(LdapContext ldapContext) throws Throwable {
+ // 1. find basic user properties
+ // 2. find user search base and user search filter by passing basic attributes
+
+ findBasicUserProperties(ldapContext, true);
+
+ findAdvUserProperties(ldapContext, true);
+ }
+
+ /* Use the provided bind dn or the user search base and user search filter for sample user and determine the basic user attribute.
+ */
+ private void findBasicUserProperties(LdapContext ldapContext, boolean isOutputNeeded) throws Throwable{
+ String bindDn = config.getLdapBindDn();
+ String userSFilter = config.getUserSearchFilter();
+ String userSBase = config.getUserSearchBase();
+ Attribute userNameAttr = null;
+ Attribute groupMemberAttr;
+ SearchControls userSearchControls = new SearchControls();
+ userSearchControls.setSearchScope(config.getUserSearchScope());
+ userSearchControls.setReturningAttributes(new java.lang.String[]{"*", "+"});
+ int noOfUsers = 0;
+
+ NamingEnumeration<SearchResult> userSearchResultEnum = null;
+
+ try {
+ if (userSBase == null || userSBase.isEmpty()) {
+ if (bindDn.contains("@")) {
+ userSBase = bindDn.substring(bindDn.indexOf("@") + 1);
+ userSBase = "dc=".concat(userSBase);
+ userSBase = userSBase.replaceAll("\\.", ",dc=");
+ } else {
+ //int dcIndex = bindDn.toLowerCase().indexOf("dc=");
+ userSBase = bindDn.substring(bindDn.indexOf(",") + 1);
+ }
+ //System.out.println("Derived user search base = " + userSearchBase);
+ }
+
+ if (userSFilter == null || userSFilter.isEmpty()) {
+ if (bindDn.contains("@")) {
+ userSFilter = "userPrincipalName=" + bindDn;
+ } else {
+ int cnEndIndex = bindDn.indexOf(",");
+ userSFilter = bindDn.substring(0,cnEndIndex);
+
+ }
+ //System.out.println("Derived user search filter = " + userSearchFilter);
+ }
+
+ try {
+ userSearchResultEnum = ldapContext.search(userSBase,
+ userSFilter, userSearchControls);
+ while (userSearchResultEnum.hasMore()) {
+ if (noOfUsers >= 1) {
+ break;
+ }
+ final SearchResult userEntry = userSearchResultEnum.next();
+
+ if (userEntry == null) {
+ logFile.println("WARN: userEntry null");
+ continue;
+ }
+
+ Attributes attributes = userEntry.getAttributes();
+ if (attributes == null) {
+ logFile.println("WARN: Attributes missing for entry " + userEntry.getNameInNamespace());
+ continue;
+ }
+
+ if (userNameAttribute == null || userNameAttribute.isEmpty()) {
+ for (int i = 0; i < userNameAttrValues.length; i++) {
+ userNameAttr = attributes.get(userNameAttrValues[i]);
+ if (userNameAttr != null) {
+ userNameAttribute = userNameAttrValues[i];
+ break;
+ }
+ }
+ if (userNameAttr == null) {
+ logFile.print("WARN: Failed to find any of ( ");
+ for (int i = 0; i < userNameAttrValues.length; i++) {
+ logFile.print(userNameAttrValues[i] + " ");
+ }
+ logFile.println(") for entry " + userEntry.getNameInNamespace());
+ continue;
+ }
+ } else {
+ userNameAttr = attributes.get(userNameAttribute);
+ if (userNameAttr == null) {
+ logFile.println("WARN: Failed to find " + userNameAttribute + " for entry " + userEntry.getNameInNamespace());
+ continue;
+ }
+ }
+
+ String userName = (String) userNameAttr.get();
+
+ if (userName == null || userName.trim().isEmpty()) {
+ logFile.println("WARN: " + userNameAttribute + " empty for entry " + userEntry.getNameInNamespace());
+ continue;
+ }
+ userName = userName.toLowerCase();
+ Attribute userObjClassAttr = attributes.get("objectClass");
+ NamingEnumeration<?> userObjClassEnum = userObjClassAttr.getAll();
+ String userObjClass = null;
+ while (userObjClassEnum.hasMore()) {
+ userObjClass = userObjClassEnum.next().toString();
+ if (userObjClassName == null || userObjClassName.isEmpty()) {
+ if (userObjClass != null) {
+ for (int i = 0; i < userObjClassValues.length; i++) {
+ if (userObjClass.equalsIgnoreCase(userObjClassValues[i])) {
+ userObjClassName = userObjClass;
+ break;
+ }
+ }
+ } else {
+ logFile.println("WARN: Failed to find objectClass attribute for " + userName);
+ //continue;
+ }
+ }
+ }
+
+ if (userObjClassName == null || userObjClassName.isEmpty()) {
+ userObjClassName = userObjClass;
+ }
+
+ for (int i = 0; i < userGroupMemAttrValues.length; i++) {
+ groupMemberAttr = attributes.get(userGroupMemAttrValues[i]);
+ if (groupMemberAttr != null) {
+ userGroupMemberName = userGroupMemAttrValues[i];
+ groupName = groupMemberAttr.get(1).toString();
+ break;
+ }
+ }
+
+ noOfUsers++;
+ }
+ } catch (NamingException ne) {
+ String msg = "Exception occured while discovering basic user properties:\n" +
+ "ranger.usersync.ldap.user.nameattribute\n" +
+ "ranger.usersync.ldap.user.objectclass\n" +
+ "ranger.usersync.ldap.user.groupnameattribute\n";
+ if ((config.getUserSearchBase() != null && !config.getUserSearchBase().isEmpty()) ||
+ (config.getUserSearchFilter() != null && !config.getUserSearchFilter().isEmpty())) {
+ throw new Exception(msg + "Please verify values for ranger.usersync.ldap.user.searchbase and ranger.usersync.ldap.user.searchfilter");
+ } else {
+ throw new Exception(msg + ne);
+ }
+ }
+
+ if (isOutputNeeded) {
+ installProps.println("# Possible values for user search related properties:");
+ installProps.println("SYNC_LDAP_USER_NAME_ATTRIBUTE=" + userNameAttribute);
+ installProps.println("SYNC_LDAP_USER_OBJECT_CLASS=" + userObjClassName);
+ installProps.println("SYNC_LDAP_USER_GROUP_NAME_ATTRIBUTE=" + userGroupMemberName);
+
+ ambariProps.println("# Possible values for user search related properties:");
+ ambariProps.println("ranger.usersync.ldap.user.nameattribute=" + userNameAttribute);
+ ambariProps.println("ranger.usersync.ldap.user.objectclass=" + userObjClassName);
+ ambariProps.println("ranger.usersync.ldap.user.groupnameattribute=" + userGroupMemberName);
+ }
+ } finally {
+ try {
+ if (userSearchResultEnum != null) {
+ userSearchResultEnum.close();
+ }
+ } catch (NamingException ne) {
+ throw new Exception("Exception occured while closing user search result: " + ne);
+ }
+ }
+ }
+
+ private void findAdvUserProperties(LdapContext ldapContext, boolean isOutputNeeded) throws Throwable{
+ int noOfUsers;
+ NamingEnumeration<SearchResult> userSearchResultEnum = null;
+ SearchControls userSearchControls = new SearchControls();
+ userSearchControls.setSearchScope(config.getUserSearchScope());
+ if (userNameAttribute != null && !userNameAttribute.isEmpty()) {
+ Set<String> userSearchAttributes = new HashSet<>();
+ userSearchAttributes.add(userNameAttribute);
+ userSearchAttributes.add(userGroupMemberName);
+ userSearchAttributes.add("distinguishedName");
+ userSearchControls.setReturningAttributes(userSearchAttributes.toArray(
+ new String[userSearchAttributes.size()]));
+ } else {
+ userSearchControls.setReturningAttributes(new java.lang.String[]{"*", "+"});
+ }
+
+ String extendedUserSearchFilter = "(objectclass=" + userObjClassName + ")";
+
+ try {
+
+ HashMap<String, Integer> ouOccurences = new HashMap<>();
+
+ userSearchResultEnum = ldapContext.search(searchBase,
+ extendedUserSearchFilter, userSearchControls);
+
+ noOfUsers = 0;
+ while (userSearchResultEnum.hasMore()) {
+ if (noOfUsers >= 20) {
+ break;
+ }
+ final SearchResult userEntry = userSearchResultEnum.next();
+
+ if (userEntry == null) {
+ logFile.println("WARN: userEntry null");
+ continue;
+ }
+
+ Attributes attributes = userEntry.getAttributes();
+ if (attributes == null) {
+ logFile.println("WARN: Attributes missing for entry " + userEntry.getNameInNamespace());
+ continue;
+ }
+
+ String dnValue;
+
+ Attribute dnAttr = attributes.get("distinguishedName");
+ if (dnAttr != null) {
+ dnValue = dnAttr.get().toString();
+ String ouStr = "OU=";
+ int indexOfOU = dnValue.indexOf(ouStr);
+ if (indexOfOU > 0) {
+ dnValue = dnValue.substring(indexOfOU);
+
+ } else {
+ dnValue = dnValue.substring(dnValue.indexOf(",") + 1);
+ }
+
+ } else {
+ // If distinguishedName is not found,
+ // strip off the userName from the long name for OU or sub domain
+ dnValue = userEntry.getNameInNamespace();
+ dnValue = dnValue.substring(dnValue.indexOf(",") + 1);
+
+ }
+ //System.out.println("OU from dn = " + dnValue);
+ Integer ouOccrs = ouOccurences.get(dnValue);
+ if (ouOccrs == null) {
+ //System.out.println("value = 0");
+ ouOccrs = new Integer(0);
+ }
+ int val = ouOccrs.intValue();
+ ouOccrs = new Integer(++val);
+ ouOccurences.put(dnValue, ouOccrs);
+ noOfUsers++;
+ }
+
+ if (!ouOccurences.isEmpty()) {
+ Set<String> keys = ouOccurences.keySet();
+ int maxOUOccr = 0;
+ for (String key : keys) {
+ int ouOccurVal = ouOccurences.get(key).intValue();
+ logFile.println("INFO: No. of users from " + key + " = " + ouOccurVal);
+ if (ouOccurVal > maxOUOccr) {
+ maxOUOccr = ouOccurVal;
+ userSearchBase = key;
+ }
+ }
+ }
+ userSearchFilter = userNameAttribute + "=*";
+
+ if (isOutputNeeded) {
+ installProps.println("SYNC_LDAP_USER_SEARCH_BASE=" + userSearchBase);
+ installProps.println("SYNC_LDAP_USER_SEARCH_FILTER=" + userSearchFilter);
+
+ ambariProps.println("ranger.usersync.ldap.user.searchbase=" + userSearchBase);
+ ambariProps.println("ranger.usersync.ldap.user.searchfilter=" + userSearchFilter);
+ }
+
+ } catch (NamingException ne) {
+ String msg = "Exception occured while discovering user properties:\n" +
+ "ranger.usersync.ldap.user.searchbase\n" +
+ "ranger.usersync.ldap.user.searchfilter\n";
+ if ((config.getUserNameAttribute() != null && !config.getUserNameAttribute().isEmpty()) ||
+ (config.getUserObjectClass() != null && !config.getUserObjectClass().isEmpty()) ||
+ (config.getGroupNameAttribute() != null && !config.getGroupNameAttribute().isEmpty())) {
+ throw new Exception("Please verify values for ranger.usersync.ldap.user.nameattribute, " +
+ "ranger.usersync.ldap.user.objectclass, and" +
+ "ranger.usersync.ldap.user.groupnameattribute");
+ } else {
+ throw new Exception(msg + ne);
+ }
+ } finally {
+ if (userSearchResultEnum != null) {
+ userSearchResultEnum.close();
+ }
+ }
+ }
+
+ public void getAllUsers(LdapContext ldapContext) throws Throwable {
+ int noOfUsers = 0;
+ Attribute userNameAttr = null;
+ String groupName = null;
+ Attribute groupMemberAttr;
+ NamingEnumeration<SearchResult> userSearchResultEnum = null;
+ SearchControls userSearchControls = new SearchControls();
+ userSearchControls.setSearchScope(config.getUserSearchScope());
+ Set<String> userSearchAttributes = new HashSet<>();
+ if (userNameAttribute != null) {
+ userSearchAttributes.add(userNameAttribute);
+ }
+ if (userGroupMemberName != null) {
+ userSearchAttributes.add(userGroupMemberName);
+ }
+ if (userSearchAttributes.size() > 0) {
+ userSearchControls.setReturningAttributes(userSearchAttributes.toArray(
+ new String[userSearchAttributes.size()]));
+ } else {
+ userSearchControls.setReturningAttributes(new java.lang.String[]{"*", "+"});
+ }
+
+ String extendedUserSearchFilter = "(objectclass=" + userObjClassName + ")";
+ if (userSearchFilter != null && !userSearchFilter.trim().isEmpty()) {
+ String customFilter = userSearchFilter.trim();
+ if (!customFilter.startsWith("(")) {
+ customFilter = "(" + customFilter + ")";
+ }
+ extendedUserSearchFilter = "(&" + extendedUserSearchFilter + customFilter + ")";
+ }
+
+ byte[] cookie = null;
+ logFile.println();
+ logFile.println("INFO: First 20 Users and associated groups are:");
+
+ try {
+ do {
+
+ userSearchResultEnum = ldapContext.search(userSearchBase,
+ extendedUserSearchFilter, userSearchControls);
+
+ while (userSearchResultEnum.hasMore()) {
+ final SearchResult userEntry = userSearchResultEnum.next();
+
+ if (userEntry == null) {
+ logFile.println("WARN: userEntry null");
+ continue;
+ }
+
+ Attributes attributes = userEntry.getAttributes();
+ if (attributes == null) {
+ logFile.println("WARN: Attributes missing for entry " + userEntry.getNameInNamespace());
+ continue;
+ }
+
+ if (userNameAttribute == null || userNameAttribute.isEmpty()) {
+ for (int i = 0; i < userNameAttrValues.length; i++) {
+ userNameAttr = attributes.get(userNameAttrValues[i]);
+ if (userNameAttr != null) {
+ userNameAttribute = userNameAttrValues[i];
+ break;
+ }
+ }
+ if (userNameAttr == null) {
+ logFile.print("WARN: Failed to find any of ( ");
+ for (int i = 0; i < userNameAttrValues.length; i++) {
+ logFile.print(userNameAttrValues[i] + " ");
+ }
+ logFile.println(") for entry " + userEntry.getNameInNamespace());
+ continue;
+ }
+ } else {
+ userNameAttr = attributes.get(userNameAttribute);
+ if (userNameAttr == null) {
+ logFile.println("WARN: Failed to find " + userNameAttribute + " for entry " + userEntry.getNameInNamespace());
+ continue;
+ }
+ }
+
+ String userName = userNameAttr.get().toString();
+
+ if (userName == null || userName.trim().isEmpty()) {
+ logFile.println("WARN: " + userNameAttribute + " empty for entry " + userEntry.getNameInNamespace());
+ continue;
+ }
+ userName = userName.toLowerCase();
+
+ Set<String> groups = new HashSet<>();
+ groupMemberAttr = attributes.get(userGroupMemberName);
+
+ if (groupMemberAttr != null) {
+ NamingEnumeration<?> groupEnum = groupMemberAttr.getAll();
+ while (groupEnum.hasMore()) {
+ String groupRes = groupEnum.next().toString();
+ groups.add(groupRes);
+ if (groupName == null || groupName.isEmpty()) {
+ groupName = groupRes;
+ }
+ }
+ }
+
+ if (noOfUsers < 20) {
+ logFile.println("Username: " + userName + ", Groups: " + groups);
+ }
+ noOfUsers++;
+ }
+ // Examine the paged results control response
+ Control[] controls = ldapContext.getResponseControls();
+ if (controls != null) {
+ for (int i = 0; i < controls.length; i++) {
+ if (controls[i] instanceof PagedResultsResponseControl) {
+ PagedResultsResponseControl prrc =
+ (PagedResultsResponseControl)controls[i];
+ cookie = prrc.getCookie();
+ }
+ }
+ } else {
+ logFile.println("WARN: No controls were sent from the server");
+ }
+ // Re-activate paged results
+ if (config.isPagedResultsEnabled()) {
+ ldapContext.setRequestControls(new Control[]{
+ new PagedResultsControl(config.getPagedResultsSize(), cookie, Control.CRITICAL)});
+ }
+ } while (cookie != null);
+ logFile.println("\nINFO: Total no. of users = " + noOfUsers);
+
+ } catch (NamingException ne) {
+ String msg = "Exception occured while retreiving users\n";
+ if ((config.getUserNameAttribute() != null && !config.getUserNameAttribute().isEmpty()) ||
+ (config.getUserObjectClass() != null && !config.getUserObjectClass().isEmpty()) ||
+ (config.getGroupNameAttribute() != null && !config.getGroupNameAttribute().isEmpty()) ||
+ (config.getUserSearchBase() != null && !config.getUserSearchBase().isEmpty()) ||
+ (config.getUserSearchFilter() != null && !config.getUserSearchFilter().isEmpty())) {
+ throw new Exception("Please verify values for:\n ranger.usersync.ldap.user.nameattribute\n " +
+ "ranger.usersync.ldap.user.objectclass\n" +
+ "ranger.usersync.ldap.user.groupnameattribute\n" +
+ "ranger.usersync.ldap.user.searchbase\n" +
+ "ranger.usersync.ldap.user.searchfilter\n");
+ } else {
+ throw new Exception(msg + ne);
+ }
+ } finally {
+ if (userSearchResultEnum != null) {
+ userSearchResultEnum.close();
+ }
+ }
+ }
+
+ public void findGroupProperties(LdapContext ldapContext) throws Throwable {
+ // find basic group attributes/properties
+ // find group search base and group search filter
+ // Get all groups
+
+ if (groupName == null || groupName.isEmpty()) {
+ // Perform basic user search and get the group name from the user's group attribute name.
+ findBasicUserProperties(ldapContext, false);
+ }
+
+ if (groupName == null || groupName.isEmpty()) {
+ // Perform adv user search and get the group name from the user's group attribute name.
+ findAdvUserProperties(ldapContext, false);
+ }
+
+ findBasicGroupProperties(ldapContext);
+
+ findAdvGroupProperties(ldapContext);
+ }
+
+ private void findBasicGroupProperties(LdapContext ldapContext) throws Throwable {
+ int noOfGroups;
+ Attribute groupNameAttr;
+ String groupBase;
+ String groupFilter;
+ Attribute groupMemberAttr;
+ NamingEnumeration<SearchResult> groupSearchResultEnum = null;
+ SearchControls groupSearchControls = new SearchControls();
+ groupSearchControls.setSearchScope(config.getGroupSearchScope());
+
+ try {
+ int baseIndex = groupName.indexOf(",");
+ groupBase = groupName.substring(baseIndex + 1);
+ groupFilter = groupName.substring(0, baseIndex);
+ groupSearchResultEnum = ldapContext.search(groupBase, groupFilter,
+ groupSearchControls);
+
+ noOfGroups = 0;
+ while (groupSearchResultEnum.hasMore()) {
+ if (noOfGroups >= 1) {
+ break;
+ }
+
+ final SearchResult groupEntry = groupSearchResultEnum.next();
+ if (groupEntry == null) {
+ continue;
+ }
+ Attributes groupAttributes = groupEntry.getAttributes();
+ if (groupAttributes == null) {
+ logFile.println("WARN: Attributes missing for entry " + groupEntry.getNameInNamespace());
+ continue;
+ }
+
+ Attribute groupObjClassAttr = groupAttributes.get("objectClass");
+ if (groupObjClassAttr != null) {
+ NamingEnumeration<?> groupObjClassEnum = groupObjClassAttr.getAll();
+ while (groupObjClassEnum.hasMore()) {
+ String groupObjClassStr = groupObjClassEnum.next().toString();
+ for (int i = 0; i < groupObjectClassValues.length; i++) {
+ if (groupObjClassStr.equalsIgnoreCase(groupObjectClassValues[i])) {
+ groupObjClassName = groupObjClassStr;
+ break;
+ }
+ }
+ }
+ } else {
+ logFile.println("WARN: Failed to find group objectClass attribute for " + groupEntry.getNameInNamespace());
+ continue;
+ }
+
+ if (groupNameAttrName == null || groupNameAttrName.isEmpty()) {
+
+ for (int i = 0; i < groupNameAttrValues.length; i++) {
+ groupNameAttr = groupAttributes.get(groupNameAttrValues[i]);
+ if (groupNameAttr != null) {
+ groupNameAttrName = groupNameAttrValues[i];
+ break;
+ }
+ }
+ }
+
+ for (int i = 0; i < groupMemAttrValues.length; i++) {
+ groupMemberAttr = groupAttributes.get(groupMemAttrValues[i]);
+ if (groupMemberAttr != null) {
+ groupMemberName = groupMemAttrValues[i];
+ break;
+ }
+ }
+ noOfGroups++;
+ }
+
+ installProps.println("\n# Possible values for group search related properties:");
+ installProps.println("SYNC_GROUP_MEMBER_ATTRIBUTE_NAME=" + groupMemberName);
+ installProps.println("SYNC_GROUP_NAME_ATTRIBUTE=" + groupNameAttrName);
+ installProps.println("SYNC_GROUP_OBJECT_CLASS=" + groupObjClassName);
+
+ ambariProps.println("\n# Possible values for group search related properties:");
+ ambariProps.println("ranger.usersync.group.memberattributename=" + groupMemberName);
+ ambariProps.println("ranger.usersync.group.nameattribute=" + groupNameAttrName);
+ ambariProps.println("ranger.usersync.group.objectclass=" + groupObjClassName);
+
+ } finally {
+
+ if (groupSearchResultEnum != null) {
+ groupSearchResultEnum.close();
+ }
+ }
+ }
+
+ private void findAdvGroupProperties(LdapContext ldapContext) throws Throwable {
+ int noOfGroups = 0;
+ NamingEnumeration<SearchResult> groupSearchResultEnum = null;
+ SearchControls groupSearchControls = new SearchControls();
+ groupSearchControls.setSearchScope(config.getGroupSearchScope());
+ Set<String> groupSearchAttributes = new HashSet<>();
+ groupSearchAttributes.add(groupNameAttrName);
+ groupSearchAttributes.add(groupMemberName);
+ groupSearchAttributes.add("distinguishedName");
+ groupSearchControls.setReturningAttributes(groupSearchAttributes.toArray(
+ new String[groupSearchAttributes.size()]));
+ String extendedGroupSearchFilter = "(objectclass=" + groupObjClassName + ")";
+
+ try {
+ HashMap<String, Integer> ouOccurences = new HashMap<>();
+
+ groupSearchResultEnum = ldapContext.search(searchBase, extendedGroupSearchFilter,
+ groupSearchControls);
+
+ while (groupSearchResultEnum.hasMore()) {
+ if (noOfGroups >= 20) {
+ break;
+ }
+
+ final SearchResult groupEntry = groupSearchResultEnum.next();
+ if (groupEntry == null) {
+ continue;
+ }
+ Attributes groupAttributes = groupEntry.getAttributes();
+ if (groupAttributes == null) {
+ logFile.println("WARN: Attributes missing for entry " + groupEntry.getNameInNamespace());
+ continue;
+ }
+
+ String dnValue;
+
+ Attribute dnAttr = groupAttributes.get("distinguishedName");
+ if (dnAttr != null) {
+ dnValue = dnAttr.get().toString();
+ String ouStr = "OU=";
+ int indexOfOU = dnValue.indexOf(ouStr);
+ if (indexOfOU > 0) {
+ dnValue = dnValue.substring(indexOfOU);
+
+ } else {
+ dnValue = dnValue.substring(dnValue.indexOf(",") + 1);
+ }
+
+ } else {
+ // If distinguishedName is not found,
+ // strip off the userName from the long name for OU or sub domain
+ dnValue = groupEntry.getNameInNamespace();
+ dnValue = dnValue.substring(dnValue.indexOf(",") + 1);
+ }
+ //System.out.println("OU from dn = " + dnValue);
+ Integer ouOccrs = ouOccurences.get(dnValue);
+ if (ouOccrs == null) {
+ //System.out.println("value = 0");
+ ouOccrs = new Integer(0);
+ }
+ int val = ouOccrs.intValue();
+ ouOccrs = new Integer(++val);
+ ouOccurences.put(dnValue, ouOccrs);
+
+ noOfGroups++;
+ }
+
+ if (!ouOccurences.isEmpty()) {
+ Set<String> keys = ouOccurences.keySet();
+ int maxOUOccr = 0;
+ for (String key : keys) {
+ int ouOccurVal = ouOccurences.get(key).intValue();
+ logFile.println("INFO: No. of groups from " + key + " = " + ouOccurVal);
+ if (ouOccurVal > maxOUOccr) {
+ maxOUOccr = ouOccurVal;
+ groupSearchBase = key;
+ }
+ }
+ }
+
+ groupSearchFilter = groupNameAttrName + "=*";
+
+ installProps.println("SYNC_GROUP_SEARCH_BASE=" + groupSearchBase);
+ installProps.println("SYNC_LDAP_GROUP_SEARCH_FILTER=" + groupSearchFilter);
+
+ ambariProps.println("ranger.usersync.group.searchbase=" + groupSearchBase);
+ ambariProps.println("ranger.usersync.group.searchfilter=" + groupSearchFilter);
+
+ } finally {
+
+ if (groupSearchResultEnum != null) {
+ groupSearchResultEnum.close();
+ }
+ }
+ }
+
+ public void getAllGroups(LdapContext ldapContext) throws Throwable {
+ int noOfGroups = 0;
+ Attribute groupNameAttr;
+ Attribute groupMemberAttr;
+ NamingEnumeration<SearchResult> groupSearchResultEnum = null;
+ SearchControls groupSearchControls = new SearchControls();
+ groupSearchControls.setSearchScope(config.getGroupSearchScope());
+ Set<String> groupSearchAttributes = new HashSet<>();
+ groupSearchAttributes.add(groupNameAttrName);
+ groupSearchAttributes.add(groupMemberName);
+ groupSearchAttributes.add("distinguishedName");
+ groupSearchControls.setReturningAttributes(groupSearchAttributes.toArray(
+ new String[groupSearchAttributes.size()]));
+
+ String extendedGroupSearchFilter= "(objectclass=" + groupObjClassName + ")";
+ if (groupSearchFilter != null && !groupSearchFilter.trim().isEmpty()) {
+ String customFilter = groupSearchFilter.trim();
+ if (!customFilter.startsWith("(")) {
+ customFilter = "(" + customFilter + ")";
+ }
+ extendedGroupSearchFilter = "(&" + extendedGroupSearchFilter + customFilter + ")";
+ }
+
+ try {
+
+ groupSearchResultEnum = ldapContext.search(groupSearchBase, extendedGroupSearchFilter,
+ groupSearchControls);
+
+ logFile.println("\nINFO: First 20 Groups and associated Users are:");
+
+ while (groupSearchResultEnum.hasMore()) {
+ final SearchResult groupEntry = groupSearchResultEnum.next();
+ if (groupEntry == null) {
+ continue;
+ }
+ Attributes groupAttributes = groupEntry.getAttributes();
+ if (groupAttributes == null) {
+ logFile.println("WARN: Attributes missing for entry " + groupEntry.getNameInNamespace());
+ continue;
+ }
+
+ groupMemberAttr = groupAttributes.get(groupMemberName);
+
+ Set<String> users = new HashSet<>();
+ if (groupMemberAttr != null) {
+ NamingEnumeration<?> userEnum = groupMemberAttr.getAll();
+ while (userEnum.hasMore()) {
+ String userRes = userEnum.next().toString();
+ users.add(userRes);
+ }
+ }
+
+ groupNameAttr = groupAttributes.get(groupNameAttrName);
+ if (noOfGroups < 20) {
+ logFile.println("Group name: " + groupNameAttr.get().toString() + ", Users: " + users);
+ }
+ noOfGroups++;
+ }
+
+ logFile.println("\nINFO: Total no. of groups = " + noOfGroups);
+
+ } catch (NamingException ne) {
+ String msg = "Exception occured while retreiving groups\n";
+ if ((config.getGroupNameAttribute() != null && !config.getGroupNameAttribute().isEmpty()) ||
+ (config.getGroupObjectClass() != null && !config.getGroupObjectClass().isEmpty()) ||
+ (config.getUserGroupMemberAttributeName() != null && !config.getUserGroupMemberAttributeName().isEmpty()) ||
+ (config.getGroupSearchBase() != null && !config.getGroupSearchBase().isEmpty()) ||
+ (config.getGroupSearchFilter() != null && !config.getGroupSearchFilter().isEmpty())) {
+ throw new Exception("Please verify values for:\n ranger.usersync.group.memberattributename\n " +
+ "ranger.usersync.group.nameattribute\n" +
+ "ranger.usersync.group.objectclass\n" +
+ "ranger.usersync.group.searchbase\n" +
+ "ranger.usersync.group.searchfilter\n");
+ } else {
+ throw new Exception(msg + ne);
+ }
+ } finally {
+
+ if (groupSearchResultEnum != null) {
+ groupSearchResultEnum.close();
+ }
+ }
+ }
+}
+
+
[2/3] incubator-ranger git commit: RANGER-652: Adding support for
ldap connection check tool
Posted by ve...@apache.org.
RANGER-652: Adding support for ldap connection check tool
Signed-off-by: Velmurugan Periasamy <ve...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/incubator-ranger/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ranger/commit/5ce7cc38
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ranger/tree/5ce7cc38
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ranger/diff/5ce7cc38
Branch: refs/heads/master
Commit: 5ce7cc38b2628380deab1f78bfa373f389c72faa
Parents: c22bdec
Author: Sailaja Polavarapu <sp...@hortonworks.com>
Authored: Fri Oct 9 10:07:01 2015 -0700
Committer: Velmurugan Periasamy <ve...@apache.org>
Committed: Sat Oct 10 12:28:32 2015 -0400
----------------------------------------------------------------------
src/main/assembly/usersync.xml | 36 +
.../ldapconfigcheck/conf/input.properties | 63 ++
.../ldapconfigchecktool/ldapconfigcheck/pom.xml | 130 +++
.../ldapconfigcheck/scripts/run.sh | 72 ++
.../ldapconfigcheck/AuthenticationCheck.java | 208 +++++
.../ldapconfigcheck/CommandLineOptions.java | 230 +++++
.../ranger/ldapconfigcheck/LdapConfig.java | 436 ++++++++++
.../ldapconfigcheck/LdapConfigCheckMain.java | 241 ++++++
.../apache/ranger/ldapconfigcheck/UserSync.java | 860 +++++++++++++++++++
9 files changed, 2276 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/5ce7cc38/src/main/assembly/usersync.xml
----------------------------------------------------------------------
diff --git a/src/main/assembly/usersync.xml b/src/main/assembly/usersync.xml
index 8c2600e..161a443 100644
--- a/src/main/assembly/usersync.xml
+++ b/src/main/assembly/usersync.xml
@@ -134,6 +134,42 @@
</includes>
<fileMode>544</fileMode>
</fileSet>
+ <fileSet>
+ <directoryMode>755</directoryMode>
+ <fileMode>755</fileMode>
+ <outputDirectory>/ldaptool</outputDirectory>
+ <directory>ugsync/ldapconfigchecktool/ldapconfigcheck/scripts</directory>
+ <includes>
+ <include>run.sh</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directoryMode>755</directoryMode>
+ <fileMode>644</fileMode>
+ <outputDirectory>/ldaptool/lib</outputDirectory>
+ <directory>ugsync/ldapconfigchecktool/ldapconfigcheck/target</directory>
+ <includes>
+ <include>ldapconfigcheck.jar</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directoryMode>755</directoryMode>
+ <fileMode>644</fileMode>
+ <outputDirectory>/ldaptool/conf</outputDirectory>
+ <directory>ugsync/ldapconfigchecktool/ldapconfigcheck/conf</directory>
+ <includes>
+ <include>input.properties</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directoryMode>755</directoryMode>
+ <fileMode>644</fileMode>
+ <outputDirectory>/ldaptool/output</outputDirectory>
+ <directory>ugsync/ldapconfigchecktool/ldapconfigcheck/conf</directory>
+ <excludes>
+ <exclude>input.properties</exclude>
+ </excludes>
+ </fileSet>
</fileSets>
<files>
<file>
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/5ce7cc38/ugsync/ldapconfigchecktool/ldapconfigcheck/conf/input.properties
----------------------------------------------------------------------
diff --git a/ugsync/ldapconfigchecktool/ldapconfigcheck/conf/input.properties b/ugsync/ldapconfigchecktool/ldapconfigcheck/conf/input.properties
new file mode 100755
index 0000000..dc6fc59
--- /dev/null
+++ b/ugsync/ldapconfigchecktool/ldapconfigcheck/conf/input.properties
@@ -0,0 +1,63 @@
+# 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.
+#
+# Mandatory ldap configuration properties.
+ranger.usersync.ldap.url=
+ranger.usersync.ldap.binddn=
+ranger.usersync.ldap.ldapbindpassword=
+
+# Mandatory only for openLdap
+ranger.usersync.ldap.user.searchbase=
+ranger.usersync.ldap.user.searchfilter=
+
+# For verifying authentication please provide sample username and password
+ranger.admin.auth.sampleuser=
+ranger.admin.auth.samplepassword=
+
+# Optional properties will be determined based on the above search
+# User attributes
+ranger.usersync.ldap.user.nameattribute=
+ranger.usersync.ldap.user.objectclass=
+ranger.usersync.ldap.user.groupnameattribute=
+
+# Group attributes
+ranger.usersync.group.searchenabled=false
+ranger.usersync.group.memberattributename=
+ranger.usersync.group.nameattribute=
+ranger.usersync.group.objectclass=
+ranger.usersync.group.searchbase=
+ranger.usersync.group.searchfilter=
+
+# Other UserSync related attributes
+ranger.usersync.ldap.authentication.mechanism=simple
+ranger.usersync.pagedresultsenabled=true
+ranger.usersync.pagedresultssize=500
+ranger.usersync.ldap.username.caseconversion=lower
+ranger.usersync.ldap.groupname.caseconversion=lower
+ranger.usersync.ldap.user.searchscope=sub
+ranger.usersync.group.searchscope=sub
+
+ranger.usersync.credstore.filename=
+ranger.usersync.ldap.bindalias=
+ranger.usersync.ldap.searchBase=
+ranger.usersync.group.usermapsyncenabled=false
+
+# Authentication properties
+ranger.authentication.method=
+ranger.ldap.ad.domain=
+ranger.ldap.user.dnpattern=
+ranger.ldap.group.roleattribute=
+ranger.ldap.group.searchbase=
+ranger.ldap.group.searchfilter=
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/5ce7cc38/ugsync/ldapconfigchecktool/ldapconfigcheck/pom.xml
----------------------------------------------------------------------
diff --git a/ugsync/ldapconfigchecktool/ldapconfigcheck/pom.xml b/ugsync/ldapconfigchecktool/ldapconfigcheck/pom.xml
new file mode 100644
index 0000000..a0971f2
--- /dev/null
+++ b/ugsync/ldapconfigchecktool/ldapconfigcheck/pom.xml
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.ranger</groupId>
+ <artifactId>ranger</artifactId>
+ <version>0.5.0</version>
+ <relativePath>..</relativePath>
+ </parent>
+
+ <artifactId>ldapconfigcheck</artifactId>
+
+ <packaging>jar</packaging>
+ <name>Ldap Config Check Tool</name>
+ <description>Ldap configuration check tool</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>commons-cli</groupId>
+ <artifactId>commons-cli</artifactId>
+ <version>${commons.cli.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-configuration</groupId>
+ <artifactId>commons-configuration</artifactId>
+ <version>${commons.configuration.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ <version>${commons.lang.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ <version>${commons.logging.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-beans</artifactId>
+ <version>${springframework.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-context</artifactId>
+ <version>${springframework.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-core</artifactId>
+ <version>${springframework.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-tx</artifactId>
+ <version>${springframework.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.ldap</groupId>
+ <artifactId>spring-ldap-core</artifactId>
+ <version>${spring-ldap-core.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.security</groupId>
+ <artifactId>spring-security-core</artifactId>
+ <version>${springframework.security.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.security</groupId>
+ <artifactId>spring-security-ldap</artifactId>
+ <version>${springframework.security.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.ranger</groupId>
+ <artifactId>credentialbuilder</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.ranger</groupId>
+ <artifactId>ranger-util</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ </dependencies>
+ <build>
+ <finalName>ldapconfigcheck</finalName>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-shade-plugin</artifactId>
+ <version>2.2</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ <configuration>
+ <transformers>
+ <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+ <mainClass>org.apache.ranger.ldapconfigcheck.LdapConfigCheckMain</mainClass>
+ </transformer>
+ </transformers>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/5ce7cc38/ugsync/ldapconfigchecktool/ldapconfigcheck/scripts/run.sh
----------------------------------------------------------------------
diff --git a/ugsync/ldapconfigchecktool/ldapconfigcheck/scripts/run.sh b/ugsync/ldapconfigchecktool/ldapconfigcheck/scripts/run.sh
new file mode 100755
index 0000000..787e216
--- /dev/null
+++ b/ugsync/ldapconfigchecktool/ldapconfigcheck/scripts/run.sh
@@ -0,0 +1,72 @@
+#!/bin/bash
+# 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.
+
+
+AUTH=1
+
+usage() {
+ echo "usage: run.sh
+ -noauth ignore authentication properties
+ -d <arg> {all|users|groups}
+ -h show help.
+ -i <arg> Input file name
+ -o <arg> Output directory
+ -r <arg> {all|users|groups}"
+ exit 1
+}
+
+cdir=`pwd`
+cp="${cdir}/lib/*:${cdir}/conf"
+OUTDIR="${cdir}/output/"
+JAVA_CMD="java -cp ${cdir}/lib/ldapconfigcheck.jar:${cp} org.apache.ranger.ldapconfigcheck.LdapConfigCheckMain"
+
+while getopts "i:o:d:r:noauthh" opt; do
+ case $opt in
+ i) INFILE=$OPTARG
+ JAVA_CMD="$JAVA_CMD -i $OPTARG"
+ ;;
+ o) OUTDIR=$OPTARG
+ ;;
+ d) DISCOVER=$OPTARG
+ JAVA_CMD="$JAVA_CMD -d $OPTARG"
+ ;;
+ r) RETRIEVE=$OPTARG
+ JAVA_CMD="$JAVA_CMD -r $OPTARG"
+ ;;
+ noauth) AUTH=0
+ JAVA_CMD="$JAVA_CMD -noauth"
+ ;;
+ h) usage
+ ;;
+ \?) echo -e \\n"Option -$OPTARG not allowed."
+ usage
+ ;;
+ esac
+done
+
+JAVA_CMD="$JAVA_CMD -o $OUTDIR"
+
+echo "JAVA commnad = $JAVA_CMD"
+
+if [ "${JAVA_HOME}" != "" ]
+then
+ export JAVA_HOME
+ PATH="${JAVA_HOME}/bin:${PATH}"
+ export PATH
+fi
+
+cd ${cdir}
+$JAVA_CMD
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/5ce7cc38/ugsync/ldapconfigchecktool/ldapconfigcheck/src/main/java/org/apache/ranger/ldapconfigcheck/AuthenticationCheck.java
----------------------------------------------------------------------
diff --git a/ugsync/ldapconfigchecktool/ldapconfigcheck/src/main/java/org/apache/ranger/ldapconfigcheck/AuthenticationCheck.java b/ugsync/ldapconfigchecktool/ldapconfigcheck/src/main/java/org/apache/ranger/ldapconfigcheck/AuthenticationCheck.java
new file mode 100644
index 0000000..f39f782
--- /dev/null
+++ b/ugsync/ldapconfigchecktool/ldapconfigcheck/src/main/java/org/apache/ranger/ldapconfigcheck/AuthenticationCheck.java
@@ -0,0 +1,208 @@
+/*
+ * 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.ranger.ldapconfigcheck;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+import org.springframework.ldap.core.support.LdapContextSource;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
+import org.springframework.security.ldap.authentication.BindAuthenticator;
+import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
+
+
+public class AuthenticationCheck {
+ private String ldapUrl = null;
+ private String authMethod = "NONE";
+ private String adDomain = null;
+ private String userDnPattern = null;
+ private String roleAttribute = null;
+ private String groupSearchBase = null;
+ private String groupSearchFilter = null;
+
+ private PrintStream logFile = null;
+ private PrintStream ambariProps = null;
+ private PrintStream installProps = null;
+
+ public AuthenticationCheck(String ldapUrl, UserSync userSyncObj, PrintStream logFile,
+ PrintStream ambariProps, PrintStream installProps) {
+
+ this.logFile = logFile;
+ this.ambariProps = ambariProps;
+ this.installProps = installProps;
+
+ if (userSyncObj.getUserNameAttribute().equalsIgnoreCase("sAMAccountName")) {
+ authMethod = "AD";
+ } else {
+ authMethod = "LDAP";
+ }
+ this.ldapUrl = ldapUrl;
+ adDomain = userSyncObj.getSearchBase();
+ userDnPattern = userSyncObj.getUserNameAttribute() + "={0}," + userSyncObj.getUserSearchBase();
+ roleAttribute = userSyncObj.getGroupNameAttrName();
+ groupSearchBase = userSyncObj.getGroupSearchBase();
+ groupSearchFilter = userSyncObj.getGroupMemberName() + "=" + userDnPattern;
+
+ }
+
+ public void discoverAuthProperties() {
+
+ ambariProps.println("\n# Possible values for authetication properties:");
+ installProps.println("\n# Possible values for authetication properties:");
+ if (authMethod.equalsIgnoreCase("AD")) {
+ installProps.println("xa_ldap_ad_url=" + ldapUrl);
+ installProps.println("xa_ldap_ad_domain=" + adDomain);
+ } else {
+ installProps.println("xa_ldap_url=" + ldapUrl);
+ installProps.println("xa_ldap_userDNpattern=" + userDnPattern);
+ installProps.println("xa_ldap_groupRoleAttribute=" + roleAttribute);
+ installProps.println("xa_ldap_groupSearchBase=" + groupSearchBase);
+ installProps.println("xa_ldap_groupSearchFilter=" + groupSearchFilter);
+ }
+
+ ambariProps.println("ranger.authentication.method=" + authMethod);
+ if (authMethod.equalsIgnoreCase("AD")) {
+ ambariProps.println("ranger.ldap.ad.url=" + ldapUrl);
+ ambariProps.println("ranger.ldap.ad.domain=" + adDomain);
+ } else {
+ ambariProps.println("ranger.ldap.url=" + ldapUrl);
+ ambariProps.println("ranger.ldap.user.dnpattern=" + userDnPattern);
+ ambariProps.println("ranger.ldap.group.roleattribute=" + roleAttribute);
+ ambariProps.println("ranger.ldap.group.searchbase=" + groupSearchBase);
+ ambariProps.println("ranger.ldap.group.searchfilter=" + groupSearchFilter);
+ }
+ }
+
+ public boolean isAuthenticated(String ldapUrl, String bindDn, String bindPassword, String userName,
+ String userPassword) {
+ boolean isAuthenticated = false;
+ //Verify Authentication
+ Authentication authentication;
+ if (authMethod.equalsIgnoreCase("AD")) {
+ authentication = getADBindAuthentication(ldapUrl, bindDn, bindPassword, userName, userPassword);
+ } else {
+ authentication = getLdapBindAuthentication(ldapUrl, bindDn, bindPassword, userName, userPassword);
+ }
+ if (authentication != null) {
+ isAuthenticated = authentication.isAuthenticated();
+ }
+
+ return isAuthenticated;
+ }
+
+ private Authentication getADBindAuthentication(String ldapUrl, String bindDn, String bindPassword,
+ String userName, String userPassword) {
+ Authentication result = null;
+ try {
+ LdapContextSource ldapContextSource = new DefaultSpringSecurityContextSource(ldapUrl);
+ ldapContextSource.setUserDn(bindDn);
+ ldapContextSource.setPassword(bindPassword);
+ ldapContextSource.setReferral("follow");
+ ldapContextSource.setCacheEnvironmentProperties(true);
+ ldapContextSource.setAnonymousReadOnly(false);
+ ldapContextSource.setPooled(true);
+ ldapContextSource.afterPropertiesSet();
+
+ String searchFilter="(sAMAccountName={0})";
+ FilterBasedLdapUserSearch userSearch=new FilterBasedLdapUserSearch(adDomain, searchFilter,ldapContextSource);
+ userSearch.setSearchSubtree(true);
+
+ BindAuthenticator bindAuthenticator = new BindAuthenticator(ldapContextSource);
+ bindAuthenticator.setUserSearch(userSearch);
+ bindAuthenticator.afterPropertiesSet();
+
+ LdapAuthenticationProvider ldapAuthenticationProvider = new LdapAuthenticationProvider(bindAuthenticator);
+
+ if (userName != null && userPassword != null && !userName.trim().isEmpty() && !userPassword.trim().isEmpty()) {
+ final List<GrantedAuthority> grantedAuths = new ArrayList<>();
+ grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
+ final UserDetails principal = new User(userName, userPassword, grantedAuths);
+ final Authentication finalAuthentication = new UsernamePasswordAuthenticationToken(principal, userPassword, grantedAuths);
+
+ result = ldapAuthenticationProvider.authenticate(finalAuthentication);
+ }
+
+ } catch (BadCredentialsException bce) {
+ logFile.println("ERROR: LDAP Authentication Failed. Please verify values for ranger.admin.auth.sampleuser and " +
+ "ranger.admin.auth.samplepassword\n");
+ } catch (Exception e) {
+ logFile.println("ERROR: LDAP Authentication Failed: " + e);
+ }
+ return result;
+ }
+
+ private Authentication getLdapBindAuthentication(String ldapUrl, String bindDn, String bindPassword,
+ String userName, String userPassword) {
+ Authentication result = null;
+ try {
+ LdapContextSource ldapContextSource = new DefaultSpringSecurityContextSource(ldapUrl);
+ ldapContextSource.setUserDn(bindDn);
+ ldapContextSource.setPassword(bindPassword);
+ ldapContextSource.setReferral("follow");
+ ldapContextSource.setCacheEnvironmentProperties(false);
+ ldapContextSource.setAnonymousReadOnly(true);
+ ldapContextSource.setPooled(true);
+ ldapContextSource.afterPropertiesSet();
+
+ DefaultLdapAuthoritiesPopulator defaultLdapAuthoritiesPopulator = new DefaultLdapAuthoritiesPopulator(ldapContextSource, groupSearchBase);
+ defaultLdapAuthoritiesPopulator.setGroupRoleAttribute(roleAttribute);
+ defaultLdapAuthoritiesPopulator.setGroupSearchFilter(groupSearchFilter);
+ defaultLdapAuthoritiesPopulator.setIgnorePartialResultException(true);
+
+ String searchFilter="(uid={0})";
+ FilterBasedLdapUserSearch userSearch=new FilterBasedLdapUserSearch(adDomain, searchFilter,ldapContextSource);
+ userSearch.setSearchSubtree(true);
+
+ BindAuthenticator bindAuthenticator = new BindAuthenticator(ldapContextSource);
+ bindAuthenticator.setUserSearch(userSearch);
+ String[] userDnPatterns = new String[] { userDnPattern };
+ bindAuthenticator.setUserDnPatterns(userDnPatterns);
+ bindAuthenticator.afterPropertiesSet();
+
+ LdapAuthenticationProvider ldapAuthenticationProvider = new LdapAuthenticationProvider(bindAuthenticator,defaultLdapAuthoritiesPopulator);
+
+ if (userName != null && userPassword != null && !userName.trim().isEmpty()&& !userPassword.trim().isEmpty()) {
+ final List<GrantedAuthority> grantedAuths = new ArrayList<>();
+ grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
+ final UserDetails principal = new User(userName, userPassword,grantedAuths);
+ final Authentication finalAuthentication = new UsernamePasswordAuthenticationToken(principal, userPassword, grantedAuths);
+
+ result = ldapAuthenticationProvider.authenticate(finalAuthentication);
+ }
+ } catch (BadCredentialsException bce) {
+ logFile.println("ERROR: LDAP Authentication Failed. Please verify values for ranger.admin.auth.sampleuser and " +
+ "ranger.admin.auth.samplepassword\n");
+ } catch (Exception e) {
+ logFile.println("ERROR: LDAP Authentication Failed: " + e);
+ }
+ return result;
+ }
+}
+
+
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/5ce7cc38/ugsync/ldapconfigchecktool/ldapconfigcheck/src/main/java/org/apache/ranger/ldapconfigcheck/CommandLineOptions.java
----------------------------------------------------------------------
diff --git a/ugsync/ldapconfigchecktool/ldapconfigcheck/src/main/java/org/apache/ranger/ldapconfigcheck/CommandLineOptions.java b/ugsync/ldapconfigchecktool/ldapconfigcheck/src/main/java/org/apache/ranger/ldapconfigcheck/CommandLineOptions.java
new file mode 100644
index 0000000..790330f
--- /dev/null
+++ b/ugsync/ldapconfigchecktool/ldapconfigcheck/src/main/java/org/apache/ranger/ldapconfigcheck/CommandLineOptions.java
@@ -0,0 +1,230 @@
+/*
+ * 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.ranger.ldapconfigcheck;
+
+import org.apache.commons.cli.*;
+import java.io.Console;
+
+public class CommandLineOptions {
+
+ private String[] args = null;
+ private Options options = new Options();
+ private String input = null;
+ private String output = null;
+ private String discoverProperties;
+ private String retrieveValues = null;
+ private boolean isAuthEnabled = true;
+ private String ldapUrl = "";
+ private String bindDn = "";
+ private String bindPassword = "";
+ private String userSearchBase = "";
+ private String userSearchFilter = "";
+ private String authUser = "";
+ private String authPass = "";
+
+ public CommandLineOptions(String[] args) {
+ this.args = args;
+ options.addOption("h", "help", false, "show help.");
+ options.addOption("i", "inputfile", true, "Input file name");
+ options.addOption("o", "outputdir", true, "Output directory");
+ options.addOption("d", "discoverProperties", true, "{all|users|groups}");
+ options.addOption("r", "retrieve", true, "{all|users|groups}");
+ options.addOption("noauth", "noAuthentication", false, "Ignore authentication properties");
+ }
+
+ public void parse() {
+ CommandLineParser parser = new BasicParser();
+ try {
+ CommandLine cmd = parser.parse(options, args);
+ if (cmd.hasOption("h")) {
+
+ }
+
+
+ if (cmd.hasOption("o")) {
+ output = cmd.getOptionValue("o");
+ } else {
+ System.out.println("Missing o option for output directory");
+ help();
+ }
+
+ if (cmd.hasOption("d")) {
+ discoverProperties = cmd.getOptionValue("d");
+ if (discoverProperties == null || (!discoverProperties.equalsIgnoreCase("all") &&
+ !discoverProperties.equalsIgnoreCase("users") && !discoverProperties.equalsIgnoreCase("groups"))) {
+ System.out.println("Unsupported value for option d");
+ help();
+ }
+ }
+
+ if (cmd.hasOption("r")) {
+ retrieveValues = cmd.getOptionValue("r");
+ if (retrieveValues == null || (!retrieveValues.equalsIgnoreCase("all")
+ && !retrieveValues.equalsIgnoreCase("users") && !retrieveValues.equalsIgnoreCase("groups"))) {
+ System.out.println("Unsupported value for option r");
+ help();
+ }
+ } else {
+ if (discoverProperties == null || discoverProperties.isEmpty()) {
+ System.out.println("Default to discover all usersync properties");
+ //help();
+ // If "d" or "r" option is not specified, then default to discover all usersync properties
+ discoverProperties = "all";
+ }
+ }
+
+ if (cmd.hasOption("noauth")) {
+ isAuthEnabled = false;
+ }
+
+ if (cmd.hasOption("i")) {
+ input = cmd.getOptionValue("i");
+ if (input == null || input.isEmpty()) {
+ System.out.println("Please specify the input properties file name");
+ help();
+ }
+
+ } else {
+ // Read the properties from CLI and write to the input properties file.
+ input = LdapConfig.CONFIG_FILE;
+ readCLI();
+ }
+
+ } catch (ParseException pe) {
+ System.out.println("Failed to parse command line arguments " + pe);
+ help();
+ }
+ }
+
+ public void help() {
+ // This prints out some help
+ HelpFormatter formater = new HelpFormatter();
+ formater.printHelp("ldapConfigCheck", options);
+ System.exit(0);
+ }
+
+ public String getInput() {
+ return input;
+ }
+
+ public String getOutput() {
+
+ return output;
+ }
+
+ public String getDiscoverProperties() {
+ return discoverProperties;
+ }
+
+ public boolean isAuthEnabled() {
+ return isAuthEnabled;
+ }
+
+ public String getRetrieveValues() {
+ return retrieveValues;
+ }
+
+ private void readCLI() {
+ boolean repeat;
+ Console console = System.console();
+ do {
+ repeat = false;
+ System.out.print("Ldap url [ldap://ldap.example.com:389]: ");
+ ldapUrl = console.readLine();
+ if (ldapUrl == null || ldapUrl.isEmpty()) {
+ System.out.println("Please enter valid ldap url.");
+ repeat = true;
+ }
+ } while (repeat == true);
+ do {
+ repeat = false;
+ System.out.print("Bind DN [cn=admin,ou=users,dc=example,dc=com]: ");
+ bindDn = console.readLine();
+ if (bindDn == null || bindDn.isEmpty()) {
+ System.out.println("Please enter valid bindDn.");
+ repeat = true;
+ }
+ } while (repeat == true);
+ do {
+ repeat = false;
+ System.out.print("Bind Password: ");
+ char[] password = console.readPassword();
+ bindPassword = String.valueOf(password);
+ if (bindPassword == null || bindPassword.isEmpty()) {
+ System.out.println("Bind Password can't be empty.");
+ repeat = true;
+ }
+ } while (repeat == true);
+ System.out.print("User Search Base [ou=users,dc=example,dc=com]: ");
+ userSearchBase = console.readLine();
+ System.out.print("User Search Filter [cn=user1]: ");
+ userSearchFilter = console.readLine();
+
+ if (isAuthEnabled) {
+ do {
+ repeat = false;
+ System.out.print("Sample Authentication User [user1]: ");
+ authUser = console.readLine();
+ if (authUser == null || authUser.isEmpty()) {
+ System.out.println("Sample Authentication user must not be empty!");
+ repeat = true;
+ }
+ } while (repeat == true);
+ do {
+ repeat = false;
+ System.out.print("Sample Authentication Password: ");
+ char[] password = console.readPassword();
+ authPass = String.valueOf(password);
+ if (authPass == null || authPass.isEmpty()) {
+ System.out.println("Sample Authentication password must not be empty!");
+ repeat = true;
+ }
+ } while (repeat == true);
+ }
+ }
+
+ public String getLdapUrl() {
+ return ldapUrl;
+ }
+
+ public String getBindDn() {
+ return bindDn;
+ }
+
+ public String getBindPassword() {
+ return bindPassword;
+ }
+
+ public String getUserSearchBase() {
+ return userSearchBase;
+ }
+
+ public String getUserSearchFilter() {
+ return userSearchFilter;
+ }
+
+ public String getAuthUser() {
+ return authUser;
+ }
+
+ public String getAuthPass() {
+ return authPass;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/5ce7cc38/ugsync/ldapconfigchecktool/ldapconfigcheck/src/main/java/org/apache/ranger/ldapconfigcheck/LdapConfig.java
----------------------------------------------------------------------
diff --git a/ugsync/ldapconfigchecktool/ldapconfigcheck/src/main/java/org/apache/ranger/ldapconfigcheck/LdapConfig.java b/ugsync/ldapconfigchecktool/ldapconfigcheck/src/main/java/org/apache/ranger/ldapconfigcheck/LdapConfig.java
new file mode 100644
index 0000000..a548957
--- /dev/null
+++ b/ugsync/ldapconfigchecktool/ldapconfigcheck/src/main/java/org/apache/ranger/ldapconfigcheck/LdapConfig.java
@@ -0,0 +1,436 @@
+/*
+ * 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.ranger.ldapconfigcheck;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.lang.NullArgumentException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+
+public class LdapConfig {
+
+ public static final String CONFIG_FILE = "input.properties";
+
+ private static final String LGSYNC_LDAP_URL = "ranger.usersync.ldap.url";
+
+ private static final String LGSYNC_LDAP_BIND_DN = "ranger.usersync.ldap.binddn";
+
+ private static final String LGSYNC_LDAP_BIND_KEYSTORE = "ranger.usersync.credstore.filename";
+
+ private static final String LGSYNC_LDAP_BIND_ALIAS = "ranger.usersync.ldap.bindalias";
+
+ private static final String LGSYNC_LDAP_BIND_PASSWORD = "ranger.usersync.ldap.ldapbindpassword";
+
+ private static final String LGSYNC_LDAP_AUTHENTICATION_MECHANISM = "ranger.usersync.ldap.authentication.mechanism";
+ private static final String DEFAULT_AUTHENTICATION_MECHANISM = "simple";
+
+ private static final String LGSYNC_SEARCH_BASE = "ranger.usersync.ldap.searchBase";
+
+ private static final String LGSYNC_USER_SEARCH_BASE = "ranger.usersync.ldap.user.searchbase";
+
+ private static final String LGSYNC_USER_SEARCH_SCOPE = "ranger.usersync.ldap.user.searchscope";
+
+ private static final String LGSYNC_USER_OBJECT_CLASS = "ranger.usersync.ldap.user.objectclass";
+
+ private static final String LGSYNC_USER_SEARCH_FILTER = "ranger.usersync.ldap.user.searchfilter";
+
+ private static final String LGSYNC_USER_NAME_ATTRIBUTE = "ranger.usersync.ldap.user.nameattribute";
+
+ private static final String LGSYNC_USER_GROUP_NAME_ATTRIBUTE = "ranger.usersync.ldap.user.groupnameattribute";
+
+ public static final String UGSYNC_LOWER_CASE_CONVERSION_VALUE = "lower";
+
+ private static final String UGSYNC_USERNAME_CASE_CONVERSION_PARAM = "ranger.usersync.ldap.username.caseconversion";
+ private static final String DEFAULT_UGSYNC_USERNAME_CASE_CONVERSION_VALUE = UGSYNC_LOWER_CASE_CONVERSION_VALUE;
+
+ private static final String UGSYNC_GROUPNAME_CASE_CONVERSION_PARAM = "ranger.usersync.ldap.groupname.caseconversion";
+ private static final String DEFAULT_UGSYNC_GROUPNAME_CASE_CONVERSION_VALUE = UGSYNC_LOWER_CASE_CONVERSION_VALUE;
+
+
+ private static final String LGSYNC_PAGED_RESULTS_ENABLED = "ranger.usersync.pagedresultsenabled";
+ private static final boolean DEFAULT_LGSYNC_PAGED_RESULTS_ENABLED = true;
+
+ private static final String LGSYNC_PAGED_RESULTS_SIZE = "ranger.usersync.pagedresultssize";
+ private static final int DEFAULT_LGSYNC_PAGED_RESULTS_SIZE = 500;
+
+ private static final String LGSYNC_GROUP_SEARCH_ENABLED = "ranger.usersync.group.searchenabled";
+ private static final boolean DEFAULT_LGSYNC_GROUP_SEARCH_ENABLED = false;
+
+ private static final String LGSYNC_GROUP_USER_MAP_SYNC_ENABLED = "ranger.usersync.group.usermapsyncenabled";
+ private static final boolean DEFAULT_LGSYNC_GROUP_USER_MAP_SYNC_ENABLED = false;
+
+ private static final String LGSYNC_GROUP_SEARCH_BASE = "ranger.usersync.group.searchbase";
+
+ private static final String LGSYNC_GROUP_SEARCH_SCOPE = "ranger.usersync.group.searchscope";
+
+ private static final String LGSYNC_GROUP_OBJECT_CLASS = "ranger.usersync.group.objectclass";
+
+ private static final String LGSYNC_GROUP_SEARCH_FILTER = "ranger.usersync.group.searchfilter";
+
+ private static final String LGSYNC_GROUP_NAME_ATTRIBUTE = "ranger.usersync.group.nameattribute";
+
+ private static final String LGSYNC_GROUP_MEMBER_ATTRIBUTE_NAME = "ranger.usersync.group.memberattributename";
+
+ //Authentication relate properties
+ private static final String AUTHENTICATION_METHOD = "ranger.authentication.method";
+ private static final String AD_DOMAIN = "ranger.ldap.ad.domain";
+ private static final String USER_DN_PATTERN = "ranger.ldap.user.dnpattern";
+ private static final String GROUP_ROLE_ATTRIBUTE = "ranger.ldap.group.roleattribute";
+ private static final String GROUP_SEARCH_BASE = "ranger.ldap.group.searchbase";
+ private static final String GROUP_SEARCH_FILTER = "ranger.ldap.group.searchfilter";
+ private static final String AUTH_USERNAME = "ranger.admin.auth.sampleuser";
+ private static final String AUTH_PASSWORD = "ranger.admin.auth.samplepassword";
+
+
+ private Properties prop = new Properties();
+
+
+ public LdapConfig(String configFile) {
+ init(configFile);
+ }
+
+ private void init(String configFile) {
+ readConfigFile(configFile);
+ }
+
+ private void readConfigFile(String fileName) {
+ try {
+ InputStream in = getFileInputStream(fileName);
+ if (in != null) {
+ try {
+ System.out.println("Reading ldap properties from " + fileName);
+ prop.load(in);
+
+ } finally {
+ try {
+ in.close();
+ } catch (IOException ioe) {
+ // Ignore IOE when closing stream
+ System.out.println(ioe);
+ }
+ }
+ }
+ } catch (Throwable e) {
+ throw new RuntimeException("Unable to load configuration file [" + fileName + "]", e);
+ }
+ }
+
+
+ /*private InputStream getFileInputStream(String path) throws FileNotFoundException {
+
+ InputStream ret = null;
+
+ File f = new File(path);
+
+ if (f.exists()) {
+ ret = new FileInputStream(f);
+ }
+
+ return ret;
+ }*/
+
+ private InputStream getFileInputStream(String path) throws FileNotFoundException {
+
+ InputStream ret = null;
+
+ File f = new File(path);
+
+ if (f.exists()) {
+ ret = new FileInputStream(f);
+ } else {
+ ret = getClass().getResourceAsStream(path);
+
+ if (ret == null) {
+ if (! path.startsWith("/")) {
+ ret = getClass().getResourceAsStream("/" + path);
+ }
+ }
+
+ if (ret == null) {
+ ret = ClassLoader.getSystemClassLoader().getResourceAsStream(path) ;
+ if (ret == null) {
+ if (! path.startsWith("/")) {
+ ret = ClassLoader.getSystemResourceAsStream("/" + path);
+ }
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ public String getLdapUrl() throws Throwable {
+ String val = prop.getProperty(LGSYNC_LDAP_URL);
+ if (val == null || val.trim().isEmpty()) {
+ throw new NullArgumentException(LGSYNC_LDAP_URL);
+ }
+ return val;
+ }
+
+
+ public String getLdapBindDn() throws Throwable {
+ String val = prop.getProperty(LGSYNC_LDAP_BIND_DN);
+ if (val == null || val.trim().isEmpty()) {
+ throw new NullArgumentException(LGSYNC_LDAP_BIND_DN);
+ }
+ return val;
+ }
+
+
+ public String getLdapBindPassword() {
+ //update credential from keystore
+ if (prop == null) {
+ return null;
+ }
+ return prop.getProperty(LGSYNC_LDAP_BIND_PASSWORD);
+ }
+
+
+ public String getLdapAuthenticationMechanism() {
+ String val = prop.getProperty(LGSYNC_LDAP_AUTHENTICATION_MECHANISM);
+ if (val == null || val.trim().isEmpty()) {
+ return DEFAULT_AUTHENTICATION_MECHANISM;
+ }
+ return val;
+ }
+
+
+ public String getUserSearchBase() {
+ String val = prop.getProperty(LGSYNC_USER_SEARCH_BASE);
+ if (val == null || val.trim().isEmpty()) {
+ val = getSearchBase();
+ }
+ return val;
+ }
+
+
+ public int getUserSearchScope() {
+ String val = prop.getProperty(LGSYNC_USER_SEARCH_SCOPE);
+ if (val == null || val.trim().isEmpty()) {
+ return 2; //subtree scope
+ }
+
+ val = val.trim().toLowerCase();
+ if (val.equals("0") || val.startsWith("base")) {
+ return 0; // object scope
+ } else if (val.equals("1") || val.startsWith("one")) {
+ return 1; // one level scope
+ } else {
+ return 2; // subtree scope
+ }
+ }
+
+
+ public String getUserObjectClass() {
+ String val = prop.getProperty(LGSYNC_USER_OBJECT_CLASS);
+ return val;
+ }
+
+ public String getUserSearchFilter() {
+ return prop.getProperty(LGSYNC_USER_SEARCH_FILTER);
+ }
+
+
+ public String getUserNameAttribute() {
+ String val = prop.getProperty(LGSYNC_USER_NAME_ATTRIBUTE);
+ return val;
+ }
+
+ public String getUserGroupNameAttribute() {
+ String val = prop.getProperty(LGSYNC_USER_GROUP_NAME_ATTRIBUTE);
+ return val;
+ }
+
+ public String getUserNameCaseConversion() {
+ String ret = prop.getProperty(UGSYNC_USERNAME_CASE_CONVERSION_PARAM, DEFAULT_UGSYNC_USERNAME_CASE_CONVERSION_VALUE);
+ return ret.trim().toLowerCase();
+ }
+
+ public String getGroupNameCaseConversion() {
+ String ret = prop.getProperty(UGSYNC_GROUPNAME_CASE_CONVERSION_PARAM, DEFAULT_UGSYNC_GROUPNAME_CASE_CONVERSION_VALUE);
+ return ret.trim().toLowerCase();
+ }
+
+ public String getSearchBase() {
+ return prop.getProperty(LGSYNC_SEARCH_BASE);
+ }
+
+ public boolean isPagedResultsEnabled() {
+ boolean pagedResultsEnabled;
+ String val = prop.getProperty(LGSYNC_PAGED_RESULTS_ENABLED);
+ if (val == null || val.trim().isEmpty()) {
+ pagedResultsEnabled = DEFAULT_LGSYNC_PAGED_RESULTS_ENABLED;
+ } else {
+ pagedResultsEnabled = Boolean.valueOf(val);
+ }
+ return pagedResultsEnabled;
+ }
+
+ public int getPagedResultsSize() {
+ int pagedResultsSize;
+ String val = prop.getProperty(LGSYNC_PAGED_RESULTS_SIZE);
+ if (val == null || val.trim().isEmpty()) {
+ pagedResultsSize = DEFAULT_LGSYNC_PAGED_RESULTS_SIZE;
+ } else {
+ pagedResultsSize = Integer.parseInt(val);
+ }
+ if (pagedResultsSize < 1) {
+ pagedResultsSize = DEFAULT_LGSYNC_PAGED_RESULTS_SIZE;
+ }
+ return pagedResultsSize;
+ }
+
+ public boolean isGroupSearchEnabled() {
+ boolean groupSearchEnabled;
+ String val = prop.getProperty(LGSYNC_GROUP_SEARCH_ENABLED);
+ if (val == null || val.trim().isEmpty()) {
+ groupSearchEnabled = DEFAULT_LGSYNC_GROUP_SEARCH_ENABLED;
+ } else {
+ groupSearchEnabled = Boolean.valueOf(val);
+ }
+ return groupSearchEnabled;
+ }
+
+ public boolean isGroupUserMapSyncEnabled() {
+ boolean groupUserMapSyncEnabled;
+ String val = prop.getProperty(LGSYNC_GROUP_USER_MAP_SYNC_ENABLED);
+ if (val == null || val.trim().isEmpty()) {
+ groupUserMapSyncEnabled = DEFAULT_LGSYNC_GROUP_USER_MAP_SYNC_ENABLED;
+ } else {
+ groupUserMapSyncEnabled = Boolean.valueOf(val);
+ }
+ return groupUserMapSyncEnabled;
+ }
+
+ public String getGroupSearchBase() {
+ String val = prop.getProperty(LGSYNC_GROUP_SEARCH_BASE);
+ return val;
+ }
+
+ public int getGroupSearchScope() {
+ String val = prop.getProperty(LGSYNC_GROUP_SEARCH_SCOPE);
+ if (val == null || val.trim().isEmpty()) {
+ return 2; //subtree scope
+ }
+
+ val = val.trim().toLowerCase();
+ if (val.equals("0") || val.startsWith("base")) {
+ return 0; // object scope
+ } else if (val.equals("1") || val.startsWith("one")) {
+ return 1; // one level scope
+ } else {
+ return 2; // subtree scope
+ }
+ }
+
+ public String getGroupObjectClass() {
+ String val = prop.getProperty(LGSYNC_GROUP_OBJECT_CLASS);
+ return val;
+ }
+
+ public String getGroupSearchFilter() {
+ return prop.getProperty(LGSYNC_GROUP_SEARCH_FILTER);
+ }
+
+ public String getUserGroupMemberAttributeName() {
+ String val = prop.getProperty(LGSYNC_GROUP_MEMBER_ATTRIBUTE_NAME);
+ return val;
+ }
+
+ public String getGroupNameAttribute() {
+ String val = prop.getProperty(LGSYNC_GROUP_NAME_ATTRIBUTE);
+ return val;
+ }
+
+ public String getAuthenticationMethod() {
+ String val = prop.getProperty(AUTHENTICATION_METHOD);
+ return val;
+ }
+
+ public String getAdDomain() {
+ String val = prop.getProperty(AD_DOMAIN);
+ return val;
+ }
+
+ public String getUserDnPattern() {
+ String val = prop.getProperty(USER_DN_PATTERN);
+ return val;
+ }
+
+ public String getGroupRoleAttribute() {
+ String val = prop.getProperty(GROUP_ROLE_ATTRIBUTE);
+ return val;
+ }
+
+ public String getAuthGroupSearchBase() {
+ String val = prop.getProperty(GROUP_SEARCH_BASE);
+ return val;
+ }
+
+ public String getAuthGroupSearchFilter() {
+ String val = prop.getProperty(GROUP_SEARCH_FILTER);
+ return val;
+ }
+
+ public String getAuthUsername() {
+ return prop.getProperty(AUTH_USERNAME);
+ }
+
+ public String getAuthPassword() {
+ return prop.getProperty(AUTH_PASSWORD);
+ }
+
+ public void updateInputPropFile(String ldapUrl, String bindDn, String bindPassword,
+ String userSearchBase, String userSearchFilter,
+ String authUser, String authPass) {
+ try {
+ PropertiesConfiguration config = new PropertiesConfiguration(CONFIG_FILE);
+ // Update properties in memory and update the file as well
+ prop.setProperty(LGSYNC_LDAP_URL, ldapUrl);
+ prop.setProperty(LGSYNC_LDAP_BIND_DN, bindDn);
+ prop.setProperty(LGSYNC_LDAP_BIND_PASSWORD, bindPassword);
+ prop.setProperty(LGSYNC_USER_SEARCH_BASE, userSearchBase);
+ prop.setProperty(LGSYNC_USER_SEARCH_FILTER, userSearchFilter);
+ prop.setProperty(AUTH_USERNAME, authUser);
+ prop.setProperty(AUTH_PASSWORD, authPass);
+ config.setProperty(LGSYNC_LDAP_URL, ldapUrl);
+ config.setProperty(LGSYNC_LDAP_BIND_DN, bindDn);
+ config.setProperty(LGSYNC_LDAP_BIND_PASSWORD, bindPassword);
+ config.setProperty(LGSYNC_USER_SEARCH_BASE, userSearchBase);
+ config.setProperty(LGSYNC_USER_SEARCH_FILTER, userSearchFilter);
+ config.setProperty(AUTH_USERNAME, authUser);
+ config.setProperty(AUTH_PASSWORD, authPass);
+ config.save();
+ } catch (ConfigurationException e) {
+ System.out.println("Failed to update " + CONFIG_FILE + ": " + e);
+ }
+ }
+}
+
+
+
+
+
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/5ce7cc38/ugsync/ldapconfigchecktool/ldapconfigcheck/src/main/java/org/apache/ranger/ldapconfigcheck/LdapConfigCheckMain.java
----------------------------------------------------------------------
diff --git a/ugsync/ldapconfigchecktool/ldapconfigcheck/src/main/java/org/apache/ranger/ldapconfigcheck/LdapConfigCheckMain.java b/ugsync/ldapconfigchecktool/ldapconfigcheck/src/main/java/org/apache/ranger/ldapconfigcheck/LdapConfigCheckMain.java
new file mode 100644
index 0000000..ad56b2e
--- /dev/null
+++ b/ugsync/ldapconfigchecktool/ldapconfigcheck/src/main/java/org/apache/ranger/ldapconfigcheck/LdapConfigCheckMain.java
@@ -0,0 +1,241 @@
+/*
+ * 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.ranger.ldapconfigcheck;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.ldap.Control;
+import javax.naming.ldap.InitialLdapContext;
+import javax.naming.ldap.LdapContext;
+import javax.naming.ldap.PagedResultsControl;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.Properties;
+
+import org.apache.commons.lang.NullArgumentException;
+
+public class LdapConfigCheckMain {
+
+ private static final String LOG_FILE = "ldapConfigCheck.log";
+ private static final String AMBARI_PROPERTIES = "ambari.properties";
+ private static final String INSTALL_PROPERTIES = "install.properties";
+
+ public static void main(String[] args) {
+
+ CommandLineOptions cli = new CommandLineOptions(args);
+ cli.parse();
+ String inFileName = cli.getInput();
+ String outputDir = cli.getOutput();
+ if (!outputDir.endsWith("/")) {
+ outputDir = outputDir.concat("/");
+ }
+
+ LdapConfig config = new LdapConfig(inFileName);
+ if (cli.getLdapUrl() != null && !cli.getLdapUrl().isEmpty()) {
+ config.updateInputPropFile(cli.getLdapUrl(), cli.getBindDn(), cli.getBindPassword(),
+ cli.getUserSearchBase(), cli.getUserSearchFilter(), cli.getAuthUser(), cli.getAuthPass());
+ }
+
+ PrintStream logFile = null;
+ PrintStream ambariProps = null;
+ PrintStream installProps = null;
+ LdapContext ldapContext;
+
+ try {
+ logFile = new PrintStream(new File(outputDir + LOG_FILE));
+ ambariProps = new PrintStream(new File(outputDir + AMBARI_PROPERTIES));
+ installProps = new PrintStream(new File(outputDir + INSTALL_PROPERTIES));
+
+ UserSync userSyncObj = new UserSync(config, logFile, ambariProps, installProps);
+
+ String bindDn = config.getLdapBindDn();
+
+ Properties env = new Properties();
+ env.put(Context.INITIAL_CONTEXT_FACTORY,
+ "com.sun.jndi.ldap.LdapCtxFactory");
+ env.put(Context.PROVIDER_URL, config.getLdapUrl());
+ env.put(Context.SECURITY_PRINCIPAL, bindDn);
+ env.put(Context.SECURITY_CREDENTIALS, config.getLdapBindPassword());
+ env.put(Context.SECURITY_AUTHENTICATION, config.getLdapAuthenticationMechanism());
+ env.put(Context.REFERRAL, "follow");
+
+ ldapContext = new InitialLdapContext(env, null);
+
+ if (config.isPagedResultsEnabled()) {
+ ldapContext.setRequestControls(new Control[]{
+ new PagedResultsControl(config.getPagedResultsSize(), Control.CRITICAL) });
+ }
+
+ String retrieveValues = "all";
+
+ if (cli.getDiscoverProperties() != null) {
+ retrieveValues = cli.getDiscoverProperties();
+ if (cli.getDiscoverProperties().equalsIgnoreCase("users")) {
+ userSyncObj.findUserProperties(ldapContext);
+ } else if (cli.getDiscoverProperties().equalsIgnoreCase("groups")) {
+ userSyncObj.findGroupProperties(ldapContext);
+ } else {
+ findAllUserSyncProperties(ldapContext, userSyncObj);
+ }
+ }else if (cli.getRetrieveValues() != null){
+ retrieveValues = cli.getRetrieveValues();
+
+ } else {
+ cli.help();
+ }
+
+ if (cli.isAuthEnabled()) {
+ authenticate(userSyncObj, config, logFile, ambariProps, installProps);
+ }
+
+ retrieveUsersGroups(ldapContext, userSyncObj, retrieveValues);
+
+ if (ldapContext != null) {
+ ldapContext.close();
+ }
+
+ } catch (FileNotFoundException fe) {
+ System.out.println(fe.getMessage());
+ } catch (IOException ioe) {
+ logFile.println("ERROR: Failed while setting the paged results controls\n" + ioe);
+ } catch (NamingException ne) {
+ System.out.println("ERROR: Failed to perfom ldap bind. Please verify values for " +
+ "ranger.usersync.ldap.binddn and ranger.usersync.ldap.ldapbindpassword\n" + ne);
+ } catch (Throwable t) {
+ if (logFile != null) {
+ logFile.println("ERROR: Connection failed: " + t.getMessage());
+ } else {
+ System.out.println("ERROR: Connection failed: " + t.getMessage());
+ }
+ } finally {
+ if (logFile != null) {
+ logFile.close();
+ }
+ if (ambariProps != null) {
+ ambariProps.close();
+ }
+ if (installProps != null) {
+ installProps.close();
+ }
+ }
+ }
+
+ private static void findAllUserSyncProperties(LdapContext ldapContext, UserSync userSyncObj) throws Throwable {
+
+ userSyncObj.findUserProperties(ldapContext);
+ userSyncObj.findGroupProperties(ldapContext);
+ }
+
+ private static void authenticate(UserSync userSyncObj, LdapConfig config,
+ PrintStream logFile, PrintStream ambariProps,
+ PrintStream installProps) throws Throwable{
+ AuthenticationCheck auth = new AuthenticationCheck(config.getLdapUrl(), userSyncObj, logFile, ambariProps, installProps);
+
+ auth.discoverAuthProperties();
+
+ String msg;
+ if (config.getAuthUsername() == null || config.getAuthUsername().isEmpty()) {
+ msg = "ranger.admin.auth.sampleuser ";
+ throw new NullArgumentException(msg);
+ }
+
+ if (config.getAuthPassword() == null || config.getAuthPassword().isEmpty()) {
+ msg = "ranger.admin.auth.samplepassword ";
+ throw new NullArgumentException(msg);
+ }
+
+ if (auth.isAuthenticated(config.getLdapUrl(), config.getLdapBindDn(), config.getLdapBindPassword(),
+ config.getAuthUsername(), config.getAuthPassword())) {
+ logFile.println("INFO: Authentication verified successfully");
+ } else {
+ logFile.println("ERROR: Failed to authenticate " + config.getAuthUsername());
+ }
+ }
+
+ private static void retrieveUsersGroups(LdapContext ldapContext, UserSync userSyncObj,
+ String retrieve) throws Throwable {
+ String msg;
+ if (retrieve == null || userSyncObj == null || ldapContext == null) {
+ msg = "Input validation failed while retrieving Users or Groups";
+ throw new NullArgumentException(msg);
+ }
+
+ if (retrieve.equalsIgnoreCase("users")) {
+ retrieveUsers(ldapContext, userSyncObj);
+ } else if (retrieve.equalsIgnoreCase("groups")){
+ retrieveGroups(ldapContext, userSyncObj);
+ } else {
+ // retrieve both
+ retrieveUsers(ldapContext, userSyncObj);
+ retrieveGroups(ldapContext, userSyncObj);
+ }
+ }
+
+ private static void retrieveUsers(LdapContext ldapContext, UserSync userSyncObj) throws Throwable {
+ String msg;
+ if (userSyncObj.getUserNameAttribute() == null || userSyncObj.getUserNameAttribute().isEmpty()) {
+ msg = "ranger.usersync.ldap.user.nameattribute ";
+ throw new NullArgumentException(msg);
+ }
+ if (userSyncObj.getUserObjClassName() == null || userSyncObj.getUserObjClassName().isEmpty()) {
+ msg = "ranger.usersync.ldap.user.objectclass ";
+ throw new NullArgumentException(msg);
+ }
+ if (userSyncObj.getUserGroupMemberName() == null || userSyncObj.getUserGroupMemberName().isEmpty()) {
+ msg = "ranger.usersync.ldap.user.groupnameattribute ";
+ throw new NullArgumentException(msg);
+ }
+ if ((userSyncObj.getUserSearchBase() == null || userSyncObj.getUserSearchBase().isEmpty()) &&
+ (userSyncObj.getSearchBase() == null || userSyncObj.getSearchBase().isEmpty())) {
+ msg = "ranger.usersync.ldap.user.searchbase and " +
+ "ranger.usersync.ldap.searchBase ";
+ throw new NullArgumentException(msg);
+ }
+ userSyncObj.getAllUsers(ldapContext);
+ }
+
+ private static void retrieveGroups(LdapContext ldapContext, UserSync userSyncObj) throws Throwable {
+ String msg;
+ if (userSyncObj.getGroupNameAttrName() == null || userSyncObj.getGroupNameAttrName().isEmpty()) {
+ msg = "ranger.usersync.group.nameattribute ";
+ throw new NullArgumentException(msg);
+ }
+ if (userSyncObj.getGroupObjClassName() == null || userSyncObj.getGroupObjClassName().isEmpty()) {
+ msg = "ranger.usersync.group.objectclass ";
+ throw new NullArgumentException(msg);
+ }
+ if (userSyncObj.getUserGroupMemberName() == null || userSyncObj.getUserGroupMemberName().isEmpty()) {
+ msg = "ranger.usersync.group.memberattributename ";
+ throw new NullArgumentException(msg);
+ }
+ if ((userSyncObj.getGroupSearchBase() == null || userSyncObj.getGroupSearchBase().isEmpty()) &&
+ (userSyncObj.getSearchBase() == null || userSyncObj.getSearchBase().isEmpty())) {
+ msg = "ranger.usersync.group.searchbase and " +
+ "ranger.usersync.ldap.searchBase ";
+ throw new NullArgumentException(msg);
+ }
+ userSyncObj.getAllGroups(ldapContext);
+ }
+
+
+}
+
[3/3] incubator-ranger git commit: Merge branch 'master' of
https://git-wip-us.apache.org/repos/asf/incubator-ranger
Posted by ve...@apache.org.
Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/incubator-ranger
Project: http://git-wip-us.apache.org/repos/asf/incubator-ranger/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ranger/commit/9474fe9d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ranger/tree/9474fe9d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ranger/diff/9474fe9d
Branch: refs/heads/master
Commit: 9474fe9d55e2e9a85923781fec88e1e3829c6224
Parents: 5ce7cc3 a2c4bb2
Author: Velmurugan Periasamy <ve...@apache.org>
Authored: Sat Oct 10 12:28:55 2015 -0400
Committer: Velmurugan Periasamy <ve...@apache.org>
Committed: Sat Oct 10 12:28:55 2015 -0400
----------------------------------------------------------------------
----------------------------------------------------------------------