You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by kr...@apache.org on 2018/08/29 07:11:10 UTC
[ambari] branch trunk updated: AMBARI-24516 - Default value for
LDAP type (#2181)
This is an automated email from the ASF dual-hosted git repository.
krisztiankasa 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 1edde0c AMBARI-24516 - Default value for LDAP type (#2181)
1edde0c is described below
commit 1edde0cfd7b91a76b306688252d41914979942e9
Author: kasakrisz <33...@users.noreply.github.com>
AuthorDate: Wed Aug 29 09:11:05 2018 +0200
AMBARI-24516 - Default value for LDAP type (#2181)
---
ambari-server/src/main/python/ambari-server.py | 43 +++--
.../src/main/python/ambari_server/setupSecurity.py | 192 +++++++++++++--------
ambari-server/src/test/python/TestAmbariServer.py | 113 ++++++++++--
3 files changed, 247 insertions(+), 101 deletions(-)
diff --git a/ambari-server/src/main/python/ambari-server.py b/ambari-server/src/main/python/ambari-server.py
index 6a05013..c1fc6eb 100755
--- a/ambari-server/src/main/python/ambari-server.py
+++ b/ambari-server/src/main/python/ambari-server.py
@@ -18,48 +18,46 @@ See the License for the specific language governing permissions and
limitations under the License.
'''
+import logging
+import logging.config
+import logging.handlers
import optparse
-import sys
import os
import signal
-import logging
-import logging.handlers
-import logging.config
-
-from optparse import OptionValueError
+import sys
from ambari_commons.exceptions import FatalException, NonFatalException
from ambari_commons.logging_utils import set_verbose, set_silent, \
print_info_msg, print_warning_msg, print_error_msg, set_debug_mode_from_options
from ambari_commons.os_check import OSConst
from ambari_commons.os_family_impl import OsFamilyFuncImpl, OsFamilyImpl
from ambari_commons.os_utils import remove_file
+from optparse import OptionValueError
+
from ambari_server.BackupRestore import main as BackupRestore_main
+from ambari_server.checkDatabase import check_database
+from ambari_server.dbCleanup import db_purge
from ambari_server.dbConfiguration import DATABASE_NAMES, LINUX_DBMS_KEYS_LIST
+from ambari_server.enableStack import enable_stack_version
+from ambari_server.hostUpdate import update_host_names
+from ambari_server.kerberos_setup import setup_kerberos
from ambari_server.serverConfiguration import configDefaults, get_ambari_properties, PID_NAME
-from ambari_server.serverUtils import is_server_runing, refresh_stack_hash, wait_for_server_to_stop
from ambari_server.serverSetup import reset, setup, setup_jce_policy
from ambari_server.serverUpgrade import upgrade, set_current
+from ambari_server.serverUtils import is_server_runing, refresh_stack_hash, wait_for_server_to_stop
+from ambari_server.setupActions import BACKUP_ACTION, LDAP_SETUP_ACTION, LDAP_SYNC_ACTION, PSTART_ACTION, \
+ REFRESH_STACK_HASH_ACTION, RESET_ACTION, RESTORE_ACTION, UPDATE_HOST_NAMES_ACTION, CHECK_DATABASE_ACTION, \
+ SETUP_ACTION, SETUP_SECURITY_ACTION, RESTART_ACTION, START_ACTION, STATUS_ACTION, STOP_ACTION, UPGRADE_ACTION, \
+ SETUP_JCE_ACTION, SET_CURRENT_ACTION, ENABLE_STACK_ACTION, SETUP_SSO_ACTION, \
+ DB_PURGE_ACTION, INSTALL_MPACK_ACTION, UNINSTALL_MPACK_ACTION, UPGRADE_MPACK_ACTION, PAM_SETUP_ACTION, \
+ MIGRATE_LDAP_PAM_ACTION, KERBEROS_SETUP_ACTION
from ambari_server.setupHttps import setup_https, setup_truststore
from ambari_server.setupMpacks import install_mpack, uninstall_mpack, upgrade_mpack, STACK_DEFINITIONS_RESOURCE_NAME, \
SERVICE_DEFINITIONS_RESOURCE_NAME, MPACKS_RESOURCE_NAME
+from ambari_server.setupSecurity import setup_ldap, sync_ldap, setup_master_key, setup_ambari_krb5_jaas, setup_pam, \
+ migrate_ldap_pam, LDAP_TYPES
from ambari_server.setupSso import setup_sso
-from ambari_server.dbCleanup import db_purge
-from ambari_server.hostUpdate import update_host_names
-from ambari_server.checkDatabase import check_database
-from ambari_server.enableStack import enable_stack_version
-
-from ambari_server.setupActions import BACKUP_ACTION, LDAP_SETUP_ACTION, LDAP_SYNC_ACTION, PSTART_ACTION, \
- REFRESH_STACK_HASH_ACTION, RESET_ACTION, RESTORE_ACTION, UPDATE_HOST_NAMES_ACTION, CHECK_DATABASE_ACTION, \
- SETUP_ACTION, SETUP_SECURITY_ACTION,START_ACTION, STATUS_ACTION, STOP_ACTION, RESTART_ACTION, UPGRADE_ACTION, \
- SETUP_JCE_ACTION, SET_CURRENT_ACTION, START_ACTION, STATUS_ACTION, STOP_ACTION, UPGRADE_ACTION, \
- SETUP_JCE_ACTION, SET_CURRENT_ACTION, ENABLE_STACK_ACTION, SETUP_SSO_ACTION, \
- DB_PURGE_ACTION, INSTALL_MPACK_ACTION, UNINSTALL_MPACK_ACTION, UPGRADE_MPACK_ACTION, PAM_SETUP_ACTION, MIGRATE_LDAP_PAM_ACTION, KERBEROS_SETUP_ACTION
-from ambari_server.setupSecurity import setup_ldap, sync_ldap, setup_master_key, setup_ambari_krb5_jaas, setup_pam, migrate_ldap_pam
from ambari_server.userInput import get_validated_string_input
-from ambari_server.kerberos_setup import setup_kerberos
-
from ambari_server_main import server_process_main
-from ambari_server.ambariPath import AmbariPath
logger = logging.getLogger()
@@ -552,6 +550,7 @@ def init_ldap_setup_parser_options(parser):
parser.add_option('--ldap-secondary-host', action="callback", callback=check_ldap_url_options, type='str', default=None, help="Secondary Host for LDAP (must not be used together with --ldap-secondary-url)", dest="ldap_secondary_host")
parser.add_option('--ldap-secondary-port', action="callback", callback=check_ldap_url_options, type='int', default=None, help="Secondary Port for LDAP (must not be used together with --ldap-secondary-url)", dest="ldap_secondary_port")
parser.add_option('--ldap-ssl', default=None, help="Use SSL [true/false] for LDAP", dest="ldap_ssl")
+ parser.add_option('--ldap-use-generic-defaults', action="store_true", default=None, help="Disables ldap type query and generic defaults will be offered for non existent properties".format("/".join(LDAP_TYPES)), dest="ldap_use_generic_defaults")
parser.add_option('--ldap-user-class', default=None, help="User Attribute Object Class for LDAP", dest="ldap_user_class")
parser.add_option('--ldap-user-attr', default=None, help="User Attribute Name for LDAP", dest="ldap_user_attr")
parser.add_option('--ldap-group-class', default=None, help="Group Attribute Object Class for LDAP", dest="ldap_group_class")
diff --git a/ambari-server/src/main/python/ambari_server/setupSecurity.py b/ambari-server/src/main/python/ambari_server/setupSecurity.py
index b35b097..e3a9f8a 100644
--- a/ambari-server/src/main/python/ambari_server/setupSecurity.py
+++ b/ambari-server/src/main/python/ambari_server/setupSecurity.py
@@ -59,12 +59,13 @@ 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
from contextlib import closing
+from urllib2 import HTTPError
logger = logging.getLogger(__name__)
LDAP_AD="AD"
LDAP_IPA="IPA"
-LDAP_GENERIC="Generic LDAP"
+LDAP_GENERIC="Generic"
LDAP_TYPES = [LDAP_AD, LDAP_IPA, LDAP_GENERIC]
@@ -287,8 +288,12 @@ class LdapSyncOptions:
def no_ldap_sync_options_set(self):
return not self.ldap_sync_all and not self.ldap_sync_existing and self.ldap_sync_users is None and self.ldap_sync_groups is None
-def getLdapPropertyFromDB(properties, admin_login, admin_password, property_name):
- ldapProperty = None
+def get_ldap_property_from_db(properties, admin_login, admin_password, property_name):
+ ldap_properties_from_db = get_ldap_properties_from_db(properties, admin_login, admin_password)
+ return ldap_properties_from_db[property_name] if ldap_properties_from_db else None
+
+def get_ldap_properties_from_db(properties, admin_login, admin_password):
+ ldap_properties = None
url = get_ambari_server_api_base(properties) + SETUP_LDAP_CONFIG_URL
admin_auth = base64.encodestring('%s:%s' % (admin_login, admin_password)).replace('\n', '')
request = urllib2.Request(url)
@@ -298,10 +303,10 @@ def getLdapPropertyFromDB(properties, admin_login, admin_password, property_name
request_in_progress = True
sys.stdout.write('\nFetching LDAP configuration from DB')
- numOfTries = 0
+ num_of_tries = 0
while request_in_progress:
- numOfTries += 1
- if (numOfTries == 60):
+ num_of_tries += 1
+ if num_of_tries == 60:
raise FatalException(1, "Could not fetch LDAP configuration within a minute; giving up!")
sys.stdout.write('.')
sys.stdout.flush()
@@ -315,22 +320,26 @@ def getLdapPropertyFromDB(properties, admin_login, admin_password, property_name
raise FatalException(1, err)
else:
response_body = json.loads(response.read())
- ldapProperties = response_body['Configuration']['properties']
- ldapProperty = ldapProperties[property_name]
- if not ldapProperty:
+ ldap_properties = response_body['Configuration']['properties']
+ if not ldap_properties:
time.sleep(1)
else:
request_in_progress = False
+ except HTTPError as e:
+ if e.code == 404:
+ sys.stdout.write(' No configuration.')
+ return None
+ err = 'Error while fetching LDAP configuration. Error details: %s' % e
+ raise FatalException(1, err)
except Exception as e:
- request_in_progress = False
err = 'Error while fetching LDAP configuration. Error details: %s' % e
raise FatalException(1, err)
- return ldapProperty
+ return ldap_properties
def is_ldap_enabled(properties, admin_login, admin_password):
- ldapEnabled = getLdapPropertyFromDB(properties, admin_login, admin_password, IS_LDAP_CONFIGURED)
- return ldapEnabled if ldapEnabled != None else 'false'
+ ldap_enabled = get_ldap_property_from_db(properties, admin_login, admin_password, IS_LDAP_CONFIGURED)
+ return ldap_enabled if ldap_enabled is not None else 'false'
#
@@ -638,63 +647,98 @@ def setup_ambari_krb5_jaas(options):
class LdapPropTemplate:
- def __init__(self, properties, i_option, i_prop_name, i_prop_val_pattern, i_prompt_regex, i_allow_empty_prompt, i_prop_name_default=None):
+ def __init__(self, properties, i_option, i_prop_name, i_prop_val_pattern, i_prompt_regex, i_allow_empty_prompt, i_prop_default=None):
self.prop_name = i_prop_name
self.option = i_option
- self.ldap_prop_value = get_value_from_properties(properties, i_prop_name, i_prop_name_default)
- self.ldap_prop_val_prompt = format_prop_val_prompt(i_prop_val_pattern, self.ldap_prop_value)
+ stored_value = get_value_from_properties(properties, i_prop_name)
+ self.default_value = LdapDefault(stored_value) if stored_value else i_prop_default
+ self.prompt_pattern = i_prop_val_pattern
self.prompt_regex = i_prompt_regex
self.allow_empty_prompt = i_allow_empty_prompt
+ def get_default_value(self, ldap_type):
+ return self.default_value.get_default_value(ldap_type) if self.default_value else None
+
+ def get_prompt_text(self, ldap_type):
+ default_value = self.get_default_value(ldap_type)
+ return format_prop_val_prompt(self.prompt_pattern, default_value)
+
+ def get_input(self, ldap_type):
+ default_value = self.get_default_value(ldap_type)
+ return get_validated_string_input(self.get_prompt_text(ldap_type),
+ default_value, self.prompt_regex,
+ "Invalid characters in the input!", False, self.allow_empty_prompt,
+ answer = self.option)
+
+ def should_query_ldap_type(self):
+ return not self.allow_empty_prompt and not self.option and self.default_value and self.default_value.depends_on_ldap_type()
+
+class LdapDefault:
+ def __init__(self, value):
+ self.default_value = value
+
+ def get_default_value(self, ldap_type):
+ return self.default_value
+
+ def depends_on_ldap_type(self):
+ return False
+
+
+class LdapDefaultMap(LdapDefault):
+ def __init__(self, value_map):
+ LdapDefault.__init__(self, None)
+ self.default_value_map = value_map
+
+ def get_default_value(self, ldap_type):
+ return self.default_value_map[ldap_type] if self.default_value_map and ldap_type in self.default_value_map else None
+
+ def depends_on_ldap_type(self):
+ return True
+
def format_prop_val_prompt(prop_prompt_pattern, prop_default_value):
default_value = get_prompt_default(prop_default_value)
return prop_prompt_pattern.format((" " + default_value) if default_value is not None and default_value != "" else "")
@OsFamilyFuncImpl(OSConst.WINSRV_FAMILY)
-def init_ldap_properties_list_reqd(properties, options, ldap_type):
+def init_ldap_properties_list_reqd(properties, options):
# python2.x dict is not ordered
ldap_properties = [
- LdapPropTemplate(properties, options.ldap_primary_host, "ambari.ldap.connectivity.server.host", "Primary LDAP Host{0}: ", REGEX_HOSTNAME, False, get_default_prop_value(ldap_type, {LDAP_IPA:'ipa.ambari.apache.org', LDAP_GENERIC:'ldap.ambari.apache.org'})),
- LdapPropTemplate(properties, options.ldap_primary_port, "ambari.ldap.connectivity.server.port", "Primary LDAP Port{0}: ", REGEX_PORT, False, get_default_prop_value(ldap_type, {LDAP_IPA:'636', LDAP_GENERIC:'389'})),
+ LdapPropTemplate(properties, options.ldap_primary_host, "ambari.ldap.connectivity.server.host", "Primary LDAP Host{0}: ", REGEX_HOSTNAME, False, LdapDefaultMap({LDAP_IPA:'ipa.ambari.apache.org', LDAP_GENERIC:'ldap.ambari.apache.org'})),
+ LdapPropTemplate(properties, options.ldap_primary_port, "ambari.ldap.connectivity.server.port", "Primary LDAP Port{0}: ", REGEX_PORT, False, LdapDefaultMap({LDAP_IPA:'636', LDAP_GENERIC:'389'})),
LdapPropTemplate(properties, options.ldap_secondary_host, "ambari.ldap.connectivity.secondary.server.host", "Secondary LDAP Host <Optional>{0}: ", REGEX_HOSTNAME, True),
LdapPropTemplate(properties, options.ldap_secondary_port, "ambari.ldap.connectivity.secondary.server.port", "Secondary LDAP Port <Optional>{0}: ", REGEX_PORT, True),
- LdapPropTemplate(properties, options.ldap_ssl, "ambari.ldap.connectivity.use_ssl", "Use SSL [true/false]{0}: ", REGEX_TRUE_FALSE, False, get_default_prop_value(ldap_type, {LDAP_AD:'false', LDAP_IPA:'true', LDAP_GENERIC:'false'})),
- LdapPropTemplate(properties, options.ldap_user_attr, "ambari.ldap.attributes.user.name_attr", "User ID attribute{0}: ", REGEX_ANYTHING, False, get_default_prop_value(ldap_type, {LDAP_AD:'sAMAccountName', LDAP_IPA:'uid', LDAP_GENERIC:'uid'})),
- LdapPropTemplate(properties, options.ldap_base_dn, "ambari.ldap.attributes.user.search_base", "Search Base{0}: ", REGEX_ANYTHING, False, "dc=ambari,dc=apache,dc=org"),
- LdapPropTemplate(properties, options.ldap_referral, "ambari.ldap.advanced.referrals", "Referral method [follow/ignore]{0}: ", REGEX_REFERRAL, True, "follow"),
- LdapPropTemplate(properties, options.ldap_bind_anonym, "ambari.ldap.connectivity.anonymous_bind" "Bind anonymously [true/false]{0}: ", REGEX_TRUE_FALSE, False, "false")
+ LdapPropTemplate(properties, options.ldap_ssl, "ambari.ldap.connectivity.use_ssl", "Use SSL [true/false]{0}: ", REGEX_TRUE_FALSE, False, LdapDefaultMap({LDAP_AD:'false', LDAP_IPA:'true', LDAP_GENERIC:'false'})),
+ LdapPropTemplate(properties, options.ldap_user_attr, "ambari.ldap.attributes.user.name_attr", "User ID attribute{0}: ", REGEX_ANYTHING, False, LdapDefaultMap({LDAP_AD:'sAMAccountName', LDAP_IPA:'uid', LDAP_GENERIC:'uid'})),
+ LdapPropTemplate(properties, options.ldap_base_dn, "ambari.ldap.attributes.user.search_base", "Search Base{0}: ", REGEX_ANYTHING, False, LdapDefault("dc=ambari,dc=apache,dc=org")),
+ LdapPropTemplate(properties, options.ldap_referral, "ambari.ldap.advanced.referrals", "Referral method [follow/ignore]{0}: ", REGEX_REFERRAL, True, LdapDefault("follow")),
+ LdapPropTemplate(properties, options.ldap_bind_anonym, "ambari.ldap.connectivity.anonymous_bind" "Bind anonymously [true/false]{0}: ", REGEX_TRUE_FALSE, False, LdapDefault("false"))
]
return ldap_properties
@OsFamilyFuncImpl(OsFamilyImpl.DEFAULT)
-def init_ldap_properties_list_reqd(properties, options, ldap_type):
+def init_ldap_properties_list_reqd(properties, options):
ldap_properties = [
- LdapPropTemplate(properties, options.ldap_primary_host, "ambari.ldap.connectivity.server.host", "Primary LDAP Host{0}: ", REGEX_HOSTNAME, False, get_default_prop_value(ldap_type, {LDAP_IPA:'ipa.ambari.apache.org', LDAP_GENERIC:'ldap.ambari.apache.org'})),
- LdapPropTemplate(properties, options.ldap_primary_port, "ambari.ldap.connectivity.server.port", "Primary LDAP Port{0}: ", REGEX_PORT, False, get_default_prop_value(ldap_type, {LDAP_IPA:'636', LDAP_GENERIC:'389'})),
+ LdapPropTemplate(properties, options.ldap_primary_host, "ambari.ldap.connectivity.server.host", "Primary LDAP Host{0}: ", REGEX_HOSTNAME, False, LdapDefaultMap({LDAP_IPA:'ipa.ambari.apache.org', LDAP_GENERIC:'ldap.ambari.apache.org'})),
+ LdapPropTemplate(properties, options.ldap_primary_port, "ambari.ldap.connectivity.server.port", "Primary LDAP Port{0}: ", REGEX_PORT, False, LdapDefaultMap({LDAP_IPA:'636', LDAP_GENERIC:'389'})),
LdapPropTemplate(properties, options.ldap_secondary_host, "ambari.ldap.connectivity.secondary.server.host", "Secondary LDAP Host <Optional>{0}: ", REGEX_HOSTNAME, True),
LdapPropTemplate(properties, options.ldap_secondary_port, "ambari.ldap.connectivity.secondary.server.port", "Secondary LDAP Port <Optional>{0}: ", REGEX_PORT, True),
- LdapPropTemplate(properties, options.ldap_ssl, "ambari.ldap.connectivity.use_ssl", "Use SSL [true/false]{0}: ", REGEX_TRUE_FALSE, False, get_default_prop_value(ldap_type, {LDAP_AD:'false', LDAP_IPA:'true', LDAP_GENERIC:'false'})),
- LdapPropTemplate(properties, options.ldap_user_class, "ambari.ldap.attributes.user.object_class", "User object class{0}: ", REGEX_ANYTHING, False, get_default_prop_value(ldap_type, {LDAP_AD:'user', LDAP_IPA:'posixUser', LDAP_GENERIC:'posixUser'})),
- LdapPropTemplate(properties, options.ldap_user_attr, "ambari.ldap.attributes.user.name_attr", "User ID attribute{0}: ", REGEX_ANYTHING, False, get_default_prop_value(ldap_type, {LDAP_AD:'sAMAccountName', LDAP_IPA:'uid', LDAP_GENERIC:'uid'})),
- LdapPropTemplate(properties, options.ldap_group_class, "ambari.ldap.attributes.group.object_class", "Group object class{0}: ", REGEX_ANYTHING, False, get_default_prop_value(ldap_type, {LDAP_AD:'group', LDAP_IPA:'posixGroup', LDAP_GENERIC:'posixGroup'})),
- LdapPropTemplate(properties, options.ldap_group_attr, "ambari.ldap.attributes.group.name_attr", "Group name attribute{0}: ", REGEX_ANYTHING, False, "cn"),
- LdapPropTemplate(properties, options.ldap_member_attr, "ambari.ldap.attributes.group.member_attr", "Group member attribute{0}: ", REGEX_ANYTHING, False, get_default_prop_value(ldap_type, {LDAP_AD:'member', LDAP_IPA:'memberUid', LDAP_GENERIC:'memberUid'})),
- LdapPropTemplate(properties, options.ldap_dn, "ambari.ldap.attributes.dn_attr", "Distinguished name attribute{0}: ", REGEX_ANYTHING, False, get_default_prop_value(ldap_type, {LDAP_AD:'distinguishedName', LDAP_IPA:'dn', LDAP_GENERIC:'dn'})),
- LdapPropTemplate(properties, options.ldap_base_dn, "ambari.ldap.attributes.user.search_base", "Search Base{0}: ", REGEX_ANYTHING, False, "dc=ambari,dc=apache,dc=org"),
- LdapPropTemplate(properties, options.ldap_referral, "ambari.ldap.advanced.referrals", "Referral method [follow/ignore]{0}: ", REGEX_REFERRAL, True, "follow"),
- LdapPropTemplate(properties, options.ldap_bind_anonym, "ambari.ldap.connectivity.anonymous_bind", "Bind anonymously [true/false]{0}: ", REGEX_TRUE_FALSE, False, "false"),
- LdapPropTemplate(properties, options.ldap_sync_username_collisions_behavior, "ambari.ldap.advanced.collision_behavior", "Handling behavior for username collisions [convert/skip] for LDAP sync{0}: ", REGEX_SKIP_CONVERT, False, "skip"),
+ LdapPropTemplate(properties, options.ldap_ssl, "ambari.ldap.connectivity.use_ssl", "Use SSL [true/false]{0}: ", REGEX_TRUE_FALSE, False, LdapDefaultMap({LDAP_AD:'false', LDAP_IPA:'true', LDAP_GENERIC:'false'})),
+ LdapPropTemplate(properties, options.ldap_user_class, "ambari.ldap.attributes.user.object_class", "User object class{0}: ", REGEX_ANYTHING, False, LdapDefaultMap({LDAP_AD:'user', LDAP_IPA:'posixAccount', LDAP_GENERIC:'posixUser'})),
+ LdapPropTemplate(properties, options.ldap_user_attr, "ambari.ldap.attributes.user.name_attr", "User ID attribute{0}: ", REGEX_ANYTHING, False, LdapDefaultMap({LDAP_AD:'sAMAccountName', LDAP_IPA:'uid', LDAP_GENERIC:'uid'})),
+ LdapPropTemplate(properties, options.ldap_group_class, "ambari.ldap.attributes.group.object_class", "Group object class{0}: ", REGEX_ANYTHING, False, LdapDefaultMap({LDAP_AD:'group', LDAP_IPA:'posixGroup', LDAP_GENERIC:'posixGroup'})),
+ LdapPropTemplate(properties, options.ldap_group_attr, "ambari.ldap.attributes.group.name_attr", "Group name attribute{0}: ", REGEX_ANYTHING, False, LdapDefault("cn")),
+ LdapPropTemplate(properties, options.ldap_member_attr, "ambari.ldap.attributes.group.member_attr", "Group member attribute{0}: ", REGEX_ANYTHING, False, LdapDefaultMap({LDAP_AD:'member', LDAP_IPA:'memberUid', LDAP_GENERIC:'memberUid'})),
+ LdapPropTemplate(properties, options.ldap_dn, "ambari.ldap.attributes.dn_attr", "Distinguished name attribute{0}: ", REGEX_ANYTHING, False, LdapDefaultMap({LDAP_AD:'distinguishedName', LDAP_IPA:'dn', LDAP_GENERIC:'dn'})),
+ LdapPropTemplate(properties, options.ldap_base_dn, "ambari.ldap.attributes.user.search_base", "Search Base{0}: ", REGEX_ANYTHING, False, LdapDefaultMap({LDAP_AD:'dc=ambari,dc=apache,dc=org', LDAP_IPA:'cn=accounts,dc=ambari,dc=apache,dc=org', LDAP_GENERIC:'dc=ambari,dc=apache,dc=org'})),
+ LdapPropTemplate(properties, options.ldap_referral, "ambari.ldap.advanced.referrals", "Referral method [follow/ignore]{0}: ", REGEX_REFERRAL, True, LdapDefault("follow")),
+ LdapPropTemplate(properties, options.ldap_bind_anonym, "ambari.ldap.connectivity.anonymous_bind", "Bind anonymously [true/false]{0}: ", REGEX_TRUE_FALSE, False, LdapDefault("false")),
+ LdapPropTemplate(properties, options.ldap_sync_username_collisions_behavior, "ambari.ldap.advanced.collision_behavior", "Handling behavior for username collisions [convert/skip] for LDAP sync{0}: ", REGEX_SKIP_CONVERT, False, LdapDefault("skip")),
LdapPropTemplate(properties, options.ldap_force_lowercase_usernames, "ambari.ldap.advanced.force_lowercase_usernames", "Force lower-case user names [true/false]{0}:", REGEX_TRUE_FALSE, True),
LdapPropTemplate(properties, options.ldap_pagination_enabled, "ambari.ldap.advanced.pagination_enabled", "Results from LDAP are paginated when requested [true/false]{0}:", REGEX_TRUE_FALSE, True)
]
return ldap_properties
-def get_default_prop_value(ldap_type, default_value_map):
- return default_value_map[ldap_type] if ldap_type in default_value_map else None
-
-
-def update_ldap_configuration(options, properties, ldap_property_value_map):
- admin_login, admin_password = get_ambari_admin_username_password_pair(options)
+def update_ldap_configuration(admin_login, admin_password, properties, ldap_property_value_map):
request_data = {
"Configuration": {
"category": "ldap-configuration",
@@ -705,9 +749,15 @@ def update_ldap_configuration(options, properties, ldap_property_value_map):
request_data['Configuration']['properties'] = ldap_property_value_map
perform_changes_via_rest_api(properties, admin_login, admin_password, SETUP_LDAP_CONFIG_URL, 'PUT', request_data)
+def should_query_ldap_type(ldap_property_list_reqd):
+ for ldap_prop in ldap_property_list_reqd:
+ if ldap_prop.should_query_ldap_type():
+ return True
+ return False
+
def query_ldap_type():
- return get_validated_string_input("Please select the type of LDAP you want to use ({}):".format(", ".join(LDAP_TYPES)),
- None,
+ return get_validated_string_input("Please select the type of LDAP you want to use [{}]({}):".format("/".join(LDAP_TYPES), LDAP_GENERIC),
+ LDAP_GENERIC,
REGEX_LDAP_TYPE,
"Please enter one of the followings '{}'!".format("', '".join(LDAP_TYPES)),
False,
@@ -735,6 +785,12 @@ def setup_ldap(options):
err = "Currently '" + current_client_security + "' configured. Can not setup LDAP."
raise FatalException(1, err)
+ admin_login, admin_password = get_ambari_admin_username_password_pair(options)
+ ldap_properties = get_ldap_properties_from_db(properties, admin_login, admin_password)
+ if ldap_properties:
+ properties.update(ldap_properties)
+ sys.stdout.write('\n')
+
isSecure = get_is_secure(properties)
if options.ldap_url:
@@ -745,9 +801,13 @@ def setup_ldap(options):
options.ldap_secondary_host = options.ldap_secondary_url.split(':')[0]
options.ldap_secondary_port = options.ldap_secondary_url.split(':')[1]
- ldap_type = query_ldap_type()
- ldap_property_list_reqd = init_ldap_properties_list_reqd(properties, options, ldap_type)
+ ldap_property_list_reqd = init_ldap_properties_list_reqd(properties, options)
+ ldap_bind_dn_template = LdapPropTemplate(properties, options.ldap_manager_dn, LDAP_MGR_USERNAME_PROPERTY, "Bind DN{0}: ", REGEX_ANYTHING, False, LdapDefaultMap({
+ LDAP_AD:'cn=ldapbind,dc=ambari,dc=apache,dc=org',
+ LDAP_IPA:'uid=ldapbind,cn=users,cn=accounts,dc=ambari,dc=apache,dc=org',
+ LDAP_GENERIC:'uid=ldapbind,cn=users,dc=ambari,dc=apache,dc=org'}))
+ ldap_type = LDAP_GENERIC if options.ldap_use_generic_defaults or not should_query_ldap_type(ldap_property_list_reqd) else query_ldap_type()
ldap_property_list_opt = [LDAP_MGR_USERNAME_PROPERTY,
LDAP_MGR_PASSWORD_PROPERTY,
@@ -758,20 +818,16 @@ def setup_ldap(options):
ldap_property_list_passwords=[LDAP_MGR_PASSWORD_PROPERTY, SSL_TRUSTSTORE_PASSWORD_PROPERTY]
- ldap_mgr_dn_default = get_default_prop_value(ldap_type, {
- LDAP_AD:'cn=ldapbind,dc=ambari,dc=apache,dc=org',
- LDAP_IPA:'uid=ldapbind,cn=users,cn=accounts,dc=ambari,dc=apache,dc=org',
- LDAP_GENERIC:'uid=ldapbind,cn=users,dc=ambari,dc=apache,dc=org'})
- SSL_TRUSTSTORE_TYPE_DEFAULT = get_value_from_properties(properties, SSL_TRUSTSTORE_TYPE_PROPERTY, "jks")
- SSL_TRUSTSTORE_PATH_DEFAULT = get_value_from_properties(properties, SSL_TRUSTSTORE_PATH_PROPERTY)
+ ssl_truststore_type_default = get_value_from_properties(properties, SSL_TRUSTSTORE_TYPE_PROPERTY, "jks")
+ ssl_truststore_path_default = get_value_from_properties(properties, SSL_TRUSTSTORE_PATH_PROPERTY)
+ disable_endpoint_identification_default = get_value_from_properties(properties, LDAP_DISABLE_ENDPOINT_IDENTIFICATION, "False")
ldap_property_value_map = {}
ldap_property_values_in_ambari_properties = {}
for ldap_prop in ldap_property_list_reqd:
- input = get_validated_string_input(ldap_prop.ldap_prop_val_prompt, ldap_prop.ldap_prop_value, ldap_prop.prompt_regex,
- "Invalid characters in the input!", False, ldap_prop.allow_empty_prompt,
- answer = ldap_prop.option)
+ input = ldap_prop.get_input(ldap_type)
+
if input is not None and input != "":
ldap_property_value_map[ldap_prop.prop_name] = input
@@ -780,10 +836,7 @@ def setup_ldap(options):
mgr_password = None
# Ask for manager credentials only if bindAnonymously is false
if not anonymous:
- username = get_validated_string_input(
- format_prop_val_prompt("Bind DN{0}: ", get_value_from_properties(properties, LDAP_MGR_USERNAME_PROPERTY, ldap_mgr_dn_default)),
- ldap_mgr_dn_default, ".*",
- "Invalid characters in the input!", False, False, answer = options.ldap_manager_dn)
+ username = ldap_bind_dn_template.get_input(ldap_type)
ldap_property_value_map[LDAP_MGR_USERNAME_PROPERTY] = username
mgr_password = configure_ldap_password(options)
ldap_property_value_map[LDAP_MGR_PASSWORD_PROPERTY] = mgr_password
@@ -792,12 +845,13 @@ def setup_ldap(options):
ts_password = None
if ldaps:
- disable_endpoint_identification = get_validated_string_input("Disable endpoint identification during SSL handshake [true/false] (false): ", "false",
+ disable_endpoint_identification = get_validated_string_input("Disable endpoint identification during SSL handshake [true/false] ({0}): ".format(disable_endpoint_identification_default),
+ disable_endpoint_identification_default,
REGEX_TRUE_FALSE, "Invalid characters in the input!", False, allowEmpty=True, answer=options.ldap_sync_disable_endpoint_identification)
ldap_property_value_map[LDAP_DISABLE_ENDPOINT_IDENTIFICATION] = disable_endpoint_identification
truststore_default = "n"
- truststore_set = bool(SSL_TRUSTSTORE_PATH_DEFAULT)
+ truststore_set = bool(ssl_truststore_path_default)
if truststore_set:
truststore_default = "y"
custom_trust_store = True if options.trust_store_path is not None and options.trust_store_path else False
@@ -806,12 +860,12 @@ def setup_ldap(options):
format(truststore_default),
truststore_set)
if custom_trust_store:
- ts_type = get_validated_string_input("TrustStore type [jks/jceks/pkcs12] {0}:".format(get_prompt_default(SSL_TRUSTSTORE_TYPE_DEFAULT)),
- SSL_TRUSTSTORE_TYPE_DEFAULT, "^(jks|jceks|pkcs12)?$", "Wrong type", False, answer=options.trust_store_type)
+ ts_type = get_validated_string_input("TrustStore type [jks/jceks/pkcs12] {0}:".format(get_prompt_default(ssl_truststore_type_default)),
+ ssl_truststore_type_default, "^(jks|jceks|pkcs12)?$", "Wrong type", False, answer=options.trust_store_type)
ts_path = None
while True:
- ts_path = get_validated_string_input("Path to TrustStore file {0}:".format(get_prompt_default(SSL_TRUSTSTORE_PATH_DEFAULT)),
- SSL_TRUSTSTORE_PATH_DEFAULT, ".*", False, False, answer = options.trust_store_path)
+ ts_path = get_validated_string_input(format_prop_val_prompt("Path to TrustStore file{0}: ", ssl_truststore_path_default),
+ ssl_truststore_path_default, ".*", False, False, answer = options.trust_store_path)
if os.path.exists(ts_path):
break
else:
@@ -842,7 +896,7 @@ def setup_ldap(options):
print '=' * 20
for property in ldap_property_list_reqd:
if ldap_property_value_map.has_key(property.prop_name):
- print("%s %s" % (property.ldap_prop_val_prompt, ldap_property_value_map[property.prop_name]))
+ print("%s %s" % (property.get_prompt_text(ldap_type), ldap_property_value_map[property.prop_name]))
for property in ldap_property_list_opt:
if ldap_property_value_map.has_key(property):
@@ -882,7 +936,7 @@ def setup_ldap(options):
ldap_property_value_map[IS_LDAP_CONFIGURED] = "true"
#Saving LDAP configuration in Ambari DB using the REST API
- update_ldap_configuration(options, properties, ldap_property_value_map)
+ update_ldap_configuration(admin_login, admin_password, properties, ldap_property_value_map)
#The only properties we want to write out in Ambari.properties are the client.security type being LDAP and the custom Truststore related properties (if any)
ldap_property_values_in_ambari_properties[CLIENT_SECURITY] = 'ldap'
diff --git a/ambari-server/src/test/python/TestAmbariServer.py b/ambari-server/src/test/python/TestAmbariServer.py
index 3b9adf6..affea57 100644
--- a/ambari-server/src/test/python/TestAmbariServer.py
+++ b/ambari-server/src/test/python/TestAmbariServer.py
@@ -109,7 +109,7 @@ with patch.object(platform, "linux_distribution", return_value = MagicMock(retur
SRVR_ONE_WAY_SSL_PORT_PROPERTY, SRVR_TWO_WAY_SSL_PORT_PROPERTY
from ambari_server.setupSecurity import adjust_directory_permissions, get_alias_string, get_ldap_event_spec_names, sync_ldap, \
configure_ldap_password, setup_ldap, REGEX_HOSTNAME_PORT, REGEX_TRUE_FALSE, REGEX_ANYTHING, setup_master_key, \
- setup_ambari_krb5_jaas
+ setup_ambari_krb5_jaas, LDAP_GENERIC, should_query_ldap_type, LdapPropTemplate, LdapDefault, LdapDefaultMap
from ambari_server.userInput import get_YN_input, get_choice_string_input, get_validated_string_input, \
read_password
from ambari_server_main import get_ulimit_open_files, ULIMIT_OPEN_FILES_KEY, ULIMIT_OPEN_FILES_DEFAULT
@@ -7131,8 +7131,8 @@ class TestAmbariServer(TestCase):
@patch("ambari_server.setupSecurity.get_ambari_properties")
@patch("ambari_server.setupSecurity.logger")
@patch("ambari_server.setupSecurity.is_server_runing")
- @patch("ambari_server.setupSecurity.query_ldap_type")
- def test_setup_ldap_invalid_input(self, query_ldap_type_method, is_server_runing_method, logger_mock, get_ambari_properties_method,
+ @patch("ambari_server.setupSecurity.get_ldap_properties_from_db")
+ def test_setup_ldap_invalid_input(self, get_ldap_properties_from_db_method, is_server_runing_method, logger_mock, get_ambari_properties_method,
search_file_message,
update_properties_method,
get_YN_input_method,
@@ -7142,7 +7142,7 @@ class TestAmbariServer(TestCase):
sys.stdout = out
is_server_runing_method.return_value = (True, 0)
search_file_message.return_value = "filepath"
- query_ldap_type_method.return_value = 'Generic LDAP'
+ get_ldap_properties_from_db_method.return_value = None
properties = Properties();
properties.process_pair(SECURITY_MASTER_KEY_LOCATION, "filepath")
@@ -7151,7 +7151,7 @@ class TestAmbariServer(TestCase):
properties.process_pair(CLIENT_API_PORT_PROPERTY, '8080')
get_ambari_properties_method.return_value = properties
- raw_input_mock.side_effect = ['a', '3', 'b', 'b', 'hody', 'b', '2', 'false', 'user', 'uid', 'group', 'cn', 'member', 'dn', 'base', 'follow', 'true', 'skip', 'false', 'false', 'admin']
+ raw_input_mock.side_effect = [LDAP_GENERIC, 'a', '3', 'b', 'b', 'hody', 'b', '2', 'false', 'user', 'uid', 'group', 'cn', 'member', 'dn', 'base', 'follow', 'true', 'skip', 'false', 'false', 'admin']
get_password_mock.side_effect = ['admin']
set_silent(False)
get_YN_input_method.return_value = True
@@ -7184,7 +7184,7 @@ class TestAmbariServer(TestCase):
self.assertEqual(1, get_password_mock.call_count)
raw_input_mock.reset_mock()
- raw_input_mock.side_effect = ['a', '3', '', '', 'b', '2', 'false', 'user', 'uid', 'group', 'cn', 'member', 'dn', 'base', 'follow', 'true', 'skip', 'false', 'false', 'admin']
+ raw_input_mock.side_effect = [LDAP_GENERIC, 'a', '3', '', '', 'b', '2', 'false', 'user', 'uid', 'group', 'cn', 'member', 'dn', 'base', 'follow', 'true', 'skip', 'false', 'false', 'admin']
get_password_mock.reset_mock()
get_password_mock.side_effect = ['admin']
@@ -7298,7 +7298,9 @@ class TestAmbariServer(TestCase):
@patch("os.path.exists")
@patch("ambari_server.setupSecurity.logger")
@patch("ambari_server.setupSecurity.is_server_runing")
- def test_setup_ldap(self, is_server_runing_method, logger_mock, exists_method, read_password_method, get_ambari_properties_method,
+ @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,
search_file_message,
get_validated_string_input_method,
configure_ldap_password_method, update_properties_method,
@@ -7312,6 +7314,9 @@ class TestAmbariServer(TestCase):
options.ambari_admin_password = 'admin'
is_server_runing_method.return_value = (True, 0)
+ get_ldap_properties_from_db_method.return_value = None
+ query_ldap_type_method.return_value = LDAP_GENERIC
+
search_file_message.return_value = "filepath"
properties = Properties();
@@ -7453,13 +7458,15 @@ class TestAmbariServer(TestCase):
@patch("ambari_server.setupSecurity.get_validated_string_input")
@patch("ambari_server.setupSecurity.get_ambari_properties")
@patch("ambari_server.setupSecurity.is_server_runing")
- def test_setup_ldap_primary_host_and_port_with_ldap_url_option(self, is_server_runing_method, get_ambari_properties_method,
+ @patch("ambari_server.setupSecurity.get_ldap_properties_from_db")
+ def test_setup_ldap_primary_host_and_port_with_ldap_url_option(self, get_ldap_properties_from_db_method, is_server_runing_method, get_ambari_properties_method,
get_validated_string_input_method, read_password_method, get_YN_input_method, urlopen_method):
out = StringIO.StringIO()
sys.stdout = out
is_server_runing_method.return_value = (True, 0)
+ get_ldap_properties_from_db_method.return_value = None
def yn_input_side_effect(*args, **kwargs):
if 'TrustStore' in args[0]:
@@ -7494,6 +7501,7 @@ class TestAmbariServer(TestCase):
options = self._create_empty_options_mock()
options.ambari_admin_username = 'admin'
options.ambari_admin_password = 'admin'
+ options.ldap_type = LDAP_GENERIC
options.ldap_url = "a:1"
setup_ldap(options)
@@ -7518,13 +7526,15 @@ class TestAmbariServer(TestCase):
@patch("ambari_server.setupSecurity.get_validated_string_input")
@patch("ambari_server.setupSecurity.get_ambari_properties")
@patch("ambari_server.setupSecurity.is_server_runing")
- def test_setup_ldap_with_ambari_admin_username_and_password_options(self, is_server_runing_method, get_ambari_properties_method,
+ @patch("ambari_server.setupSecurity.get_ldap_properties_from_db")
+ def test_setup_ldap_with_ambari_admin_username_and_password_options(self, get_ldap_properties_from_db_method, is_server_runing_method, get_ambari_properties_method,
get_validated_string_input_method, get_YN_input_method, urlopen_method):
out = StringIO.StringIO()
sys.stdout = out
is_server_runing_method.return_value = (True, 0)
+ get_ldap_properties_from_db_method.return_value = None
def yn_input_side_effect(*args, **kwargs):
return False if 'TrustStore' in args[0] else True
@@ -7558,6 +7568,7 @@ class TestAmbariServer(TestCase):
options = self._create_empty_options_mock()
options.ambari_admin_username = 'admin'
options.ambari_admin_password = 'admin'
+ options.ldap_type = LDAP_GENERIC
setup_ldap(options)
@@ -7572,12 +7583,16 @@ class TestAmbariServer(TestCase):
@patch("ambari_server.setupSecurity.get_validated_string_input")
@patch("ambari_server.setupSecurity.get_ambari_properties")
@patch("ambari_server.setupSecurity.is_server_runing")
- def test_setup_ldap_enforcement_cli_option(self, is_server_runing_method, get_ambari_properties_method,
+ @patch("ambari_server.setupSecurity.query_ldap_type")
+ @patch("ambari_server.setupSecurity.get_ldap_properties_from_db")
+ def test_setup_ldap_enforcement_cli_option(self, get_ldap_properties_from_db_method, query_ldap_type_method, is_server_runing_method, get_ambari_properties_method,
get_validated_string_input_method, get_YN_input_method, urlopen_method):
out = StringIO.StringIO()
sys.stdout = out
is_server_runing_method.return_value = (True, 0)
+ query_ldap_type_method.return_value = LDAP_GENERIC
+ get_ldap_properties_from_db_method.return_value = None
def yn_input_side_effect(*args, **kwargs):
if 'do you wish to use LDAP instead' in args[0]:
@@ -7622,6 +7637,84 @@ class TestAmbariServer(TestCase):
sys.stdout = sys.__stdout__
pass
+ def test_should_query_ldap_type_returns_false_if_no_prop_requires_ldap_type(self):
+ prop_template0 = MagicMock()
+ prop_template0.should_query_ldap_type.return_value = False
+ prop_template1 = MagicMock()
+ prop_template1.should_query_ldap_type.return_value = False
+ ldap_properties = [prop_template0, prop_template1]
+ self.assertFalse(should_query_ldap_type(ldap_properties))
+ pass
+
+ def test_should_query_ldap_type_returns_true_if_any_prop_requires_ldap_type(self):
+ prop_template0 = MagicMock()
+ prop_template0.should_query_ldap_type.return_value = False
+ prop_template1 = MagicMock()
+ prop_template1.should_query_ldap_type.return_value = True
+ ldap_properties = [prop_template0, prop_template1]
+ self.assertTrue(should_query_ldap_type(ldap_properties))
+ pass
+
+ def test_LdapPropTemplate_should_query_ldap_type_returns_false_if_empty_prompt_is_allowed(self):
+ prop_template = LdapPropTemplate(Properties(), None, "any.prop", "Any prop:", REGEX_ANYTHING, True)
+ self.assertFalse(prop_template.should_query_ldap_type())
+ pass
+
+ def test_LdapPropTemplate_should_query_ldap_type_returns_false_if_option_value_is_present(self):
+ prop_template = LdapPropTemplate(Properties(), 'value', "any.prop", "Any prop:", REGEX_ANYTHING, False)
+ self.assertFalse(prop_template.should_query_ldap_type())
+ pass
+
+ def test_LdapPropTemplate_should_query_ldap_type_returns_false_if_property_value_is_present(self):
+ properties = Properties()
+ properties.process_pair("a.prop", "value")
+ prop_template = LdapPropTemplate(properties, None, "a.prop", "Any prop:", REGEX_ANYTHING, False, LdapDefaultMap({'key' : 'default_value'}))
+ self.assertFalse(prop_template.should_query_ldap_type())
+ pass
+
+ def test_LdapPropTemplate_should_query_ldap_type_returns_false_if_default_is_not_depend_on_ldap_type(self):
+ prop_template = LdapPropTemplate(Properties(), None, "a.prop", "Any prop:", REGEX_ANYTHING, False, LdapDefault('default_value'))
+ self.assertFalse(prop_template.should_query_ldap_type())
+ pass
+
+ def test_LdapPropTemplate_should_query_ldap_type_returns_true_if_property_value_is_depends_on_ldap_type_and_no_option_and_property_is_given(self):
+ prop_template = LdapPropTemplate(Properties(), None, "a.prop", "Any prop:", REGEX_ANYTHING, False, LdapDefaultMap({'key' : 'default_value'}))
+ self.assertTrue(prop_template.should_query_ldap_type())
+ pass
+
+ def test_LdapPropTemplate_get_default_value_returns_stored_property_value_if_presents(self):
+ properties = Properties()
+ properties.process_pair("a.prop", "value")
+ prop_template = LdapPropTemplate(properties, None, "a.prop", "Any prop:", REGEX_ANYTHING, False, LdapDefaultMap('default_value'))
+ self.assertEquals(prop_template.get_default_value('any_type'), "value")
+ pass
+
+ def test_LdapPropTemplate_get_default_value_returns_default_value_if_stored_property_value_not_exists(self):
+ prop_template = LdapPropTemplate(Properties(), None, "a.prop", "Any prop:", REGEX_ANYTHING, False, LdapDefault('default_value'))
+ self.assertEquals(prop_template.get_default_value('any_type'), "default_value")
+ pass
+
+ def test_LdapPropTemplate_get_default_value_returns_none_if_stored_property_value_not_exists_and_no_default_value_was_specified(self):
+ prop_template = LdapPropTemplate(Properties(), None, "a.prop", "Any prop:", REGEX_ANYTHING, False)
+ self.assertEquals(prop_template.get_default_value('any_type'), None)
+ pass
+
+ def test_LdapDefaultMap_get_default_value_returns_none_if_default_map_is_none(self):
+ default_map = LdapDefaultMap(None)
+ self.assertEquals(default_map.get_default_value('any_type'), None)
+ pass
+
+ def test_LdapDefaultMap_get_default_value_returns_none_if_key_not_present(self):
+ default_map = LdapDefaultMap({LDAP_GENERIC : 'value'})
+ self.assertEquals(default_map.get_default_value('non_existent_type'), None)
+ pass
+
+ def test_LdapDefaultMap_get_default_value_returns_key_value_if_key_presents(self):
+ default_map = LdapDefaultMap({LDAP_GENERIC : 'value'})
+ self.assertEquals(default_map.get_default_value(LDAP_GENERIC), 'value')
+ pass
+
+
@patch("urllib2.urlopen")
@patch("ambari_server.setupSecurity.get_validated_string_input")
@patch("ambari_server.setupSecurity.get_ambari_properties")