You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by sm...@apache.org on 2018/11/06 18:08:51 UTC
[ambari] branch trunk updated: AMBARI-24861. New wrapper class on
Python side for LDAP-related data for use in service advisors (#2579)
This is an automated email from the ASF dual-hosted git repository.
smolnar pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ambari.git
The following commit(s) were added to refs/heads/trunk by this push:
new 66a3bf9 AMBARI-24861. New wrapper class on Python side for LDAP-related data for use in service advisors (#2579)
66a3bf9 is described below
commit 66a3bf93adbecdda74b1ea76cde4f39c49b9beaa
Author: Sandor Molnar <sm...@apache.org>
AuthorDate: Tue Nov 6 19:08:46 2018 +0100
AMBARI-24861. New wrapper class on Python side for LDAP-related data for use in service advisors (#2579)
---
.../ldap/domain/AmbariLdapConfiguration.java | 4 +
.../main/resources/stacks/ambari_configuration.py | 225 +++++++++++++++++++++
...configuration.py => TestAmbariConfiguration.py} | 126 +++++++++++-
3 files changed, 354 insertions(+), 1 deletion(-)
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ldap/domain/AmbariLdapConfiguration.java b/ambari-server/src/main/java/org/apache/ambari/server/ldap/domain/AmbariLdapConfiguration.java
index fe99a35..c55f337 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/ldap/domain/AmbariLdapConfiguration.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ldap/domain/AmbariLdapConfiguration.java
@@ -34,6 +34,10 @@ import org.slf4j.LoggerFactory;
/**
* This class is an immutable representation of all the LDAP related
* configurationMap entries.
+ * <p>
+ * <strong>IMPORTANT: </strong>in case you declare any new LDAP related property
+ * please do it in the Python class
+ * <code>stacks.ambari_configuration.AmbariLDAPConfiguration</code> too.
*/
public class AmbariLdapConfiguration {
diff --git a/ambari-server/src/main/resources/stacks/ambari_configuration.py b/ambari-server/src/main/resources/stacks/ambari_configuration.py
index d327c44..9104c32 100644
--- a/ambari-server/src/main/resources/stacks/ambari_configuration.py
+++ b/ambari-server/src/main/resources/stacks/ambari_configuration.py
@@ -107,6 +107,19 @@ class AmbariConfiguration(object):
"""
return AmbariSSODetails(self.get_ambari_sso_configuration())
+ def get_ambari_ldap_configuration(self):
+ """
+ Safely gets a dictionary of properties for the "ldap-configuration" category.
+
+ :return: a dictionary or None, if "ldap-configuration" is not available
+ """
+ return self.get_ambari_server_configuration_category("ldap-configuration")
+
+ def get_ambari_ldap_details(self):
+ """
+ :return: instance of AmbariLDAPConfiguration that may be used to configure a service for LDAP integration
+ """
+ return AmbariLDAPConfiguration(self.get_ambari_ldap_configuration())
class AmbariSSODetails(object):
"""
@@ -262,3 +275,215 @@ class AmbariSSODetails(object):
public_cert = public_cert.replace('\n', '')
return public_cert
+
+
+class AmbariLDAPConfiguration:
+ """
+ AmbariLDAPConfiguration encapsulates the LDAP configuration data specified in the ambari-server-configuration data.
+ The public API of class mirrors the following Java class's public API (except for trust store related API and getLdapServerProperties which we do not need in Pyton side):
+ org.apache.ambari.server.ldap.domain.AmbariLdapConfiguration
+ """
+
+ def __init__(self, ldap_properties):
+ self.ldap_properties = ldap_properties
+
+ def is_ldap_enabled(self):
+ return "true" == _get_from_dictionary(self.ldap_properties, 'ambari.ldap.authentication.enabled')
+
+ def get_server_host(self):
+ '''
+ :return: The LDAP URL host used for connecting to an LDAP server when authenticating users or None if ldap-configuration/ambari.ldap.connectivity.server.host is not specified
+ '''
+ return _get_from_dictionary(self.ldap_properties, 'ambari.ldap.connectivity.server.host')
+
+ def get_server_port(self):
+ '''
+ :return: The LDAP URL port (as an integer) used for connecting to an LDAP server when authenticating users or None if ldap-configuration/ambari.ldap.connectivity.server.port is not specified
+ '''
+ ldap_server_port = _get_from_dictionary(self.ldap_properties, 'ambari.ldap.connectivity.server.port')
+ return int(ldap_server_port) if ldap_server_port is not None else None
+
+ def get_server_url(self):
+ '''
+ :return: The LDAP URL (host:port) used for connecting to an LDAP server when authenticating users
+ '''
+ ldap_host = self.get_server_host()
+ ldap_port = self.get_server_port()
+ return None if ldap_host is None or ldap_port is None else '{}:{}'.format(ldap_host,ldap_port)
+
+ def get_secondary_server_host(self):
+ '''
+ :return: A second LDAP URL host to use as a backup when authenticating users or None if ldap-configuration/ambari.ldap.connectivity.secondary.server.host is not specified
+ '''
+ return _get_from_dictionary(self.ldap_properties, 'ambari.ldap.connectivity.secondary.server.host')
+
+ def get_secondary_server_port(self):
+ '''
+ :return: A second LDAP URL port (as an integer) to use as a backup when authenticating users or None if ldap-configuration/ambari.ldap.connectivity.secondary.server.port is not specified
+ '''
+ ldap_server_secondary_port = _get_from_dictionary(self.ldap_properties, 'ambari.ldap.connectivity.secondary.server.port')
+ return int(ldap_server_secondary_port) if ldap_server_secondary_port is not None else None
+
+ def get_secondary_server_url(self):
+ '''
+ :return: A second LDAP URL (host:port) used for connecting to an LDAP server when authenticating users
+ '''
+ ldap_host = self.get_secondary_server_host()
+ ldap_port = self.get_secondary_server_port()
+ return None if ldap_host is None or ldap_port is None else '{}:{}'.format(ldap_host,ldap_port)
+
+ def is_use_ssl(self):
+ '''
+ :return: Whether to use LDAP over SSL (LDAPS).
+ '''
+ return "true" == _get_from_dictionary(self.ldap_properties, 'ambari.ldap.connectivity.use_ssl')
+
+ def is_anonymous_bind(self):
+ '''
+ :return: Whether LDAP requests can connect anonymously or if a managed user is required to connect
+ '''
+ return "true" == _get_from_dictionary(self.ldap_properties, 'ambari.ldap.connectivity.anonymous_bind')
+
+ def get_bind_dn(self):
+ '''
+ :return: The DN of the manager account to use when binding to LDAP if anonymous binding is disabled or None if ldap-configuration/ is not specified
+ '''
+ return _get_from_dictionary(self.ldap_properties, 'ambari.ldap.connectivity.bind_dn')
+
+ def get_bind_password(self):
+ '''
+ :return: The password for the manager account used to bind to LDAP if anonymous binding is disabled
+ '''
+ return _get_from_dictionary(self.ldap_properties, 'ambari.ldap.connectivity.bind_password')
+
+ def get_dn_attribute(self):
+ '''
+ :return: The attribute used for determining what the distinguished name property is or None if ldap-configuration/ambari.ldap.attributes.dn_attr is not specified
+ '''
+ return _get_from_dictionary(self.ldap_properties, 'ambari.ldap.attributes.dn_attr')
+
+ def get_user_object_class(self):
+ '''
+ :return: The class to which user objects in LDAP belong or None if ldap-configuration/ambari.ldap.attributes.user.object_class is not specified
+ '''
+ return _get_from_dictionary(self.ldap_properties, 'ambari.ldap.attributes.user.object_class')
+
+ def get_user_name_attribute(self):
+ '''
+ :return: The attribute used for determining the user name, such as 'uid' or None if ldap-configuration/ambari.ldap.attributes.user.name_attr is not specified
+ '''
+ return _get_from_dictionary(self.ldap_properties, 'ambari.ldap.attributes.user.name_attr')
+
+ def get_user_search_base(self):
+ '''
+ :return: The base DN to use when filtering LDAP users and groups. This is only used when LDAP authentication is enabled or None if ldap-configuration/ambari.ldap.attributes.user.search_base is not specified
+ '''
+ return _get_from_dictionary(self.ldap_properties, 'ambari.ldap.attributes.user.search_base')
+
+ def get_group_object_class(self):
+ '''
+ :return: The LDAP object class value that defines groups in the directory service or None if ldap-configuration/ambari.ldap.attributes.group.object_class is not specified
+ '''
+ return _get_from_dictionary(self.ldap_properties, 'ambari.ldap.attributes.group.object_class')
+
+ def get_group_name_attribute(self):
+ '''
+ :return: The attribute used to determine the group name in LDAP or None if ldap-configuration/ambari.ldap.attributes.group.name_attr is not specified
+ '''
+ return _get_from_dictionary(self.ldap_properties, 'ambari.ldap.attributes.group.name_attr')
+
+ def get_group_member_attribute(self):
+ '''
+ :return: The LDAP attribute which identifies group membership or None if ldap-configuration/ambari.ldap.attributes.group.member_attr is not specified
+ '''
+ return _get_from_dictionary(self.ldap_properties, 'ambari.ldap.attributes.group.member_attr')
+
+ def get_group_search_base(self):
+ '''
+ :return: The base DN to use when filtering LDAP users and groups or None if ldap-configuration/ambari.ldap.attributes.group.search_base is not specified
+ '''
+ return _get_from_dictionary(self.ldap_properties, 'ambari.ldap.attributes.group.search_base')
+
+ def get_group_mapping_rules(self):
+ '''
+ :return: A comma-separate list of groups which would give a user administrative access to Ambari when syncing from LDAP or None if ldap-configuration/ambari.ldap.advanced.group_mapping_rules is not specified
+ '''
+ return _get_from_dictionary(self.ldap_properties, 'ambari.ldap.advanced.group_mapping_rules')
+
+ def get_user_search_filter(self):
+ '''
+ :return: A filter used to lookup a user in LDAP based on the Ambari user name or None if ldap-configuration/ambari.ldap.advanced.user_search_filter is not specified
+ '''
+ return _get_from_dictionary(self.ldap_properties, 'ambari.ldap.advanced.user_search_filter')
+
+ def get_user_member_replace_pattern(self):
+ '''
+ :return: The regex pattern to use when replacing the user member attribute ID value with a placeholder or None if ldap-configuration/ambari.ldap.advanced.user_member_replace_pattern is not specified
+ '''
+ return _get_from_dictionary(self.ldap_properties, 'ambari.ldap.advanced.user_member_replace_pattern')
+
+ def get_user_member_filter(self):
+ '''
+ :return: The filter to use for syncing user members of a group from LDAP or None if ldap-configuration/ambari.ldap.advanced.user_member_filter is not specified
+ '''
+ return _get_from_dictionary(self.ldap_properties, 'ambari.ldap.advanced.user_member_filter')
+
+ def get_group_search_filter(self):
+ '''
+ :return: The DN to use when searching for LDAP groups or None if ldap-configuration/ambari.ldap.advanced.group_search_filter is not specified
+ '''
+ return _get_from_dictionary(self.ldap_properties, 'ambari.ldap.advanced.group_search_filter')
+
+ def get_group_member_replace_pattern(self):
+ '''
+ :return: The regex pattern to use when replacing the group member attribute ID value with a placeholder or None if ldap-configuration/ambari.ldap.advanced.group_member_replace_pattern is not specified
+ '''
+ return _get_from_dictionary(self.ldap_properties, 'ambari.ldap.advanced.group_member_replace_pattern')
+
+ def get_group_member_filter(self):
+ '''
+ :return: The F=filter to use for syncing group members of a group from LDAP or None if ldap-configuration/ambari.ldap.advanced.group_member_filter is not specified
+ '''
+ return _get_from_dictionary(self.ldap_properties, 'ambari.ldap.advanced.group_member_filter')
+
+ def is_force_lower_case_user_names(self):
+ '''
+ :return: Whether to force the ldap user name to be lowercase or leave as-is
+ '''
+ return "true" == _get_from_dictionary(self.ldap_properties, 'ambari.ldap.advanced.force_lowercase_usernames')
+
+ def is_pagination_enabled(self):
+ '''
+ :return: Whether results from LDAP are paginated when requested
+ '''
+ return "true" == _get_from_dictionary(self.ldap_properties, 'ambari.ldap.advanced.pagination_enabled')
+
+ def is_follow_referral_handling(self):
+ '''
+ :return: Whether to follow LDAP referrals to other URLs when the LDAP controller doesn't have the requested object
+ '''
+ return "true" == _get_from_dictionary(self.ldap_properties, 'ambari.ldap.advanced.referrals')
+
+ def is_disable_endpoint_identification(self):
+ '''
+ :return: Whether to disable endpoint identification (hostname verification) during SSL handshake while updating from LDAP
+ '''
+ return "true" == _get_from_dictionary(self.ldap_properties, 'ambari.ldap.advanced.disable_endpoint_identification')
+
+ def is_ldap_alternate_user_search_enabled(self):
+ '''
+ :return: Whether a secondary (alternate) LDAP user search filer is used if the primary filter fails to find a user
+ '''
+ return "true" == _get_from_dictionary(self.ldap_properties, 'ambari.ldap.advanced.alternate_user_search_enabled')
+
+ def get_alternate_user_search_filter(self):
+ '''
+ :return: An alternate LDAP user search filter which can be used if 'ldap_alternate_user_search_enabled' is enabled and the primary filter fails to find a user
+ '''
+ return _get_from_dictionary(self.ldap_properties, 'ambari.ldap.advanced.alternate_user_search_filter')
+
+ def get_sync_collision_handling_behavior(self):
+ '''
+ :return: How to handle username collision while updating from LDAP or None if ldap-configuration/ambari.ldap.advanced.collision_behavior is not specified
+ '''
+ return _get_from_dictionary(self.ldap_properties, 'ambari.ldap.advanced.collision_behavior')
diff --git a/ambari-server/src/test/python/stacks/test_ambari_configuration.py b/ambari-server/src/test/python/TestAmbariConfiguration.py
similarity index 61%
rename from ambari-server/src/test/python/stacks/test_ambari_configuration.py
rename to ambari-server/src/test/python/TestAmbariConfiguration.py
index 5894e49..58062e1 100644
--- a/ambari-server/src/test/python/stacks/test_ambari_configuration.py
+++ b/ambari-server/src/test/python/TestAmbariConfiguration.py
@@ -26,7 +26,7 @@ class TestAmbariConfiguration(TestCase):
import imp
self.test_directory = os.path.dirname(os.path.abspath(__file__))
- relative_path = '../../../main/resources/stacks/ambari_configuration.py'
+ relative_path = '../../main/resources/stacks/ambari_configuration.py'
ambari_configuration_path = os.path.abspath(os.path.join(self.test_directory, relative_path))
class_name = 'AmbariConfiguration'
@@ -41,6 +41,7 @@ class TestAmbariConfiguration(TestCase):
ambari_configuration = self.ambari_configuration_class('{}')
self.assertIsNone(ambari_configuration.get_ambari_server_configuration())
self.assertIsNone(ambari_configuration.get_ambari_sso_configuration())
+ self.assertIsNone(ambari_configuration.get_ambari_ldap_configuration())
def testMissingSSOConfiguration(self):
services_json = {
@@ -280,3 +281,126 @@ class TestAmbariConfiguration(TestCase):
'................................................................'
'dXRpbmcxFzAVBgNVBAMTDmNsb3VkYnJlYWstcmdsMSUwIwYJKoZIhvcNAQkBFhZy',
ambari_sso_details.get_sso_provider_certificate(False, True))
+
+ def testMissingLDAPConfiguration(self):
+ services_json = {
+ "ambari-server-configuration": {
+ }
+ }
+
+ ambari_configuration = self.ambari_configuration_class(services_json)
+ self.assertIsNone(ambari_configuration.get_ambari_ldap_configuration())
+
+ ambari_ldap_details = ambari_configuration.get_ambari_ldap_details()
+ self.assertIsNotNone(ambari_ldap_details)
+ self.assertFalse(ambari_ldap_details.is_ldap_enabled())
+ self.assertIsNone(ambari_ldap_details.get_server_host())
+ self.assertIsNone(ambari_ldap_details.get_server_port())
+ self.assertIsNone(ambari_ldap_details.get_server_url())
+ self.assertIsNone(ambari_ldap_details.get_secondary_server_host())
+ self.assertIsNone(ambari_ldap_details.get_secondary_server_port())
+ self.assertIsNone(ambari_ldap_details.get_secondary_server_url())
+ self.assertFalse(ambari_ldap_details.is_use_ssl())
+ self.assertFalse(ambari_ldap_details.is_anonymous_bind())
+ self.assertIsNone(ambari_ldap_details.get_bind_dn())
+ self.assertIsNone(ambari_ldap_details.get_bind_password())
+ self.assertIsNone(ambari_ldap_details.get_dn_attribute())
+ self.assertIsNone(ambari_ldap_details.get_user_object_class())
+ self.assertIsNone(ambari_ldap_details.get_user_name_attribute())
+ self.assertIsNone(ambari_ldap_details.get_user_search_base())
+ self.assertIsNone(ambari_ldap_details.get_group_object_class())
+ self.assertIsNone(ambari_ldap_details.get_group_name_attribute())
+ self.assertIsNone(ambari_ldap_details.get_group_member_attribute())
+ self.assertIsNone(ambari_ldap_details.get_group_search_base())
+ self.assertIsNone(ambari_ldap_details.get_group_mapping_rules())
+ self.assertIsNone(ambari_ldap_details.get_user_search_filter())
+ self.assertIsNone(ambari_ldap_details.get_user_member_replace_pattern())
+ self.assertIsNone(ambari_ldap_details.get_user_member_filter())
+ self.assertIsNone(ambari_ldap_details.get_group_search_filter())
+ self.assertIsNone(ambari_ldap_details.get_group_member_replace_pattern())
+ self.assertIsNone(ambari_ldap_details.get_group_member_filter())
+ self.assertFalse(ambari_ldap_details.is_force_lower_case_user_names())
+ self.assertFalse(ambari_ldap_details.is_pagination_enabled())
+ self.assertFalse(ambari_ldap_details.is_follow_referral_handling())
+ self.assertFalse(ambari_ldap_details.is_disable_endpoint_identification())
+ self.assertFalse(ambari_ldap_details.is_ldap_alternate_user_search_enabled())
+ self.assertIsNone(ambari_ldap_details.get_alternate_user_search_filter())
+ self.assertIsNone(ambari_ldap_details.get_sync_collision_handling_behavior())
+
+ def testNotEmtpyLDAPConfiguration(self):
+ services_json = {
+ "ambari-server-configuration": {
+ "ldap-configuration": {
+ "ambari.ldap.authentication.enabled" : "true",
+ "ambari.ldap.connectivity.server.host" : "host1",
+ "ambari.ldap.connectivity.server.port" : "336",
+ "ambari.ldap.connectivity.secondary.server.host" : "host2",
+ "ambari.ldap.connectivity.secondary.server.port" : "337",
+ "ambari.ldap.connectivity.use_ssl" : "true",
+ "ambari.ldap.connectivity.anonymous_bind" : "true",
+ "ambari.ldap.connectivity.bind_dn" : "bind_dn",
+ "ambari.ldap.connectivity.bind_password" : "bind_password",
+ "ambari.ldap.attributes.dn_attr" : "dn_attr",
+ "ambari.ldap.attributes.user.object_class" : "user.object_class",
+ "ambari.ldap.attributes.user.name_attr" : "user.name_attr",
+ "ambari.ldap.attributes.user.search_base" : "user.search_base",
+ "ambari.ldap.attributes.group.object_class" : "group.object_class",
+ "ambari.ldap.attributes.group.name_attr" : "group.name_attr",
+ "ambari.ldap.attributes.group.member_attr" : "group.member_attr",
+ "ambari.ldap.attributes.group.search_base" : "group.search_base",
+ "ambari.ldap.advanced.group_mapping_rules" : "group_mapping_rules",
+ "ambari.ldap.advanced.user_search_filter" : "user_search_filter",
+ "ambari.ldap.advanced.user_member_replace_pattern" : "user_member_replace_pattern",
+ "ambari.ldap.advanced.user_member_filter" : "user_member_filter",
+ "ambari.ldap.advanced.group_search_filter" : "group_search_filter",
+ "ambari.ldap.advanced.group_member_replace_pattern" : "group_member_replace_pattern",
+ "ambari.ldap.advanced.group_member_filter" : "group_member_filter",
+ "ambari.ldap.advanced.force_lowercase_usernames" : "true",
+ "ambari.ldap.advanced.pagination_enabled" : "true",
+ "ambari.ldap.advanced.referrals" : "true",
+ "ambari.ldap.advanced.disable_endpoint_identification" : "true",
+ "ambari.ldap.advanced.alternate_user_search_enabled" : "true",
+ "ambari.ldap.advanced.alternate_user_search_filter" : "alternate_user_search_filter",
+ "ambari.ldap.advanced.collision_behavior" : "collision_behavior"
+ }
+ }
+ }
+
+ ambari_configuration = self.ambari_configuration_class(services_json)
+ self.assertIsNotNone(ambari_configuration.get_ambari_ldap_configuration())
+ ambari_ldap_details = ambari_configuration.get_ambari_ldap_details()
+ self.assertIsNotNone(ambari_ldap_details)
+
+ self.assertTrue(ambari_ldap_details.is_ldap_enabled())
+ self.assertEquals(ambari_ldap_details.get_server_host(), "host1")
+ self.assertEquals(ambari_ldap_details.get_server_port(), 336)
+ self.assertEquals(ambari_ldap_details.get_server_url(), "host1:336")
+ self.assertEquals(ambari_ldap_details.get_secondary_server_host(), "host2")
+ self.assertEquals(ambari_ldap_details.get_secondary_server_port(), 337)
+ self.assertEquals(ambari_ldap_details.get_secondary_server_url(), "host2:337")
+ self.assertTrue(ambari_ldap_details.is_use_ssl())
+ self.assertTrue(ambari_ldap_details.is_anonymous_bind())
+ self.assertEquals(ambari_ldap_details.get_bind_dn(), "bind_dn")
+ self.assertEquals(ambari_ldap_details.get_bind_password(), "bind_password")
+ self.assertEquals(ambari_ldap_details.get_dn_attribute(), "dn_attr")
+ self.assertEquals(ambari_ldap_details.get_user_object_class(), "user.object_class")
+ self.assertEquals(ambari_ldap_details.get_user_name_attribute(), "user.name_attr")
+ self.assertEquals(ambari_ldap_details.get_user_search_base(), "user.search_base")
+ self.assertEquals(ambari_ldap_details.get_group_object_class(), "group.object_class")
+ self.assertEquals(ambari_ldap_details.get_group_name_attribute(), "group.name_attr")
+ self.assertEquals(ambari_ldap_details.get_group_member_attribute(), "group.member_attr")
+ self.assertEquals(ambari_ldap_details.get_group_search_base(), "group.search_base")
+ self.assertEquals(ambari_ldap_details.get_group_mapping_rules(), "group_mapping_rules")
+ self.assertEquals(ambari_ldap_details.get_user_search_filter(), "user_search_filter")
+ self.assertEquals(ambari_ldap_details.get_user_member_replace_pattern(), "user_member_replace_pattern")
+ self.assertEquals(ambari_ldap_details.get_user_member_filter(), "user_member_filter")
+ self.assertEquals(ambari_ldap_details.get_group_search_filter(), "group_search_filter")
+ self.assertEquals(ambari_ldap_details.get_group_member_replace_pattern(), "group_member_replace_pattern")
+ self.assertEquals(ambari_ldap_details.get_group_member_filter(), "group_member_filter")
+ self.assertTrue(ambari_ldap_details.is_force_lower_case_user_names())
+ self.assertTrue(ambari_ldap_details.is_pagination_enabled())
+ self.assertTrue(ambari_ldap_details.is_follow_referral_handling())
+ self.assertTrue(ambari_ldap_details.is_disable_endpoint_identification())
+ self.assertTrue(ambari_ldap_details.is_ldap_alternate_user_search_enabled())
+ self.assertEquals(ambari_ldap_details.get_alternate_user_search_filter(), "alternate_user_search_filter")
+ self.assertEquals(ambari_ldap_details.get_sync_collision_handling_behavior(), "collision_behavior")