This is an automated email from the ASF dual-hosted git repository. ncole pushed a commit to branch branch-feature-AMBARI-21674 in repository https://gitbox.apache.org/repos/asf/ambari.git
commit 49d8082d3cfb3af448933b331ae0ac225771d903 Author: Sandor Molnar <smol...@hortonworks.com> AuthorDate: Fri Jan 19 16:12:19 2018 +0100 AMBARI-22797. The stup-ldap tool should persists its output into Ambari database rather than ambari.properties --- .../internal/AmbariServerConfigurationHandler.java | 9 +- ambari-server/src/main/python/ambari-server.py | 12 +- .../python/ambari_server/serverConfiguration.py | 7 +- .../src/main/python/ambari_server/serverUpgrade.py | 8 +- .../src/main/python/ambari_server/setupSecurity.py | 136 +++++--- ...ComponentConfigurationResourceProviderTest.java | 2 +- ambari-server/src/test/python/TestAmbariServer.py | 381 +++++++++++++-------- 7 files changed, 356 insertions(+), 199 deletions(-) diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AmbariServerConfigurationHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AmbariServerConfigurationHandler.java index f3ff2dd..f96ad08 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AmbariServerConfigurationHandler.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AmbariServerConfigurationHandler.java @@ -115,10 +115,13 @@ class AmbariServerConfigurationHandler extends RootServiceComponentConfiguration while (propertiesIterator.hasNext()) { Map.Entry<String, String> property = propertiesIterator.next(); if (AmbariServerConfigurationUtils.isPassword(categoryName, property.getKey())) { - if (updatePasswordIfNeeded(categoryName, property.getKey(), property.getValue())) { - toBePublished = true; + final String passwordFileOrCredentailStoreAlias = fetchPasswordFileNameOrCredentialStoreAlias(categoryName, property.getKey()); + if (StringUtils.isNotBlank(passwordFileOrCredentailStoreAlias)) { //if blank -> this is the first time setup; we simply need to store the alias/file name + if (updatePasswordIfNeeded(categoryName, property.getKey(), property.getValue())) { + toBePublished = true; + } + propertiesIterator.remove(); //we do not need to change the any PASSWORD type configuration going forward } - propertiesIterator.remove(); //we do not need to change the any PASSWORD type configuration going forward } } diff --git a/ambari-server/src/main/python/ambari-server.py b/ambari-server/src/main/python/ambari-server.py index 4fd82e8..72dd292 100755 --- a/ambari-server/src/main/python/ambari-server.py +++ b/ambari-server/src/main/python/ambari-server.py @@ -532,8 +532,10 @@ def init_ldap_sync_parser_options(parser): @OsFamilyFuncImpl(OsFamilyImpl.DEFAULT) def init_ldap_setup_parser_options(parser): - parser.add_option('--ldap-url', default=None, help="Primary url for LDAP", dest="ldap_url") - parser.add_option('--ldap-secondary-url', default=None, help="Secondary url for LDAP", dest="ldap_secondary_url") + parser.add_option('--ldap-url-host', default=None, help="Primary Host for LDAP", dest="ldap_url_host") + parser.add_option('--ldap-url-port', default=None, help="Primary Port for LDAP", dest="ldap_url_port") + parser.add_option('--ldap-secondary-url-host', default=None, help="Secondary Host for LDAP", dest="ldap_secondary_url_host") + parser.add_option('--ldap-secondary-url-port', default=None, help="Secondary Port for LDAP", dest="ldap_secondary_url_port") parser.add_option('--ldap-ssl', default=None, help="Use SSL [true/false] for LDAP", dest="ldap_ssl") 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") @@ -548,6 +550,8 @@ def init_ldap_setup_parser_options(parser): parser.add_option('--ldap-referral', default=None, help="Referral method [follow/ignore] for LDAP", dest="ldap_referral") parser.add_option('--ldap-bind-anonym', default=None, help="Bind anonymously [true/false] for LDAP", dest="ldap_bind_anonym") parser.add_option('--ldap-sync-username-collisions-behavior', default=None, help="Handling behavior for username collisions [convert/skip] for LDAP sync", dest="ldap_sync_username_collisions_behavior") + parser.add_option('--ldap-force-lowercase-usernames', default=None, help="Declares whether to force the ldap user name to be lowercase or leave as-is", dest="ldap_force_lowercase_usernames") + parser.add_option('--ldap-pagination-enabled', default=None, help="Determines whether results from LDAP are paginated when requested", dest="ldap_pagination_enabled") @OsFamilyFuncImpl(OsFamilyImpl.DEFAULT) def init_pam_setup_parser_options(parser): @@ -972,10 +976,6 @@ def mainBody(): parser = optparse.OptionParser(usage="usage: %prog action [options]",) action = sys.argv[1] - if action == "setup-ldap": - print "setup-ldap action is deprecated. Please configure LDAP integration from the Ambari UI" - sys.exit(0) - init_action_parser(action, parser) (options, args) = parser.parse_args() diff --git a/ambari-server/src/main/python/ambari_server/serverConfiguration.py b/ambari-server/src/main/python/ambari_server/serverConfiguration.py index fd8bf73..fc9a28f 100644 --- a/ambari-server/src/main/python/ambari_server/serverConfiguration.py +++ b/ambari-server/src/main/python/ambari_server/serverConfiguration.py @@ -112,6 +112,7 @@ JDBC_RCA_PASSWORD_FILENAME = "rca_password.dat" CLIENT_API_PORT_PROPERTY = "client.api.port" CLIENT_API_PORT = "8080" +CLIENT_SECURITY = "client.security" SERVER_VERSION_FILE_PATH = "server.version.file" @@ -158,12 +159,8 @@ RESOURCES_DIR_PROPERTY = "resources.dir" STACK_LOCATION_KEY = 'metadata.path' # LDAP security -IS_LDAP_CONFIGURED = "ambari.ldap.isConfigured" LDAP_MGR_PASSWORD_ALIAS = "ambari.ldap.manager.password" -LDAP_MGR_PASSWORD_PROPERTY = "authentication.ldap.managerPassword" -LDAP_MGR_PASSWORD_FILENAME = "ldap-password.dat" -LDAP_MGR_USERNAME_PROPERTY = "authentication.ldap.managerDn" -LDAP_PRIMARY_URL_PROPERTY = "authentication.ldap.primaryUrl" +LDAP_MGR_PASSWORD_PROPERTY = "ambari.ldap.connectivity.bind_password" # SSL truststore SSL_TRUSTSTORE_PASSWORD_ALIAS = "ambari.ssl.trustStore.password" diff --git a/ambari-server/src/main/python/ambari_server/serverUpgrade.py b/ambari-server/src/main/python/ambari_server/serverUpgrade.py index dd847e3..accbd26 100644 --- a/ambari-server/src/main/python/ambari_server/serverUpgrade.py +++ b/ambari-server/src/main/python/ambari_server/serverUpgrade.py @@ -40,7 +40,7 @@ from ambari_server.serverConfiguration import configDefaults, get_resources_loca check_database_name_property, get_ambari_properties, get_ambari_version, \ get_java_exe_path, get_stack_location, parse_properties_file, read_ambari_user, update_ambari_properties, \ update_database_name_property, get_admin_views_dir, get_views_dir, get_views_jars, \ - AMBARI_PROPERTIES_FILE, IS_LDAP_CONFIGURED, LDAP_PRIMARY_URL_PROPERTY, RESOURCES_DIR_PROPERTY, \ + AMBARI_PROPERTIES_FILE, CLIENT_SECURITY, RESOURCES_DIR_PROPERTY, \ SETUP_OR_UPGRADE_MSG, update_krb_jaas_login_properties, AMBARI_KRB_JAAS_LOGIN_FILE, get_db_type, update_ambari_env, \ AMBARI_ENV_FILE, JDBC_DATABASE_PROPERTY, get_default_views_dir, write_gpl_license_accepted from ambari_server.setupSecurity import adjust_directory_permissions, \ @@ -304,9 +304,9 @@ def upgrade(args): for views_jar in views_jars: os.utime(views_jar, None) - # check if ambari has obsolete LDAP configuration - if properties.get_property(LDAP_PRIMARY_URL_PROPERTY) and not properties.get_property(IS_LDAP_CONFIGURED): - args.warnings.append("Existing LDAP configuration is detected. You must run the \"ambari-server setup-ldap\" command to adjust existing LDAP configuration.") + # check if ambari is configured to use LDAP authentication + if properties.get_property(CLIENT_SECURITY) == "ldap": + args.warnings.append("LDAP authentication is detected. You must run the \"ambari-server setup-ldap\" command to adjust existing LDAP configuration.") # adding custom jdbc name and previous custom jdbc properties # we need that to support new dynamic jdbc names for upgraded ambari diff --git a/ambari-server/src/main/python/ambari_server/setupSecurity.py b/ambari-server/src/main/python/ambari_server/setupSecurity.py index f175d7c..47bc3e4 100644 --- a/ambari-server/src/main/python/ambari_server/setupSecurity.py +++ b/ambari-server/src/main/python/ambari_server/setupSecurity.py @@ -42,10 +42,10 @@ from ambari_server.serverConfiguration import configDefaults, parse_properties_f get_credential_store_location, get_is_persisted, get_is_secure, get_master_key_location, get_db_type, write_property, \ get_original_master_key, get_value_from_properties, get_java_exe_path, is_alias_string, read_ambari_user, \ read_passwd_for_alias, remove_password_file, save_passwd_for_alias, store_password_file, update_properties_2, \ - BLIND_PASSWORD, BOOTSTRAP_DIR_PROPERTY, IS_LDAP_CONFIGURED, JDBC_PASSWORD_FILENAME, JDBC_PASSWORD_PROPERTY, \ + BLIND_PASSWORD, BOOTSTRAP_DIR_PROPERTY, JDBC_PASSWORD_FILENAME, JDBC_PASSWORD_PROPERTY, \ JDBC_RCA_PASSWORD_ALIAS, JDBC_RCA_PASSWORD_FILE_PROPERTY, JDBC_USE_INTEGRATED_AUTH_PROPERTY, \ - LDAP_MGR_PASSWORD_ALIAS, LDAP_MGR_PASSWORD_FILENAME, LDAP_MGR_PASSWORD_PROPERTY, LDAP_MGR_USERNAME_PROPERTY, \ - LDAP_PRIMARY_URL_PROPERTY, SECURITY_IS_ENCRYPTION_ENABLED, SECURITY_KEY_ENV_VAR_NAME, SECURITY_KERBEROS_JASS_FILENAME, \ + LDAP_MGR_PASSWORD_ALIAS, LDAP_MGR_PASSWORD_PROPERTY, CLIENT_SECURITY, \ + SECURITY_IS_ENCRYPTION_ENABLED, SECURITY_KEY_ENV_VAR_NAME, SECURITY_KERBEROS_JASS_FILENAME, \ SECURITY_PROVIDER_KEY_CMD, SECURITY_MASTER_KEY_FILENAME, SSL_TRUSTSTORE_PASSWORD_ALIAS, \ SSL_TRUSTSTORE_PASSWORD_PROPERTY, SSL_TRUSTSTORE_PATH_PROPERTY, SSL_TRUSTSTORE_TYPE_PROPERTY, \ SSL_API, SSL_API_PORT, DEFAULT_SSL_API_PORT, CLIENT_API_PORT, JDK_NAME_PROPERTY, JCE_NAME_PROPERTY, JAVA_HOME_PROPERTY, \ @@ -61,6 +61,7 @@ logger = logging.getLogger(__name__) REGEX_IP_ADDRESS = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$" REGEX_HOSTNAME = "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$" +REGEX_PORT = "^([0-9]{1,5}$)" REGEX_HOSTNAME_PORT = "^(.*:[0-9]{1,5}$)" REGEX_TRUE_FALSE = "^(true|false)?$" REGEX_SKIP_CONVERT = "^(skip|convert)?$" @@ -70,14 +71,16 @@ LDAP_TO_PAM_MIGRATION_HELPER_CMD = "{0} -cp {1} " + \ "org.apache.ambari.server.security.authentication.LdapToPamMigrationHelper" + \ " >> " + configDefaults.SERVER_OUT_FILE + " 2>&1" -CLIENT_SECURITY_KEY = "client.security" - AUTO_GROUP_CREATION = "auto.group.creation" SERVER_API_LDAP_URL = 'ldap_sync_events' +SETUP_LDAP_CONFIG_URL = 'services/AMBARI/components/AMBARI_SERVER/configurations/ldap-configuration' 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" def read_master_key(isReset=False, options = None): passwordPattern = ".*" @@ -278,7 +281,7 @@ def sync_ldap(options): properties = get_ambari_properties() - if get_value_from_properties(properties,CLIENT_SECURITY_KEY,"") == 'pam': + if get_value_from_properties(properties,CLIENT_SECURITY,"") == 'pam': err = "PAM is configured. Can not sync LDAP." raise FatalException(1, err) @@ -587,37 +590,76 @@ class LdapPropTemplate: def init_ldap_properties_list_reqd(properties, options): # python2.x dict is not ordered ldap_properties = [ - LdapPropTemplate(properties, options.ldap_url, "authentication.ldap.primaryUrl", "Primary URL* {{host:port}} {0}: ", REGEX_HOSTNAME_PORT, False), - LdapPropTemplate(properties, options.ldap_secondary_url, "authentication.ldap.secondaryUrl", "Secondary URL {{host:port}} {0}: ", REGEX_HOSTNAME_PORT, True), - LdapPropTemplate(properties, options.ldap_ssl, "authentication.ldap.useSSL", "Use SSL* [true/false] {0}: ", REGEX_TRUE_FALSE, False, "false"), - LdapPropTemplate(properties, options.ldap_user_attr, "authentication.ldap.usernameAttribute", "User name attribute* {0}: ", REGEX_ANYTHING, False, "uid"), - LdapPropTemplate(properties, options.ldap_base_dn, "authentication.ldap.baseDn", "Base DN* {0}: ", REGEX_ANYTHING, False), - LdapPropTemplate(properties, options.ldap_referral, "authentication.ldap.referral", "Referral method [follow/ignore] {0}: ", REGEX_REFERRAL, True), - LdapPropTemplate(properties, options.ldap_bind_anonym, "authentication.ldap.bindAnonymously" "Bind anonymously* [true/false] {0}: ", REGEX_TRUE_FALSE, False, "false") + LdapPropTemplate(properties, options.ldap_url_host, "ambari.ldap.connectivity.server.host", "Primary URL Host* {0}: ", REGEX_HOSTNAME, False), + LdapPropTemplate(properties, options.ldap_url_port, "ambari.ldap.connectivity.server.port", "Primary URL Port* {0}: ", REGEX_PORT, False), + LdapPropTemplate(properties, options.ldap_secondary_url_host, "ambari.ldap.connectivity.secondary.server.host", "Secondary URL Host {0}: ", REGEX_HOSTNAME, True), + LdapPropTemplate(properties, options.ldap_secondary_url_port, "ambari.ldap.connectivity.secondary.server.port", "Secondary URL Port {0}: ", REGEX_PORT, True), + LdapPropTemplate(properties, options.ldap_ssl, "ambari.ldap.connectivity.use_ssl", "Use SSL* [true/false] {0}: ", REGEX_TRUE_FALSE, False, "false"), + LdapPropTemplate(properties, options.ldap_user_attr, "ambari.ldap.attributes.user.name_attr", "User name attribute* {0}: ", REGEX_ANYTHING, False, "uid"), + LdapPropTemplate(properties, options.ldap_base_dn, "ambari.ldap.attributes.user.search_base", "Base DN* {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), + LdapPropTemplate(properties, options.ldap_bind_anonym, "ambari.ldap.connectivity.anonymous_bind" "Bind anonymously* [true/false] {0}: ", REGEX_TRUE_FALSE, False, "false") ] return ldap_properties @OsFamilyFuncImpl(OsFamilyImpl.DEFAULT) def init_ldap_properties_list_reqd(properties, options): ldap_properties = [ - LdapPropTemplate(properties, options.ldap_url, LDAP_PRIMARY_URL_PROPERTY, "Primary URL* {{host:port}} {0}: ", REGEX_HOSTNAME_PORT, False), - LdapPropTemplate(properties, options.ldap_secondary_url, "authentication.ldap.secondaryUrl", "Secondary URL {{host:port}} {0}: ", REGEX_HOSTNAME_PORT, True), - LdapPropTemplate(properties, options.ldap_ssl, "authentication.ldap.useSSL", "Use SSL* [true/false] {0}: ", REGEX_TRUE_FALSE, False, "false"), - LdapPropTemplate(properties, options.ldap_user_class, "authentication.ldap.userObjectClass", "User object class* {0}: ", REGEX_ANYTHING, False, "posixAccount"), - LdapPropTemplate(properties, options.ldap_user_attr, "authentication.ldap.usernameAttribute", "User name attribute* {0}: ", REGEX_ANYTHING, False, "uid"), - LdapPropTemplate(properties, options.ldap_group_class, "authentication.ldap.groupObjectClass", "Group object class* {0}: ", REGEX_ANYTHING, False, "posixGroup"), - LdapPropTemplate(properties, options.ldap_group_attr, "authentication.ldap.groupNamingAttr", "Group name attribute* {0}: ", REGEX_ANYTHING, False, "cn"), - LdapPropTemplate(properties, options.ldap_member_attr, "authentication.ldap.groupMembershipAttr", "Group member attribute* {0}: ", REGEX_ANYTHING, False, "memberUid"), - LdapPropTemplate(properties, options.ldap_dn, "authentication.ldap.dnAttribute", "Distinguished name attribute* {0}: ", REGEX_ANYTHING, False, "dn"), - LdapPropTemplate(properties, options.ldap_base_dn, "authentication.ldap.baseDn", "Base DN* {0}: ", REGEX_ANYTHING, False), - LdapPropTemplate(properties, options.ldap_referral, "authentication.ldap.referral", "Referral method [follow/ignore] {0}: ", REGEX_REFERRAL, True), - LdapPropTemplate(properties, options.ldap_bind_anonym, "authentication.ldap.bindAnonymously", "Bind anonymously* [true/false] {0}: ", REGEX_TRUE_FALSE, False, "false"), - LdapPropTemplate(properties, options.ldap_sync_username_collisions_behavior, "ldap.sync.username.collision.behavior", "Handling behavior for username collisions [convert/skip] for LDAP sync* {0}: ", REGEX_SKIP_CONVERT, False, "convert"), + LdapPropTemplate(properties, options.ldap_url_host, "ambari.ldap.connectivity.server.host", "Primary URL Host* {0}: ", REGEX_HOSTNAME, False), + LdapPropTemplate(properties, options.ldap_url_port, "ambari.ldap.connectivity.server.port", "Primary URL Port* {0}: ", REGEX_PORT, False), + LdapPropTemplate(properties, options.ldap_secondary_url_host, "ambari.ldap.connectivity.secondary.server.host", "Secondary URL Host {0}: ", REGEX_HOSTNAME, True), + LdapPropTemplate(properties, options.ldap_secondary_url_port, "ambari.ldap.connectivity.secondary.server.port", "Secondary URL Port {0}: ", REGEX_PORT, True), + LdapPropTemplate(properties, options.ldap_ssl, "ambari.ldap.connectivity.use_ssl", "Use SSL* [true/false] {0}: ", REGEX_TRUE_FALSE, False, "false"), + LdapPropTemplate(properties, options.ldap_user_class, "ambari.ldap.attributes.user.object_class", "User object class* {0}: ", REGEX_ANYTHING, False, "person"), + LdapPropTemplate(properties, options.ldap_user_attr, "ambari.ldap.attributes.user.name_attr", "User name attribute* {0}: ", REGEX_ANYTHING, False, "uid"), + LdapPropTemplate(properties, options.ldap_group_class, "ambari.ldap.attributes.group.object_class", "Group object class* {0}: ", REGEX_ANYTHING, False, "ou=groups,dc=ambari,dc=apache,dc=org"), + 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, "memberUid"), + LdapPropTemplate(properties, options.ldap_dn, "ambari.ldap.attributes.dn_attr", "Distinguished name attribute* {0}: ", REGEX_ANYTHING, False, "dn"), + LdapPropTemplate(properties, options.ldap_base_dn, "ambari.ldap.attributes.user.search_base", "Base DN* {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), + 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.advance.collision_behavior", "Handling behavior for username collisions [convert/skip] for LDAP sync* {0}: ", REGEX_SKIP_CONVERT, False, "convert"), + 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 update_ldap_configuration(properties, ldap_property_value_map): + admin_login = get_validated_string_input("Enter Ambari Admin login: ", None, None, None, False, False) + admin_password = get_validated_string_input("Enter Ambari Admin password: ", None, None, None, True, False) + 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) + request.add_header('Authorization', 'Basic %s' % admin_auth) + request.add_header('X-Requested-By', 'ambari') + data = { + "Configuration": { + "service_name": "AMBARI", + "component_name": "AMBARI_SERVER", + "category": "ldap-configuration", + "properties": { + } + } + } + data['Configuration']['properties'] = ldap_property_value_map + request.add_data(json.dumps(data)) + request.get_method = lambda: 'PUT' + + try: + response = urllib2.urlopen(request) + except Exception as e: + err = 'Updating LDAP configuration failed. Error details: %s' % e + raise FatalException(1, err) + + response_status_code = response.getcode() + if response_status_code != 200: + err = 'Error during syncing. Http status code - ' + str(response_status_code) + raise FatalException(1, err) + def setup_ldap(options): logger.info("Setup LDAP.") + if not is_root(): err = 'Ambari-server setup-ldap should be run with ' \ 'root-level privileges' @@ -625,7 +667,12 @@ def setup_ldap(options): properties = get_ambari_properties() - if get_value_from_properties(properties,CLIENT_SECURITY_KEY,"") == 'pam': + server_status, pid = is_server_runing() + if not server_status: + err = 'Ambari Server is not running.' + raise FatalException(1, err) + + if get_value_from_properties(properties,CLIENT_SECURITY,"") == 'pam': query = "PAM is currently configured, do you wish to use LDAP instead [y/n] (n)? " if get_YN_input(query, False): pass @@ -637,20 +684,16 @@ def setup_ldap(options): ldap_property_list_reqd = init_ldap_properties_list_reqd(properties, options) - ldap_property_list_opt = ["authentication.ldap.managerDn", + ldap_property_list_opt = ["ambari.ldap.connectivity.bind_dn", LDAP_MGR_PASSWORD_PROPERTY, SSL_TRUSTSTORE_TYPE_PROPERTY, SSL_TRUSTSTORE_PATH_PROPERTY, SSL_TRUSTSTORE_PASSWORD_PROPERTY] - ldap_property_list_truststore=[SSL_TRUSTSTORE_TYPE_PROPERTY, - SSL_TRUSTSTORE_PATH_PROPERTY, - SSL_TRUSTSTORE_PASSWORD_PROPERTY] - ldap_property_list_passwords=[LDAP_MGR_PASSWORD_PROPERTY, SSL_TRUSTSTORE_PASSWORD_PROPERTY] - LDAP_MGR_DN_DEFAULT = get_value_from_properties(properties, ldap_property_list_opt[0]) + LDAP_MGR_DN_DEFAULT = None 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) @@ -663,7 +706,7 @@ def setup_ldap(options): if input is not None and input != "": ldap_property_value_map[ldap_prop.prop_name] = input - bindAnonymously = ldap_property_value_map["authentication.ldap.bindAnonymously"] + bindAnonymously = ldap_property_value_map["ambari.ldap.connectivity.anonymous_bind"] anonymous = (bindAnonymously and bindAnonymously.lower() == 'true') mgr_password = None # Ask for manager credentials only if bindAnonymously is false @@ -675,7 +718,7 @@ def setup_ldap(options): mgr_password = configure_ldap_password(options) ldap_property_value_map[LDAP_MGR_PASSWORD_PROPERTY] = mgr_password - useSSL = ldap_property_value_map["authentication.ldap.useSSL"] + useSSL = ldap_property_value_map["ambari.ldap.connectivity.use_ssl"] ldaps = (useSSL and useSSL.lower() == 'true') ts_password = None @@ -725,7 +768,7 @@ def setup_ldap(options): print 'Review Settings' print '=' * 20 for property in ldap_property_list_reqd: - if property in ldap_property_value_map: + if ldap_property_value_map.has_key(property): print("%s: %s" % (property, ldap_property_value_map[property])) for property in ldap_property_list_opt: @@ -738,7 +781,6 @@ def setup_ldap(options): save_settings = True if options.ldap_save_settings is not None else get_YN_input("Save settings [y/n] (y)? ", True) if save_settings: - ldap_property_value_map[CLIENT_SECURITY_KEY] = 'ldap' if isSecure: if mgr_password: encrypted_passwd = encrypt_password(LDAP_MGR_PASSWORD_ALIAS, mgr_password, options) @@ -753,11 +795,21 @@ def setup_ldap(options): pass # Persisting values - ldap_property_value_map[IS_LDAP_CONFIGURED] = "true" if mgr_password: ldap_property_value_map[LDAP_MGR_PASSWORD_PROPERTY] = store_password_file(mgr_password, LDAP_MGR_PASSWORD_FILENAME) + + 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(properties, ldap_property_value_map) + + #The only property we want to write out in Ambari.properties is the client.security type being LDAP + ldap_property_value_map.clear() + ldap_property_value_map[CLIENT_SECURITY] = 'ldap' update_properties_2(properties, ldap_property_value_map) - print 'Saving...done' + + print 'Saving LDAP properties finished' return 0 @@ -855,7 +907,7 @@ def setup_pam(options): properties = get_ambari_properties() - if get_value_from_properties(properties,CLIENT_SECURITY_KEY,"") == 'ldap': + if get_value_from_properties(properties,CLIENT_SECURITY,"") == 'ldap': query = "LDAP is currently configured, do you wish to use PAM instead [y/n] (n)? " if get_YN_input(query, False): pass @@ -866,7 +918,7 @@ def setup_pam(options): pam_property_list_reqd = init_pam_properties_list_reqd(properties, options) pam_property_value_map = {} - pam_property_value_map[CLIENT_SECURITY_KEY] = 'pam' + pam_property_value_map[CLIENT_SECURITY] = 'pam' for pam_prop in pam_property_list_reqd: input = get_validated_string_input(pam_prop.pam_prop_val_prompt, pam_prop.pam_prop_name, pam_prop.prompt_regex, @@ -891,7 +943,7 @@ def setup_pam(options): def migrate_ldap_pam(args): properties = get_ambari_properties() - if get_value_from_properties(properties,CLIENT_SECURITY_KEY,"") != 'pam': + if get_value_from_properties(properties,CLIENT_SECURITY,"") != 'pam': err = "PAM is not configured. Please configure PAM authentication first." raise FatalException(1, err) diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RootServiceComponentConfigurationResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RootServiceComponentConfigurationResourceProviderTest.java index bd0ff1d..6dbdd65 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RootServiceComponentConfigurationResourceProviderTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RootServiceComponentConfigurationResourceProviderTest.java @@ -530,7 +530,7 @@ public class RootServiceComponentConfigurationResourceProviderTest extends EasyM private void setupBasicExpectations(Map<String, String> expectedProperties) { expect(request.getProperties()).andReturn(propertySets).once(); expect(request.getRequestInfoProperties()).andReturn(new HashMap<>()); - expect(dao.findByCategory(LDAP_CONFIG_CATEGORY)).andReturn(createEntities(AmbariServerConfigurationCategory.LDAP_CONFIGURATION.getCategoryName(), expectedProperties)).once(); + expect(dao.findByCategory(LDAP_CONFIG_CATEGORY)).andReturn(createEntities(AmbariServerConfigurationCategory.LDAP_CONFIGURATION.getCategoryName(), expectedProperties)).times(2); expect(factory.getInstance(RootService.AMBARI.name(), RootComponent.AMBARI_SERVER.name(), LDAP_CONFIG_CATEGORY)).andReturn(new AmbariServerLDAPConfigurationHandler()).once(); } diff --git a/ambari-server/src/test/python/TestAmbariServer.py b/ambari-server/src/test/python/TestAmbariServer.py index 9152d0f..e1d0b3c 100644 --- a/ambari-server/src/test/python/TestAmbariServer.py +++ b/ambari-server/src/test/python/TestAmbariServer.py @@ -97,14 +97,14 @@ with patch.object(platform, "linux_distribution", return_value = MagicMock(retur AMBARI_CONF_VAR, AMBARI_SERVER_LIB, JDBC_DATABASE_PROPERTY, JDBC_RCA_PASSWORD_FILE_PROPERTY, \ PERSISTENCE_TYPE_PROPERTY, JDBC_URL_PROPERTY, get_conf_dir, JDBC_USER_NAME_PROPERTY, JDBC_PASSWORD_PROPERTY, \ JDBC_DATABASE_NAME_PROPERTY, OS_TYPE_PROPERTY, validate_jdk, JDBC_POSTGRES_SCHEMA_PROPERTY, \ - RESOURCES_DIR_PROPERTY, JDBC_RCA_PASSWORD_ALIAS, JDBC_RCA_SCHEMA_PROPERTY, IS_LDAP_CONFIGURED, \ + RESOURCES_DIR_PROPERTY, JDBC_RCA_PASSWORD_ALIAS, JDBC_RCA_SCHEMA_PROPERTY, \ SSL_API, SSL_API_PORT, CLIENT_API_PORT_PROPERTY,\ JDBC_CONNECTION_POOL_TYPE, JDBC_CONNECTION_POOL_ACQUISITION_SIZE, \ JDBC_CONNECTION_POOL_IDLE_TEST_INTERVAL, JDBC_CONNECTION_POOL_MAX_AGE, JDBC_CONNECTION_POOL_MAX_IDLE_TIME, \ JDBC_CONNECTION_POOL_MAX_IDLE_TIME_EXCESS,\ LDAP_MGR_PASSWORD_PROPERTY, LDAP_MGR_PASSWORD_ALIAS, JDBC_PASSWORD_FILENAME, NR_USER_PROPERTY, SECURITY_KEY_IS_PERSISTED, \ SSL_TRUSTSTORE_PASSWORD_PROPERTY, SECURITY_IS_ENCRYPTION_ENABLED, PID_DIR_PROPERTY, SSL_TRUSTSTORE_PASSWORD_ALIAS, \ - SECURITY_MASTER_KEY_LOCATION, SECURITY_KEYS_DIR, LDAP_PRIMARY_URL_PROPERTY, store_password_file, \ + SECURITY_MASTER_KEY_LOCATION, SECURITY_KEYS_DIR, store_password_file, \ get_pass_file_path, GET_FQDN_SERVICE_URL, JDBC_USE_INTEGRATED_AUTH_PROPERTY, SECURITY_KEY_ENV_VAR_NAME, \ JAVA_HOME_PROPERTY, JDK_NAME_PROPERTY, JCE_NAME_PROPERTY, STACK_LOCATION_KEY, SERVER_VERSION_FILE_PATH, \ COMMON_SERVICES_PATH_PROPERTY, WEBAPP_DIR_PROPERTY, SHARED_RESOURCES_DIR, BOOTSTRAP_SCRIPT, \ @@ -121,7 +121,7 @@ with patch.object(platform, "linux_distribution", return_value = MagicMock(retur SRVR_ONE_WAY_SSL_PORT_PROPERTY, SRVR_TWO_WAY_SSL_PORT_PROPERTY, GANGLIA_HTTPS from ambari_server.setupSecurity import adjust_directory_permissions, get_alias_string, get_ldap_event_spec_names, sync_ldap, LdapSyncOptions, \ configure_ldap_password, setup_ldap, REGEX_HOSTNAME_PORT, REGEX_TRUE_FALSE, REGEX_ANYTHING, setup_master_key, \ - setup_ambari_krb5_jaas, ensure_can_start_under_current_user, generate_env + setup_ambari_krb5_jaas, ensure_can_start_under_current_user, generate_env, IS_LDAP_CONFIGURED 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 @@ -7147,15 +7147,16 @@ class TestAmbariServer(TestCase): def _init_test_ldap_properties_map_invalid_input_1(): ldap_properties_map = \ { - LDAP_PRIMARY_URL_PROPERTY: "a:3", - "authentication.ldap.secondaryUrl": "b:2", - "authentication.ldap.useSSL": "false", - "authentication.ldap.usernameAttribute": "user", - "authentication.ldap.baseDn": "uid", - "authentication.ldap.bindAnonymously": "true", - "authentication.ldap.referral": "follow", - "client.security": "ldap", - "ambari.ldap.isConfigured": "true" + "ambari.ldap.connectivity.server.host": "a", + "ambari.ldap.connectivity.server.port" : "3", + "ambari.ldap.connectivity.secondary.server.host": "b", + "ambari.ldap.connectivity.secondary.server.port" : "2", + "ambari.ldap.connectivity.use_ssl": "false", + "ambari.ldap.attributes.user.name_attr": "user", + "ambari.ldap.attributes.user.search_base": "uid", + "ambari.ldap.connectivity.anonymous_bind": "true", + "ambari.ldap.advanced.referrals": "follow", + "ambari.ldap.authentication.enabled": "true" } return ldap_properties_map @@ -7164,21 +7165,24 @@ class TestAmbariServer(TestCase): def _init_test_ldap_properties_map_invalid_input_1(): ldap_properties_map = \ { - LDAP_PRIMARY_URL_PROPERTY: "a:3", - "authentication.ldap.secondaryUrl": "b:2", - "authentication.ldap.useSSL": "false", - "authentication.ldap.userObjectClass": "user", - "authentication.ldap.usernameAttribute": "uid", - "authentication.ldap.groupObjectClass": "group", - "authentication.ldap.groupNamingAttr": "cn", - "authentication.ldap.groupMembershipAttr": "member", - "authentication.ldap.dnAttribute": "dn", - "authentication.ldap.baseDn": "base", - "authentication.ldap.referral": "follow", - "authentication.ldap.bindAnonymously": "true", - "ldap.sync.username.collision.behavior": "skip", - "client.security": "ldap", - "ambari.ldap.isConfigured": "true" + "ambari.ldap.connectivity.server.host": "a", + "ambari.ldap.connectivity.server.port" : "3", + "ambari.ldap.connectivity.secondary.server.host": "b", + "ambari.ldap.connectivity.secondary.server.port" : "2", + "ambari.ldap.connectivity.use_ssl": "false", + "ambari.ldap.attributes.user.object_class": "user", + "ambari.ldap.attributes.user.name_attr": "uid", + "ambari.ldap.attributes.group.object_class": "group", + "ambari.ldap.attributes.group.name_attr": "cn", + "ambari.ldap.attributes.group.member_attr": "member", + "ambari.ldap.attributes.dn_attr": "dn", + "ambari.ldap.attributes.user.search_base": "base", + "ambari.ldap.advanced.referrals": "follow", + "ambari.ldap.connectivity.anonymous_bind": "true", + "ambari.ldap.advance.collision_behavior": "skip", + "ambari.ldap.advanced.force_lowercase_usernames": "false", + "ambari.ldap.advanced.pagination_enabled": "false", + "ambari.ldap.authentication.enabled": "true" } return ldap_properties_map @@ -7187,15 +7191,17 @@ class TestAmbariServer(TestCase): def _init_test_ldap_properties_map_invalid_input_2(): ldap_properties_map = \ { - LDAP_PRIMARY_URL_PROPERTY: "a:3", - "authentication.ldap.useSSL": "false", - "authentication.ldap.usernameAttribute": "user", - "authentication.ldap.baseDn": "uid", - "authentication.ldap.bindAnonymously": "true", - "ldap.sync.username.collision.behavior": "skip", - "authentication.ldap.referral": "follow", - "client.security": "ldap", - "ambari.ldap.isConfigured": "true" + "ambari.ldap.connectivity.server.host": "a", + "ambari.ldap.connectivity.server.port" : "3", + "ambari.ldap.connectivity.use_ssl": "false", + "ambari.ldap.attributes.user.name_attr": "user", + "ambari.ldap.attributes.user.search_base": "uid", + "ambari.ldap.connectivity.anonymous_bind": "true", + "ambari.ldap.advance.collision_behavior": "skip", + "ambari.ldap.advanced.force_lowercase_usernames": "false", + "ambari.ldap.advanced.pagination_enabled": "false", + "ambari.ldap.advanced.referrals": "follow", + "ambari.ldap.authentication.enabled": "true" } return ldap_properties_map @@ -7204,25 +7210,29 @@ class TestAmbariServer(TestCase): def _init_test_ldap_properties_map_invalid_input_2(): ldap_properties_map = \ { - LDAP_PRIMARY_URL_PROPERTY: "a:3", - "authentication.ldap.useSSL": "false", - "authentication.ldap.userObjectClass": "user", - "authentication.ldap.usernameAttribute": "uid", - "authentication.ldap.groupObjectClass": "group", - "authentication.ldap.groupNamingAttr": "cn", - "authentication.ldap.groupMembershipAttr": "member", - "authentication.ldap.dnAttribute": "dn", - "authentication.ldap.baseDn": "base", - "authentication.ldap.referral": "follow", - "authentication.ldap.bindAnonymously": "true", - "ldap.sync.username.collision.behavior": "skip", - "client.security": "ldap", - "ambari.ldap.isConfigured": "true" + "ambari.ldap.connectivity.server.host": "a", + "ambari.ldap.connectivity.server.port" : "3", + "ambari.ldap.connectivity.use_ssl": "false", + "ambari.ldap.attributes.user.object_class": "user", + "ambari.ldap.attributes.user.name_attr": "uid", + "ambari.ldap.attributes.group.object_class": "group", + "ambari.ldap.attributes.group.name_attr": "cn", + "ambari.ldap.attributes.group.member_attr": "member", + "ambari.ldap.attributes.dn_attr": "dn", + "ambari.ldap.attributes.user.search_base": "base", + "ambari.ldap.advanced.referrals": "follow", + "ambari.ldap.connectivity.anonymous_bind": "true", + "ambari.ldap.advance.collision_behavior": "skip", + "ambari.ldap.advanced.force_lowercase_usernames": "false", + "ambari.ldap.advanced.pagination_enabled": "false", + "ambari.ldap.authentication.enabled": "true" } return ldap_properties_map @patch.object(OSCheck, "os_distribution", new = MagicMock(return_value = os_distro_value)) + @patch("urllib2.urlopen") @patch("__builtin__.raw_input") + @patch("ambari_server.userInput.get_password") @patch("ambari_server.setupSecurity.get_is_secure") @patch("ambari_server.setupSecurity.get_YN_input") @patch("ambari_server.setupSecurity.update_properties_2") @@ -7230,73 +7240,144 @@ class TestAmbariServer(TestCase): @patch("ambari_server.setupSecurity.get_ambari_properties") @patch("ambari_server.setupSecurity.is_root") @patch("ambari_server.setupSecurity.logger") - def test_setup_ldap_invalid_input(self, logger_mock, is_root_method, get_ambari_properties_method, + @patch("ambari_server.setupSecurity.is_server_runing") + def test_setup_ldap_invalid_input(self, is_server_runing_method, logger_mock, is_root_method, get_ambari_properties_method, search_file_message, update_properties_method, get_YN_input_method, get_is_secure_method, - raw_input_mock): + get_password_mock, raw_input_mock, urlopen_mock): out = StringIO.StringIO() sys.stdout = out is_root_method.return_value = True + is_server_runing_method.return_value = (True, 0) search_file_message.return_value = "filepath" - configs = {SECURITY_MASTER_KEY_LOCATION: "filepath", - SECURITY_KEYS_DIR: tempfile.gettempdir(), - SECURITY_IS_ENCRYPTION_ENABLED: "true" - } + properties = Properties(); + properties.process_pair(SECURITY_MASTER_KEY_LOCATION, "filepath") + properties.process_pair(SECURITY_KEYS_DIR, tempfile.gettempdir()) + properties.process_pair(SECURITY_IS_ENCRYPTION_ENABLED, "true") + properties.process_pair(CLIENT_API_PORT_PROPERTY, '8080') - get_ambari_properties_method.return_value = configs - raw_input_mock.side_effect = ['a:3', 'b:b', 'hody', 'b:2', 'false', 'user', 'uid', 'group', 'cn', 'member', 'dn', 'base', 'follow', 'true', 'skip'] + 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'] + get_password_mock.side_effect = ['admin'] set_silent(False) get_YN_input_method.return_value = True + + response = MagicMock() + response.getcode.return_value = 200 + urlopen_mock.return_value = response options = self._create_empty_options_mock() setup_ldap(options) - - ldap_properties_map = TestAmbariServer._init_test_ldap_properties_map_invalid_input_1() - - sorted_x = sorted(ldap_properties_map.iteritems(), key=operator.itemgetter(0)) - sorted_y = sorted(update_properties_method.call_args[0][1].iteritems(), - key=operator.itemgetter(0)) - self.assertEquals(sorted_x, sorted_y) + + requestCall = urlopen_mock.call_args_list[0] + args, kwargs = requestCall + request = args[0] + requestData = json.loads(request.data) + self.assertTrue(isinstance(requestData, dict)) + ldapProperties = requestData['Configuration']['properties']; + properties_updated_in_ambari_db = sorted(ldapProperties.iteritems(), key=operator.itemgetter(0)) + properties_should_be_updated_in_ambari_db = sorted(TestAmbariServer._init_test_ldap_properties_map_invalid_input_1().iteritems(), key=operator.itemgetter(0)) + self.assertEqual(properties_should_be_updated_in_ambari_db, properties_updated_in_ambari_db) + + properties_updated_in_ambari_dot_properties = sorted(update_properties_method.call_args[0][1].iteritems(), key=operator.itemgetter(0)) + properties_should_be_updated_in_ambari_dot_properties = sorted({"client.security": "ldap"}.iteritems(), key=operator.itemgetter(0)) + self.assertEquals(properties_should_be_updated_in_ambari_dot_properties, properties_updated_in_ambari_dot_properties) + + self.assertTrue(urlopen_mock.called) + self.assertTrue(update_properties_method.called) self.assertTrue(get_YN_input_method.called) - self.assertEquals(15, raw_input_mock.call_count) - + self.assertEquals(21, raw_input_mock.call_count) + 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'] + raw_input_mock.side_effect = ['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'] + + urlopen_mock.reset_mock() + urlopen_mock.return_value = response setup_ldap(options) - ldap_properties_map = TestAmbariServer._init_test_ldap_properties_map_invalid_input_2() + requestCall = urlopen_mock.call_args_list[0] + args, kwargs = requestCall + request = args[0] + requestData = json.loads(request.data) + self.assertTrue(isinstance(requestData, dict)) + ldapProperties = requestData['Configuration']['properties']; + properties_updated_in_ambari_db = sorted(ldapProperties.iteritems(), key=operator.itemgetter(0)) + properties_should_be_updated_in_ambari_db = sorted(TestAmbariServer._init_test_ldap_properties_map_invalid_input_2().iteritems(), key=operator.itemgetter(0)) + self.assertEqual(properties_should_be_updated_in_ambari_db, properties_updated_in_ambari_db) + + properties_updated_in_ambari_dot_properties = sorted(update_properties_method.call_args[0][1].iteritems(), key=operator.itemgetter(0)) + properties_should_be_updated_in_ambari_dot_properties = sorted({"client.security": "ldap"}.iteritems(), key=operator.itemgetter(0)) + self.assertEquals(properties_should_be_updated_in_ambari_dot_properties, properties_updated_in_ambari_dot_properties) - sorted_x = sorted(ldap_properties_map.iteritems(), key=operator.itemgetter(0)) - sorted_y = sorted(update_properties_method.call_args[0][1].iteritems(), - key=operator.itemgetter(0)) - self.assertEquals(sorted_x, sorted_y) - self.assertEquals(14, raw_input_mock.call_count) + self.assertTrue(urlopen_mock.called) + self.assertTrue(update_properties_method.called) + self.assertTrue(get_YN_input_method.called) + self.assertEquals(20, raw_input_mock.call_count) + self.assertEqual(1, get_password_mock.call_count) sys.stdout = sys.__stdout__ pass + @patch("ambari_server.setupSecurity.is_root") + def test_setup_ldap_should_fail_if_executed_by_not_root_user(self, is_root_mock): + out = StringIO.StringIO() + sys.stdout = out + is_root_mock.return_value = False + try: + setup_ldap(self._create_empty_options_mock()) + self.fail("Should throw exception") + except FatalException as fe: + self.assertTrue("root-level" in fe.reason) + pass + + sys.stdout = sys.__stdout__ + pass + + @patch("ambari_server.setupSecurity.is_server_runing") + @patch("ambari_server.setupSecurity.is_root") + def test_setup_ldap_should_fail_if_ambari_server_is_not_running(self, is_root_mock, is_server_runing_mock): + out = StringIO.StringIO() + sys.stdout = out + is_root_mock.return_value = True + is_server_runing_mock.return_value = (False, 0) + try: + setup_ldap(self._create_empty_options_mock()) + self.fail("Should throw exception") + except FatalException as fe: + self.assertTrue("Ambari Server is not running." == fe.reason) + pass + + sys.stdout = sys.__stdout__ + pass @staticmethod @OsFamilyFuncImpl(OSConst.WINSRV_FAMILY) def _init_test_ldap_properties_map(): ldap_properties_map = \ { - "authentication.ldap.primaryUrl": "test", - "authentication.ldap.secondaryUrl": "test", - "authentication.ldap.useSSL": "false", - "authentication.ldap.usernameAttribute": "test", - "authentication.ldap.baseDn": "test", - "authentication.ldap.bindAnonymously": "false", - "ldap.sync.username.collision.behavior": "skip", - "authentication.ldap.managerDn": "test", - "authentication.ldap.referral": "test", + "ambari.ldap.connectivity.server.host": "test", + "ambari.ldap.connectivity.server.port" : "1", + "ambari.ldap.connectivity.secondary.server.host": "test", + "ambari.ldap.connectivity.secondary.server.port" : "2", + "ambari.ldap.connectivity.use_ssl": "false", + "ambari.ldap.attributes.user.name_attr": "test", + "ambari.ldap.attributes.user.search_base": "test", + "ambari.ldap.connectivity.anonymous_bind": "false", + "ambari.ldap.advance.collision_behavior": "skip", + "ambari.ldap.advanced.force_lowercase_usernames": "false", + "ambari.ldap.advanced.pagination_enabled": "false", + "ambari.ldap.connectivity.bind_dn": "test", + "ambari.ldap.advanced.referrals": "test", "client.security": "ldap", LDAP_MGR_PASSWORD_PROPERTY: "ldap-password.dat", - "ambari.ldap.isConfigured": "true" + "ambari.ldap.authentication.enabled": "true" } return ldap_properties_map @@ -7305,27 +7386,31 @@ class TestAmbariServer(TestCase): def _init_test_ldap_properties_map(): ldap_properties_map = \ { - "authentication.ldap.primaryUrl": "test", - "authentication.ldap.secondaryUrl": "test", - "authentication.ldap.useSSL": "false", - "authentication.ldap.userObjectClass": "test", - "authentication.ldap.usernameAttribute": "test", - "authentication.ldap.baseDn": "test", - "authentication.ldap.bindAnonymously": "false", - "ldap.sync.username.collision.behavior": "skip", - "authentication.ldap.managerDn": "test", - "authentication.ldap.groupObjectClass": "test", - "authentication.ldap.groupMembershipAttr": "test", - "authentication.ldap.groupNamingAttr": "test", - "authentication.ldap.dnAttribute": "test", - "authentication.ldap.referral": "test", - "client.security": "ldap", + "ambari.ldap.connectivity.server.host": "test", + "ambari.ldap.connectivity.server.port" : "1", + "ambari.ldap.connectivity.secondary.server.host": "test", + "ambari.ldap.connectivity.secondary.server.port" : "1", + "ambari.ldap.connectivity.use_ssl": "false", + "ambari.ldap.attributes.user.object_class": "test", + "ambari.ldap.attributes.user.name_attr": "test", + "ambari.ldap.attributes.user.search_base": "test", + "ambari.ldap.connectivity.anonymous_bind": "false", + "ambari.ldap.advance.collision_behavior": "skip", + "ambari.ldap.advanced.force_lowercase_usernames": "false", + "ambari.ldap.advanced.pagination_enabled": "false", + "ambari.ldap.connectivity.bind_dn": "test", + "ambari.ldap.attributes.group.object_class": "test", + "ambari.ldap.attributes.group.member_attr": "test", + "ambari.ldap.attributes.group.name_attr": "test", + "ambari.ldap.attributes.dn_attr": "test", + "ambari.ldap.advanced.referrals": "test", LDAP_MGR_PASSWORD_PROPERTY: "ldap-password.dat", - "ambari.ldap.isConfigured": "true" + "ambari.ldap.authentication.enabled": "true" } return ldap_properties_map @patch.object(OSCheck, "os_distribution", new = MagicMock(return_value = os_distro_value)) + @patch("urllib2.urlopen") @patch("ambari_server.setupSecurity.get_is_secure") @patch("ambari_server.setupSecurity.encrypt_password") @patch("ambari_server.setupSecurity.save_passwd_for_alias") @@ -7339,37 +7424,29 @@ class TestAmbariServer(TestCase): @patch("ambari_server.setupSecurity.read_password") @patch("os.path.exists") @patch("ambari_server.setupSecurity.logger") - def test_setup_ldap(self, logger_mock, exists_method, read_password_method, is_root_method, get_ambari_properties_method, + @patch("ambari_server.setupSecurity.is_server_runing") + def test_setup_ldap(self, is_server_runing_method, logger_mock, exists_method, read_password_method, is_root_method, get_ambari_properties_method, search_file_message, get_validated_string_input_method, configure_ldap_password_method, update_properties_method, get_YN_input_method, save_passwd_for_alias_method, - encrypt_password_method, get_is_secure_method): + encrypt_password_method, get_is_secure_method, urlopen_mock): out = StringIO.StringIO() sys.stdout = out options = self._create_empty_options_mock() - # Testing call under non-root - is_root_method.return_value = False - try: - setup_ldap(options) - self.fail("Should throw exception") - except FatalException as fe: - # Expected - self.assertTrue("root-level" in fe.reason) - pass - - # Testing call under root is_root_method.return_value = True + is_server_runing_method.return_value = (True, 0) search_file_message.return_value = "filepath" - configs = {SECURITY_MASTER_KEY_LOCATION: "filepath", - SECURITY_KEYS_DIR: tempfile.gettempdir(), - SECURITY_IS_ENCRYPTION_ENABLED: "true" - } + properties = Properties(); + properties.process_pair(SECURITY_MASTER_KEY_LOCATION, "filepath") + properties.process_pair(SECURITY_KEYS_DIR, tempfile.gettempdir()) + properties.process_pair(SECURITY_IS_ENCRYPTION_ENABLED, "true") + properties.process_pair(CLIENT_API_PORT_PROPERTY, '8080') - get_ambari_properties_method.return_value = configs + get_ambari_properties_method.return_value = properties configure_ldap_password_method.return_value = "password" save_passwd_for_alias_method.return_value = 0 encrypt_password_method.return_value = get_alias_string(LDAP_MGR_PASSWORD_ALIAS) @@ -7380,13 +7457,17 @@ class TestAmbariServer(TestCase): else: return True - get_YN_input_method.side_effect = [True, ] + get_YN_input_method.side_effect = yn_input_side_effect def valid_input_side_effect(*args, **kwargs): - if 'Bind anonymously' in args[0]: + if 'Bind anonymously' in args[0] or 'lower-case' in args[0] or 'paginated' in args[0]: return 'false' if 'username collisions' in args[0]: return 'skip' + if 'URL Port' in args[0]: + return '1' + if 'Ambari Admin' in args[0]: + return 'admin' if args[1] == "true" or args[1] == "false": return args[1] else: @@ -7394,14 +7475,27 @@ class TestAmbariServer(TestCase): get_validated_string_input_method.side_effect = valid_input_side_effect - setup_ldap(options) + response = MagicMock() + response.getcode.return_value = 200 + urlopen_mock.return_value = response - ldap_properties_map = TestAmbariServer._init_test_ldap_properties_map() + setup_ldap(options) - sorted_x = sorted(ldap_properties_map.iteritems(), key=operator.itemgetter(0)) - sorted_y = sorted(update_properties_method.call_args[0][1].iteritems(), - key=operator.itemgetter(0)) - self.assertEquals(sorted_x, sorted_y) + requestCall = urlopen_mock.call_args_list[0] + args, kwargs = requestCall + request = args[0] + requestData = json.loads(request.data) + self.assertTrue(isinstance(requestData, dict)) + ldapProperties = requestData['Configuration']['properties']; + properties_updated_in_ambari_db = sorted(ldapProperties.iteritems(), key=operator.itemgetter(0)) + properties_should_be_updated_in_ambari_db = sorted(TestAmbariServer._init_test_ldap_properties_map().iteritems(), key=operator.itemgetter(0)) + self.assertEqual(properties_should_be_updated_in_ambari_db, properties_updated_in_ambari_db) + + properties_updated_in_ambari_dot_properties = sorted(update_properties_method.call_args[0][1].iteritems(), key=operator.itemgetter(0)) + properties_should_be_updated_in_ambari_dot_properties = sorted({"client.security": "ldap"}.iteritems(), key=operator.itemgetter(0)) + self.assertEquals(properties_should_be_updated_in_ambari_dot_properties, properties_updated_in_ambari_dot_properties) + + self.assertTrue(urlopen_mock.called) self.assertTrue(update_properties_method.called) self.assertTrue(configure_ldap_password_method.called) self.assertTrue(get_validated_string_input_method.called) @@ -7427,6 +7521,10 @@ class TestAmbariServer(TestCase): return "bogus" else: return "valid" + if 'URL Port' in args[0]: + return '1' + if 'Ambari Admin' in args[0]: + return 'admin' if args[1] == "true" or args[1] == "false": return args[1] else: @@ -7442,7 +7540,8 @@ class TestAmbariServer(TestCase): get_YN_input_method.side_effect = [True, True] update_properties_method.reset_mock() - options.ldap_url = None + options.ldap_url_host = None + options.ldap_url_port = None options.ldap_member_attr = None setup_ldap(options) @@ -7450,15 +7549,17 @@ class TestAmbariServer(TestCase): ldap_properties_map = \ { - "authentication.ldap.primaryUrl": "test", - "authentication.ldap.secondaryUrl": "test", - "authentication.ldap.useSSL": "true", - "authentication.ldap.usernameAttribute": "test", - "authentication.ldap.baseDn": "test", - "authentication.ldap.dnAttribute": "test", - "authentication.ldap.bindAnonymously": "false", - "ldap.sync.username.collision.behavior": "skip", - "authentication.ldap.managerDn": "test", + "ambari.ldap.connectivity.server.host": "a", + "ambari.ldap.connectivity.server.port" : "3", + "ambari.ldap.connectivity.secondary.server.host": "b", + "ambari.ldap.connectivity.secondary.server.port" : "2", + "ambari.ldap.connectivity.use_ssl": "true", + "ambari.ldap.attributes.user.name_attr": "test", + "ambari.ldap.attributes.user.search_base": "test", + "ambari.ldap.attributes.dn_attr": "test", + "ambari.ldap.connectivity.anonymous_bind": "false", + "ambari.ldap.advance.collision_behavior": "skip", + "ambari.ldap.connectivity.bind_dn": "test", "client.security": "ldap", "ssl.trustStore.type": "test", "ssl.trustStore.path": "valid", @@ -8584,8 +8685,10 @@ class TestAmbariServer(TestCase): def _create_empty_options_mock(self): options = MagicMock() - options.ldap_url = None - options.ldap_secondary_url = None + options.ldap_url_host = None + options.ldap_url_port = None + options.ldap_secondary_url_host = None + options.ldap_secondary_url_port = None options.ldap_ssl = None options.ldap_user_class = None options.ldap_user_attr = None @@ -8601,6 +8704,8 @@ class TestAmbariServer(TestCase): options.ldap_bind_anonym = None options.ldap_sync_admin_name = None options.ldap_sync_username_collisions_behavior = None + options.ldap_force_lowercase_usernames = None + options.ldap_pagination_enabled = None options.ldap_sync_admin_password = None options.custom_trust_store = None options.trust_store_type = None -- To stop receiving notification emails like this one, please contact nc...@apache.org.