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/27 09:26:59 UTC
[ambari] branch trunk updated: AMBARI-24951. Using Ambari CLI to
specify which services should be setup for LDAP integration (#2652)
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 4d245a1 AMBARI-24951. Using Ambari CLI to specify which services should be setup for LDAP integration (#2652)
4d245a1 is described below
commit 4d245a1196bbcf6e2ca9b77901bf3942f3ac60f8
Author: Sandor Molnar <sm...@apache.org>
AuthorDate: Tue Nov 27 10:26:53 2018 +0100
AMBARI-24951. Using Ambari CLI to specify which services should be setup for LDAP integration (#2652)
---
ambari-server/src/main/python/ambari-server.py | 4 ++
.../src/main/python/ambari_server/serverUtils.py | 34 +++++++++-
.../src/main/python/ambari_server/setupSecurity.py | 78 ++++++++++++++++++++--
.../src/main/python/ambari_server/setupSso.py | 37 +---------
ambari-server/src/test/python/TestAmbariServer.py | 39 +++++++++--
ambari-server/src/test/python/TestSetupSso.py | 5 +-
6 files changed, 149 insertions(+), 48 deletions(-)
diff --git a/ambari-server/src/main/python/ambari-server.py b/ambari-server/src/main/python/ambari-server.py
index 4cf7325..e5a943f 100755
--- a/ambari-server/src/main/python/ambari-server.py
+++ b/ambari-server/src/main/python/ambari-server.py
@@ -581,6 +581,10 @@ def init_ldap_setup_parser_options(parser):
parser.add_option('--truststore-path', default=None, help="Path of TrustStore", dest="trust_store_path")
parser.add_option('--truststore-password', default=None, help="Password for TrustStore", dest="trust_store_password")
parser.add_option('--truststore-reconfigure', action="store_true", default=None, help="Force to reconfigure TrustStore if exits", dest="trust_store_reconfigure")
+ parser.add_option('--ldap-enabled-ambari', default=None, help="Indicates whether to enable/disable LDAP authentication for Ambari, itself", dest='ldap_enabled_ambari')
+ parser.add_option('--ldap-manage-services', default=None, help="Indicates whether Ambari should manage the LDAP configurations for specified services", dest='ldap_manage_services')
+ parser.add_option('--ldap-enabled-services', default=None, help="A comma separated list of services that are expected to be configured for LDAP (you are allowed to use '*' to indicate ALL services)", dest='ldap_enabled_services')
+
@OsFamilyFuncImpl(OsFamilyImpl.DEFAULT)
def init_setup_sso_options(parser):
diff --git a/ambari-server/src/main/python/ambari_server/serverUtils.py b/ambari-server/src/main/python/ambari_server/serverUtils.py
index 7d2370e..f37e515 100644
--- a/ambari-server/src/main/python/ambari_server/serverUtils.py
+++ b/ambari-server/src/main/python/ambari_server/serverUtils.py
@@ -294,4 +294,36 @@ def is_api_ssl_enabled(properties):
if api_ssl_prop is not None:
ssl_enabled = api_ssl_prop.lower() == "true"
- return ssl_enabled
\ No newline at end of file
+ return ssl_enabled
+
+def eligible(service_info, is_sso_integration):
+ if is_sso_integration:
+ return service_info['sso_integration_supported'] and (not service_info['sso_integration_requires_kerberos'] or service_info['kerberos_enabled'])
+ else:
+ return service_info['ldap_integration_supported']
+
+def get_eligible_services(properties, admin_login, admin_password, cluster_name, entry_point, service_qualifier):
+ print_info_msg("Fetching %s enabled services" % service_qualifier)
+
+ safe_cluster_name = urllib2.quote(cluster_name)
+
+ response_code, json_data = get_json_via_rest_api(properties, admin_login, admin_password, entry_point % safe_cluster_name)
+
+ services = []
+
+ if json_data and 'items' in json_data:
+ services = [item['ServiceInfo']['service_name'] for item in json_data['items'] if eligible(item['ServiceInfo'], 'SSO' == service_qualifier)]
+
+ if len(services) > 0:
+ print_info_msg('Found %s enabled services: %s' % (service_qualifier, ', '.join(services)))
+ else:
+ print_info_msg('No %s enabled services were found' % service_qualifier)
+
+ return services
+
+def get_value_from_dictionary(properties, key, default_value=None):
+ return properties[key] if properties and key in properties else default_value
+
+def get_boolean_from_dictionary(properties, key, default_value=False):
+ value = get_value_from_dictionary(properties, key, None)
+ return 'true' == value.lower() if value else default_value
\ No newline at end of file
diff --git a/ambari-server/src/main/python/ambari_server/setupSecurity.py b/ambari-server/src/main/python/ambari_server/setupSecurity.py
index f6d0a3e..e281c16 100644
--- a/ambari-server/src/main/python/ambari_server/setupSecurity.py
+++ b/ambari-server/src/main/python/ambari_server/setupSecurity.py
@@ -54,7 +54,8 @@ from ambari_server.serverConfiguration import configDefaults, parse_properties_f
get_resources_location, SECURITY_MASTER_KEY_LOCATION, SETUP_OR_UPGRADE_MSG, \
CHECK_AMBARI_KRB_JAAS_CONFIGURATION_PROPERTY
from ambari_server.serverUtils import is_server_runing, get_ambari_server_api_base, \
- get_ambari_admin_username_password_pair, perform_changes_via_rest_api, get_ssl_context
+ get_ambari_admin_username_password_pair, perform_changes_via_rest_api, get_ssl_context, get_cluster_name, \
+ get_eligible_services, get_boolean_from_dictionary, get_value_from_dictionary
from ambari_server.setupActions import SETUP_ACTION, LDAP_SETUP_ACTION
from ambari_server.userInput import get_validated_string_input, get_prompt_default, read_password, get_YN_input, \
quit_if_has_answer
@@ -89,7 +90,6 @@ SETUP_LDAP_CONFIG_URL = 'services/AMBARI/components/AMBARI_SERVER/configurations
PAM_CONFIG_FILE = 'pam.configuration'
-IS_LDAP_CONFIGURED = "ambari.ldap.authentication.enabled"
LDAP_MGR_USERNAME_PROPERTY = "ambari.ldap.connectivity.bind_dn"
LDAP_MGR_PASSWORD_FILENAME = "ldap-password.dat"
LDAP_ANONYMOUS_BIND="ambari.ldap.connectivity.anonymous_bind"
@@ -97,6 +97,12 @@ LDAP_USE_SSL="ambari.ldap.connectivity.use_ssl"
LDAP_DISABLE_ENDPOINT_IDENTIFICATION = "ambari.ldap.advanced.disable_endpoint_identification"
NO_AUTH_METHOD_CONFIGURED = "no auth method"
+AMBARI_LDAP_AUTH_ENABLED = "ambari.ldap.authentication.enabled"
+LDAP_MANAGE_SERVICES = "ambari.ldap.manage_services"
+LDAP_ENABLED_SERVICES = "ambari.ldap.enabled_services"
+WILDCARD_FOR_ALL_SERVICES = "*"
+FETCH_SERVICES_FOR_LDAP_ENTRYPOINT = "clusters/%s/services?ServiceInfo/ldap_integration_supported=true&fields=ServiceInfo/*"
+
def read_master_key(isReset=False, options = None):
passwordPattern = ".*"
passwordPrompt = "Please provide master key for locking the credential store: "
@@ -338,7 +344,7 @@ def get_ldap_properties_from_db(properties, admin_login, admin_password):
return ldap_properties
def is_ldap_enabled(properties, admin_login, admin_password):
- ldap_enabled = get_ldap_property_from_db(properties, admin_login, admin_password, IS_LDAP_CONFIGURED)
+ ldap_enabled = get_ldap_property_from_db(properties, admin_login, admin_password, AMBARI_LDAP_AUTH_ENABLED)
return ldap_enabled if ldap_enabled is not None else 'false'
@@ -814,7 +820,9 @@ def setup_ldap(options):
LDAP_DISABLE_ENDPOINT_IDENTIFICATION,
SSL_TRUSTSTORE_TYPE_PROPERTY,
SSL_TRUSTSTORE_PATH_PROPERTY,
- SSL_TRUSTSTORE_PASSWORD_PROPERTY]
+ SSL_TRUSTSTORE_PASSWORD_PROPERTY,
+ LDAP_MANAGE_SERVICES,
+ LDAP_ENABLED_SERVICES]
ldap_property_list_passwords=[LDAP_MGR_PASSWORD_PROPERTY, SSL_TRUSTSTORE_PASSWORD_PROPERTY]
@@ -891,6 +899,9 @@ def setup_ldap(options):
pass
pass
+ populate_ambari_requires_ldap(options, ldap_property_value_map)
+ populate_service_management(options, ldap_property_value_map, properties, admin_login, admin_password)
+
print '=' * 20
print 'Review Settings'
print '=' * 20
@@ -934,7 +945,6 @@ def setup_ldap(options):
print 'Saving LDAP properties...'
- ldap_property_value_map[IS_LDAP_CONFIGURED] = "true"
#Saving LDAP configuration in Ambari DB using the REST API
update_ldap_configuration(admin_login, admin_password, properties, ldap_property_value_map)
@@ -1127,3 +1137,61 @@ def migrate_ldap_pam(args):
else:
print_info_msg('LDAP to PAM migration completed')
return retcode
+
+
+def populate_ambari_requires_ldap(options, properties):
+ if options.ldap_enabled_ambari is None:
+ enabled = get_boolean_from_dictionary(properties, AMBARI_LDAP_AUTH_ENABLED, False)
+ enabled = get_YN_input("Use LDAP authentication for Ambari [y/n] ({0})? ".format('y' if enabled else 'n'), enabled)
+ else:
+ enabled = 'true' == options.ldap_enabled_ambari
+
+ properties[AMBARI_LDAP_AUTH_ENABLED] = 'true' if enabled else 'false'
+
+
+def populate_service_management(options, properties, ambari_properties, admin_login, admin_password):
+ services = ""
+ if options.ldap_enabled_services is None:
+ if options.ldap_manage_services is None:
+ manage_services = get_boolean_from_dictionary(properties, LDAP_MANAGE_SERVICES, False)
+ manage_services = get_YN_input("Manage LDAP configurations for eligible services [y/n] ({0})? ".format('y' if manage_services else 'n'), manage_services)
+ else:
+ manage_services = 'true' == options.ldap_manage_services
+ stored_manage_services = get_boolean_from_dictionary(properties, LDAP_MANAGE_SERVICES, False)
+ print("Manage LDAP configurations for eligible services [y/n] ({0})? {1}".format('y' if stored_manage_services else 'n', 'y' if manage_services else 'n'))
+
+ if manage_services:
+ enabled_services = get_value_from_dictionary(properties, LDAP_ENABLED_SERVICES, "").upper().split(',')
+
+ all = WILDCARD_FOR_ALL_SERVICES in enabled_services
+ configure_for_all_services = get_YN_input(" Manage LDAP for all services [y/n] ({0})? ".format('y' if all else 'n'), all)
+ if configure_for_all_services:
+ services = WILDCARD_FOR_ALL_SERVICES
+ else:
+ cluster_name = get_cluster_name(ambari_properties, admin_login, admin_password)
+
+ if cluster_name:
+ eligible_services = get_eligible_services(ambari_properties, admin_login, admin_password, cluster_name, FETCH_SERVICES_FOR_LDAP_ENTRYPOINT, 'LDAP')
+
+ if eligible_services and len(eligible_services) > 0:
+ service_list = []
+
+ for service in eligible_services:
+ enabled = service.upper() in enabled_services
+ question = " Manage LDAP for {0} [y/n] ({1})? ".format(service, 'y' if enabled else 'n')
+ if get_YN_input(question, enabled):
+ service_list.append(service)
+
+ services = ','.join(service_list)
+ else:
+ print (" There are no eligible services installed.")
+ else:
+ if options.ldap_manage_services:
+ manage_services = 'true' == options.ldap_manage_services
+ else:
+ manage_services = True
+
+ services = options.ldap_enabled_services.upper() if options.ldap_enabled_services else ""
+
+ properties[LDAP_MANAGE_SERVICES] = 'true' if manage_services else 'false'
+ properties[LDAP_ENABLED_SERVICES] = services
\ No newline at end of file
diff --git a/ambari-server/src/main/python/ambari_server/setupSso.py b/ambari-server/src/main/python/ambari_server/setupSso.py
index 8b3a041..d65f579 100644
--- a/ambari-server/src/main/python/ambari_server/setupSso.py
+++ b/ambari-server/src/main/python/ambari_server/setupSso.py
@@ -26,7 +26,8 @@ from ambari_commons.logging_utils import get_silent, print_info_msg
from ambari_server.serverConfiguration import get_ambari_properties
from ambari_server.serverUtils import is_server_runing, get_ambari_admin_username_password_pair, \
- get_cluster_name, perform_changes_via_rest_api, get_json_via_rest_api
+ get_cluster_name, perform_changes_via_rest_api, get_json_via_rest_api, get_eligible_services, \
+ get_boolean_from_dictionary, get_value_from_dictionary
from ambari_server.setupSecurity import REGEX_TRUE_FALSE
from ambari_server.userInput import get_validated_string_input, get_YN_input, get_multi_line_input
@@ -134,31 +135,6 @@ def populate_ambari_requires_sso(options, properties):
properties[AMBARI_SSO_AUTH_ENABLED] = 'true' if enabled else 'false'
-def eligible(service_info):
- return service_info['sso_integration_supported'] \
- and (not service_info['sso_integration_requires_kerberos'] or service_info['kerberos_enabled'])
-
-def get_eligible_services(properties, admin_login, admin_password, cluster_name):
- print_info_msg("Fetching SSO enabled services")
-
- safe_cluster_name = urllib2.quote(cluster_name)
-
- response_code, json_data = get_json_via_rest_api(properties, admin_login, admin_password,
- FETCH_SERVICES_FOR_SSO_ENTRYPOINT % safe_cluster_name)
-
- services = []
-
- if json_data and 'items' in json_data:
- services = [item['ServiceInfo']['service_name'] for item in json_data['items'] if eligible(item['ServiceInfo'])]
-
- if len(services) > 0:
- print_info_msg('Found SSO enabled services: %s' % ', '.join(services))
- else:
- print_info_msg('No SSO enabled services were found')
-
- return services
-
-
def populate_service_management(options, properties, ambari_properties, admin_login, admin_password):
if not options.sso_enabled_services:
if not options.sso_manage_services:
@@ -183,7 +159,7 @@ def populate_service_management(options, properties, ambari_properties, admin_lo
cluster_name = get_cluster_name(ambari_properties, admin_login, admin_password)
if cluster_name:
- eligible_services = get_eligible_services(ambari_properties, admin_login, admin_password, cluster_name)
+ eligible_services = get_eligible_services(ambari_properties, admin_login, admin_password, cluster_name, FETCH_SERVICES_FOR_SSO_ENTRYPOINT, 'SSO')
if eligible_services and len(eligible_services) > 0:
service_list = []
@@ -319,10 +295,3 @@ def ensure_complete_cert(cert_string):
return cert_string
-def get_value_from_dictionary(properties, key, default_value=None):
- return properties[key] if properties and key in properties else default_value
-
-def get_boolean_from_dictionary(properties, key, default_value=False):
- value = get_value_from_dictionary(properties, key, None)
- return 'true' == value.lower() if value else default_value
-
diff --git a/ambari-server/src/test/python/TestAmbariServer.py b/ambari-server/src/test/python/TestAmbariServer.py
index 9c4e704..4e5db52 100644
--- a/ambari-server/src/test/python/TestAmbariServer.py
+++ b/ambari-server/src/test/python/TestAmbariServer.py
@@ -7047,7 +7047,9 @@ class TestAmbariServer(TestCase):
"ambari.ldap.attributes.user.search_base": "uid",
"ambari.ldap.connectivity.anonymous_bind": "true",
"ambari.ldap.advanced.referrals": "follow",
- "ambari.ldap.authentication.enabled": "true"
+ "ambari.ldap.authentication.enabled": "true",
+ "ambari.ldap.manage_services": "true",
+ "ambari.ldap.enabled_services":"*"
}
return ldap_properties_map
@@ -7073,7 +7075,9 @@ class TestAmbariServer(TestCase):
"ambari.ldap.advanced.collision_behavior": "skip",
"ambari.ldap.advanced.force_lowercase_usernames": "false",
"ambari.ldap.advanced.pagination_enabled": "false",
- "ambari.ldap.authentication.enabled": "true"
+ "ambari.ldap.authentication.enabled": "true",
+ "ambari.ldap.manage_services": "true",
+ "ambari.ldap.enabled_services":"*"
}
return ldap_properties_map
@@ -7092,7 +7096,9 @@ class TestAmbariServer(TestCase):
"ambari.ldap.advanced.force_lowercase_usernames": "false",
"ambari.ldap.advanced.pagination_enabled": "false",
"ambari.ldap.advanced.referrals": "follow",
- "ambari.ldap.authentication.enabled": "true"
+ "ambari.ldap.authentication.enabled": "true",
+ "ambari.ldap.manage_services": "true",
+ "ambari.ldap.enabled_services":"*"
}
return ldap_properties_map
@@ -7116,7 +7122,9 @@ class TestAmbariServer(TestCase):
"ambari.ldap.advanced.collision_behavior": "skip",
"ambari.ldap.advanced.force_lowercase_usernames": "false",
"ambari.ldap.advanced.pagination_enabled": "false",
- "ambari.ldap.authentication.enabled": "true"
+ "ambari.ldap.authentication.enabled": "true",
+ "ambari.ldap.manage_services": "true",
+ "ambari.ldap.enabled_services":"*"
}
return ldap_properties_map
@@ -7280,7 +7288,9 @@ class TestAmbariServer(TestCase):
"ambari.ldap.attributes.dn_attr": "test",
"ambari.ldap.advanced.referrals": "test",
LDAP_MGR_PASSWORD_PROPERTY: "ldap-password.dat",
- "ambari.ldap.authentication.enabled": "true"
+ "ambari.ldap.authentication.enabled": "true",
+ "ambari.ldap.manage_services": "true",
+ "ambari.ldap.enabled_services":"ZOOKEEPER",
}
return ldap_properties_map
@@ -7301,7 +7311,10 @@ class TestAmbariServer(TestCase):
@patch("ambari_server.setupSecurity.is_server_runing")
@patch("ambari_server.setupSecurity.query_ldap_type")
@patch("ambari_server.setupSecurity.get_ldap_properties_from_db")
- def test_setup_ldap(self, get_ldap_properties_from_db_method, query_ldap_type_method, is_server_runing_method, logger_mock, exists_method, read_password_method, get_ambari_properties_method,
+ @patch("ambari_server.setupSecurity.get_eligible_services")
+ @patch("ambari_server.setupSecurity.get_cluster_name")
+ def test_setup_ldap(self, get_cluster_name_method, get_eligible_services_method,
+ get_ldap_properties_from_db_method, query_ldap_type_method, is_server_runing_method, logger_mock, exists_method, read_password_method, get_ambari_properties_method,
search_file_message,
get_validated_string_input_method,
configure_ldap_password_method, update_properties_method,
@@ -7334,6 +7347,10 @@ class TestAmbariServer(TestCase):
def yn_input_side_effect(*args, **kwargs):
if 'TrustStore' in args[0]:
return False
+ if 'for all services' in args[0]:
+ return False
+ if 'Manage LDAP for HDFS' in args[0]: #note that LDAP is enabled for HDFS (see below) but we say we do not want it to be managed by Ambari
+ return False
else:
return True
@@ -7355,6 +7372,10 @@ class TestAmbariServer(TestCase):
get_validated_string_input_method.side_effect = valid_input_side_effect
+ get_cluster_name_method.return_value = "cluster1"
+ eligible_services = ["HDFS", "ZOOKEEPER"]
+ get_eligible_services_method.return_value = eligible_services
+
response = MagicMock()
response.getcode.return_value = 200
urlopen_mock.return_value = response
@@ -7415,7 +7436,7 @@ class TestAmbariServer(TestCase):
get_validated_string_input_method.side_effect = input_enable_ssl
read_password_method.return_value = "password"
get_YN_input_method.reset_mock()
- get_YN_input_method.side_effect = [True, True, True]
+ get_YN_input_method.side_effect = [True, True, True, False, True]
update_properties_method.reset_mock()
options.ldap_primary_host = None
@@ -8781,6 +8802,10 @@ class TestAmbariServer(TestCase):
def _create_empty_options_mock(self):
options = MagicMock()
+ options.ldap_enabled = None
+ options.ldap_enabled_ambari = None
+ options.ldap_manage_services = None
+ options.ldap_enabled_services = None
options.ldap_url = None
options.ldap_primary_host = None
options.ldap_primary_port = None
diff --git a/ambari-server/src/test/python/TestSetupSso.py b/ambari-server/src/test/python/TestSetupSso.py
index 802c058..b708587 100644
--- a/ambari-server/src/test/python/TestSetupSso.py
+++ b/ambari-server/src/test/python/TestSetupSso.py
@@ -482,6 +482,7 @@ class TestSetupSso(unittest.TestCase):
self.assertEqual(ssoProperties[SSO_ENABLED_SERVICES], "*")
+ @patch("urllib2.urlopen")
@patch("ambari_server.setupSso.perform_changes_via_rest_api")
@patch("ambari_server.setupSso.get_cluster_name")
@patch("ambari_server.setupSso.get_YN_input")
@@ -497,7 +498,8 @@ class TestSetupSso(unittest.TestCase):
get_ambari_properties_mock,
get_YN_input_mock,
get_cluster_name_mock,
- perform_changes_via_rest_api_mock):
+ perform_changes_via_rest_api_mock,
+ urlopen_mock):
out = StringIO.StringIO()
sys.stdout = out
@@ -582,6 +584,7 @@ class TestSetupSso(unittest.TestCase):
response = MagicMock()
response.getcode.return_value = 200
response.read.return_value = eligible_services
+ urlopen_mock.return_value = response
options = self._create_empty_options_mock()
options.sso_enabled = 'true'