From 0127b0fa0a050c3e69dc02780a5342cb4bfa0ceb Mon Sep 17 00:00:00 2001 From: Lisnichenko Dmitro Date: Sat, 5 Jan 2019 17:06:49 +0200 Subject: [PATCH 1/3] AMBARI-24745. Enable encryption of sensitive data in Ambari DB using Ambari CLI (dlysnichenko) --- .../src/main/python/ambari-server.py | 4 +-- .../ambari_server/serverConfiguration.py | 6 +++++ .../python/ambari_server/setupSecurity.py | 25 +++++++++++++++++-- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/ambari-server/src/main/python/ambari-server.py b/ambari-server/src/main/python/ambari-server.py index 4539879fb81..85d40efc4a7 100755 --- a/ambari-server/src/main/python/ambari-server.py +++ b/ambari-server/src/main/python/ambari-server.py @@ -253,7 +253,7 @@ def refresh_stack_hash_action(): def create_setup_security_actions(args): action_list = [ ['setup-https', 'Enable HTTPS for Ambari server.', UserActionRestart(setup_https, args)], - ['encrypt-passwords', 'Encrypt passwords stored in ambari.properties file.', UserAction(setup_master_key, args)], + ['encrypt-passwords', 'Encrypt passwords managed by Ambari.', UserAction(setup_master_key, args)], ['setup-kerberos-jaas', 'Setup Ambari kerberos JAAS configuration.', UserAction(setup_ambari_krb5_jaas, args)], ['setup-truststore', 'Setup truststore.', UserActionRestart(setup_truststore, args)], ['import-certificate', 'Import certificate to truststore.', UserActionRestart(setup_truststore, True, args)], @@ -264,7 +264,7 @@ def create_setup_security_actions(args): def create_setup_security_actions(args): action_list = [ ['setup-https', 'Enable HTTPS for Ambari server.', UserActionRestart(setup_https, args)], - ['encrypt-passwords', 'Encrypt passwords stored in ambari.properties file.', UserAction(setup_master_key, args)], + ['encrypt-passwords', 'Encrypt passwords managed by Ambari.', UserAction(setup_master_key, args)], ['setup-kerberos-jaas', 'Setup Ambari kerberos JAAS configuration.', UserAction(setup_ambari_krb5_jaas, args)], ['setup-truststore', 'Setup truststore.', UserActionRestart(setup_truststore, args)], ['import-certificate', 'Import certificate to truststore.', UserActionRestart(setup_truststore, args, True)], diff --git a/ambari-server/src/main/python/ambari_server/serverConfiguration.py b/ambari-server/src/main/python/ambari_server/serverConfiguration.py index fb0e0a2364f..6fcf7c5ad88 100644 --- a/ambari-server/src/main/python/ambari_server/serverConfiguration.py +++ b/ambari-server/src/main/python/ambari_server/serverConfiguration.py @@ -608,6 +608,7 @@ def __init__(self): SECURITY_KEY_ENV_VAR_NAME = "AMBARI_SECURITY_MASTER_KEY" SECURITY_MASTER_KEY_FILENAME = "master" SECURITY_IS_ENCRYPTION_ENABLED = "security.passwords.encryption.enabled" +SECURITY_SENSITIVE_DATA_ENCRYPTON_ENABLED = "security.server.encrypt_sensitive_data" SECURITY_KERBEROS_JASS_FILENAME = "krb5JAASLogin.conf" SECURITY_PROVIDER_GET_CMD = "{0} -cp {1} " + \ @@ -625,6 +626,11 @@ def __init__(self): ".MasterKeyServiceImpl {2} {3} {4} " + \ "> " + configDefaults.SERVER_OUT_FILE + " 2>&1" +SECURITY_SENSITIVE_DATA_ENCRYPTON_CMD = "{0} -cp {1} " + \ + "org.apache.ambari.server.security.encryption.SensitiveDataEncryption" + \ + " {2} " + \ + "> " + configDefaults.SERVER_OUT_FILE + " 2>&1" + def read_ambari_user(): diff --git a/ambari-server/src/main/python/ambari_server/setupSecurity.py b/ambari-server/src/main/python/ambari_server/setupSecurity.py index 7952a077fbe..ae1b361f690 100644 --- a/ambari-server/src/main/python/ambari_server/setupSecurity.py +++ b/ambari-server/src/main/python/ambari_server/setupSecurity.py @@ -47,8 +47,8 @@ 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_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, \ + SECURITY_IS_ENCRYPTION_ENABLED, SECURITY_SENSITIVE_DATA_ENCRYPTON_ENABLED, SECURITY_KEY_ENV_VAR_NAME, SECURITY_KERBEROS_JASS_FILENAME, \ + SECURITY_PROVIDER_KEY_CMD, SECURITY_SENSITIVE_DATA_ENCRYPTON_CMD, SECURITY_MASTER_KEY_FILENAME, SSL_TRUSTSTORE_PASSWORD_ALIAS, \ SSL_TRUSTSTORE_PASSWORD_PROPERTY, SSL_TRUSTSTORE_PATH_PROPERTY, SSL_TRUSTSTORE_TYPE_PROPERTY, \ JDK_NAME_PROPERTY, JCE_NAME_PROPERTY, JAVA_HOME_PROPERTY, \ get_resources_location, SECURITY_MASTER_KEY_LOCATION, SETUP_OR_UPGRADE_MSG, \ @@ -487,6 +487,18 @@ def sync_ldap(options): sys.stdout.write('\n') sys.stdout.flush() +def sensitive_data_encryption(options, direction): + jdk_path = find_jdk() + if jdk_path is None: + print_error_msg("No JDK found, please run the \"setup\" " + "command to install a JDK automatically or install any " + "JDK manually to " + configDefaults.JDK_INSTALL_DIR) + return 1 + serverClassPath = ServerClassPath(get_ambari_properties(), options) + command = SECURITY_SENSITIVE_DATA_ENCRYPTON_CMD.format(get_java_exe_path(), serverClassPath.get_full_ambari_classpath_escaped_for_shell(), direction) + (retcode, stdout, stderr) = run_os_command(command) + pass + def setup_master_key(options): if not is_root(): warn = 'ambari-server setup-https is run as ' \ @@ -536,6 +548,7 @@ def setup_master_key(options): masterKey = get_original_master_key(properties, options) # Unable get the right master key or skipped question if not masterKey: + # todo sensitive_data_encryption support for not persisted masterkey print "To disable encryption, do the following:" print "- Edit " + find_properties_file() + \ " and set " + SECURITY_IS_ENCRYPTION_ENABLED + " = " + "false." @@ -551,6 +564,11 @@ def setup_master_key(options): pass pass + # decrypt sensitive data if resetKey + if resetKey: + sensitive_data_encryption(options, "decryption") + pass + # Read back any encrypted passwords if db_sql_auth and db_password and is_alias_string(db_password): db_password = read_passwd_for_alias(JDBC_RCA_PASSWORD_ALIAS, masterKey) @@ -607,6 +625,9 @@ def setup_master_key(options): propertyMap[SSL_TRUSTSTORE_PASSWORD_PROPERTY] = get_alias_string(SSL_TRUSTSTORE_PASSWORD_ALIAS) pass + propertyMap[SECURITY_SENSITIVE_DATA_ENCRYPTON_ENABLED] = 'true' + sensitive_data_encryption(options, "encryption") + update_properties_2(properties, propertyMap) # Since files for store and master are created we need to ensure correct From 1cbeeada5958b8d62c9a7f68a31ea75e725e23f1 Mon Sep 17 00:00:00 2001 From: Lisnichenko Dmitro Date: Fri, 11 Jan 2019 21:19:22 +0200 Subject: [PATCH 2/3] AMBARI-24745. Enable encryption of sensitive data in Ambari DB using Ambari CLI (dlysnichenko) --- .../src/main/python/ambari-server.py | 6 +- .../python/ambari_server/setupSecurity.py | 182 ++++++++++-------- .../src/test/python/TestAmbariServer.py | 10 +- 3 files changed, 114 insertions(+), 84 deletions(-) diff --git a/ambari-server/src/main/python/ambari-server.py b/ambari-server/src/main/python/ambari-server.py index 85d40efc4a7..78d5405d7db 100755 --- a/ambari-server/src/main/python/ambari-server.py +++ b/ambari-server/src/main/python/ambari-server.py @@ -54,7 +54,7 @@ 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, \ +from ambari_server.setupSecurity import setup_ldap, sync_ldap, setup_sensitive_data_encryption, setup_ambari_krb5_jaas, setup_pam, \ migrate_ldap_pam, LDAP_TYPES from ambari_server.setupSso import setup_sso from ambari_server.setupTrustedProxy import setup_trusted_proxy @@ -253,7 +253,7 @@ def refresh_stack_hash_action(): def create_setup_security_actions(args): action_list = [ ['setup-https', 'Enable HTTPS for Ambari server.', UserActionRestart(setup_https, args)], - ['encrypt-passwords', 'Encrypt passwords managed by Ambari.', UserAction(setup_master_key, args)], + ['encrypt-passwords', 'Encrypt passwords managed by Ambari.', UserAction(setup_sensitive_data_encryption, args)], ['setup-kerberos-jaas', 'Setup Ambari kerberos JAAS configuration.', UserAction(setup_ambari_krb5_jaas, args)], ['setup-truststore', 'Setup truststore.', UserActionRestart(setup_truststore, args)], ['import-certificate', 'Import certificate to truststore.', UserActionRestart(setup_truststore, True, args)], @@ -264,7 +264,7 @@ def create_setup_security_actions(args): def create_setup_security_actions(args): action_list = [ ['setup-https', 'Enable HTTPS for Ambari server.', UserActionRestart(setup_https, args)], - ['encrypt-passwords', 'Encrypt passwords managed by Ambari.', UserAction(setup_master_key, args)], + ['encrypt-passwords', 'Encrypt passwords managed by Ambari.', UserAction(setup_sensitive_data_encryption, args)], ['setup-kerberos-jaas', 'Setup Ambari kerberos JAAS configuration.', UserAction(setup_ambari_krb5_jaas, args)], ['setup-truststore', 'Setup truststore.', UserActionRestart(setup_truststore, args)], ['import-certificate', 'Import certificate to truststore.', UserActionRestart(setup_truststore, args, True)], diff --git a/ambari-server/src/main/python/ambari_server/setupSecurity.py b/ambari-server/src/main/python/ambari_server/setupSecurity.py index ae1b361f690..2707d3abec9 100644 --- a/ambari-server/src/main/python/ambari_server/setupSecurity.py +++ b/ambari-server/src/main/python/ambari_server/setupSecurity.py @@ -487,7 +487,10 @@ def sync_ldap(options): sys.stdout.write('\n') sys.stdout.flush() -def sensitive_data_encryption(options, direction): +def sensitive_data_encryption(options, direction, masterKey=None): + environ = os.environ.copy() + if masterKey: + environ[SECURITY_KEY_ENV_VAR_NAME] = masterKey jdk_path = find_jdk() if jdk_path is None: print_error_msg("No JDK found, please run the \"setup\" " @@ -496,12 +499,12 @@ def sensitive_data_encryption(options, direction): return 1 serverClassPath = ServerClassPath(get_ambari_properties(), options) command = SECURITY_SENSITIVE_DATA_ENCRYPTON_CMD.format(get_java_exe_path(), serverClassPath.get_full_ambari_classpath_escaped_for_shell(), direction) - (retcode, stdout, stderr) = run_os_command(command) + (retcode, stdout, stderr) = run_os_command(command, environ) pass -def setup_master_key(options): +def setup_sensitive_data_encryption(options): if not is_root(): - warn = 'ambari-server setup-https is run as ' \ + warn = 'ambari-server encrypt-passwords is run as ' \ 'non-root user, some sudo privileges might be required' print warn @@ -528,82 +531,66 @@ def setup_master_key(options): ts_password = properties.get_property(SSL_TRUSTSTORE_PASSWORD_PROPERTY) resetKey = False + decrypt = False masterKey = None if isSecure: print "Password encryption is enabled." - resetKey = True if options.security_option is not None else get_YN_input("Do you want to reset Master Key? [y/n] (n): ", False) - - # For encrypting of only unencrypted passwords without resetting the key ask - # for master key if not persisted. - if isSecure and not isPersisted and not resetKey: - print "Master Key not persisted." - masterKey = get_original_master_key(properties, options) - pass + decrypt = get_YN_input("Do you want to decrypt passwords managed by Ambari? [y/n] (n): ", False) + resetKey = get_YN_input("Do you want to reset Master Key? [y/n] (n): ", False) # Make sure both passwords are clear-text if master key is lost - if resetKey: - if not isPersisted: + if resetKey or decrypt: + if isPersisted: + sensitive_data_encryption(options, "decryption") + else: print "Master Key not persisted." masterKey = get_original_master_key(properties, options) # Unable get the right master key or skipped question if not masterKey: - # todo sensitive_data_encryption support for not persisted masterkey - print "To disable encryption, do the following:" - print "- Edit " + find_properties_file() + \ - " and set " + SECURITY_IS_ENCRYPTION_ENABLED + " = " + "false." - err = "{0} is already encrypted. Please call {1} to store unencrypted" \ - " password and call 'encrypt-passwords' again." - if db_sql_auth and db_password and is_alias_string(db_password): - print err.format('- Database password', "'" + SETUP_ACTION + "'") - if ts_password and is_alias_string(ts_password): - print err.format('TrustStore password', "'" + LDAP_SETUP_ACTION + "'") - + # todo fix unreachable code + printManualDecryptionWarning(db_password, db_sql_auth, ts_password) return 1 - pass - pass - pass - - # decrypt sensitive data if resetKey - if resetKey: - sensitive_data_encryption(options, "decryption") - pass + sensitive_data_encryption(options, "decryption", masterKey) # Read back any encrypted passwords - if db_sql_auth and db_password and is_alias_string(db_password): - db_password = read_passwd_for_alias(JDBC_RCA_PASSWORD_ALIAS, masterKey) - if ts_password and is_alias_string(ts_password): - ts_password = read_passwd_for_alias(SSL_TRUSTSTORE_PASSWORD_ALIAS, masterKey) - # Read master key, if non-secure or reset is true - if resetKey or not isSecure: - masterKey = read_master_key(resetKey, options) - persist = get_YN_input("Do you want to persist master key. If you choose " \ - "not to persist, you need to provide the Master " \ - "Key while starting the ambari server as an env " \ - "variable named " + SECURITY_KEY_ENV_VAR_NAME + \ - " or the start will prompt for the master key." - " Persist [y/n] (y)? ", True, options.master_key_persist) - if persist: - save_master_key(options, masterKey, get_master_key_location(properties) + os.sep + - SECURITY_MASTER_KEY_FILENAME, persist) - elif not persist and masterKeyFile: - try: - os.remove(masterKeyFile) - print_info_msg("Deleting master key file at location: " + str( - masterKeyFile)) - except Exception, e: - print 'ERROR: Could not remove master key file. %s' % e - # Blow up the credential store made with previous key, if any - store_file = get_credential_store_location(properties) - if os.path.exists(store_file): - try: - os.remove(store_file) - except: - print_warning_msg("Failed to remove credential store file.") - pass - pass - pass + db_password, ts_password = deryptPasswordsConfigs(db_password, db_sql_auth, masterKey, ts_password) + save_decrypted_ambari_properties(db_password, properties, ts_password) + + + if not decrypt: + if resetKey or not isSecure: + # Read master key and encrypt sensitive data, if non-secure or reset is true + masterKey, persist = setup_master_key(masterKeyFile, options, properties, resetKey) + else: + if not isPersisted: + # For encrypting of only unencrypted passwords without resetting the key ask + # for master key if not persisted. + print "Master Key not persisted." + masterKey = get_original_master_key(properties, options) + encrypt_sensitive_data(db_password, masterKey, options, persist, properties, ts_password) + + # Since files for store and master are created we need to ensure correct + # permissions + ambari_user = read_ambari_user() + if ambari_user: + adjust_directory_permissions(ambari_user) + return 0 + +def save_decrypted_ambari_properties(db_password, properties, ts_password): + propertyMap = {SECURITY_IS_ENCRYPTION_ENABLED: 'false'} + propertyMap[SECURITY_SENSITIVE_DATA_ENCRYPTON_ENABLED] = 'false' + if db_password: + propertyMap[JDBC_PASSWORD_PROPERTY] = db_password + if properties.get_property(JDBC_RCA_PASSWORD_FILE_PROPERTY): + propertyMap[JDBC_RCA_PASSWORD_FILE_PROPERTY] = db_password + if ts_password: + propertyMap[SSL_TRUSTSTORE_PASSWORD_PROPERTY] = ts_password + update_properties_2(properties, propertyMap) + + +def encrypt_sensitive_data(db_password, masterKey, options, persist, properties, ts_password): propertyMap = {SECURITY_IS_ENCRYPTION_ENABLED: 'true'} # Encrypt only un-encrypted passwords if db_password and not is_alias_string(db_password): @@ -615,7 +602,6 @@ def setup_master_key(options): remove_password_file(JDBC_PASSWORD_FILENAME) if properties.get_property(JDBC_RCA_PASSWORD_FILE_PROPERTY): propertyMap[JDBC_RCA_PASSWORD_FILE_PROPERTY] = get_alias_string(JDBC_RCA_PASSWORD_ALIAS) - pass if ts_password and not is_alias_string(ts_password): retCode = save_passwd_for_alias(SSL_TRUSTSTORE_PASSWORD_ALIAS, ts_password, masterKey) @@ -623,20 +609,64 @@ def setup_master_key(options): print 'Failed to save secure TrustStore password.' else: propertyMap[SSL_TRUSTSTORE_PASSWORD_PROPERTY] = get_alias_string(SSL_TRUSTSTORE_PASSWORD_ALIAS) - pass propertyMap[SECURITY_SENSITIVE_DATA_ENCRYPTON_ENABLED] = 'true' - sensitive_data_encryption(options, "encryption") - + if persist: + sensitive_data_encryption(options, "encryption") + else: + sensitive_data_encryption(options, "encryption", masterKey) update_properties_2(properties, propertyMap) - # Since files for store and master are created we need to ensure correct - # permissions - ambari_user = read_ambari_user() - if ambari_user: - adjust_directory_permissions(ambari_user) - return 0 +def setup_master_key(masterKeyFile, options, properties, resetKey): + masterKey = read_master_key(resetKey, options) + persist = get_YN_input("Do you want to persist master key. If you choose " \ + "not to persist, you need to provide the Master " \ + "Key while starting the ambari server as an env " \ + "variable named " + SECURITY_KEY_ENV_VAR_NAME + \ + " or the start will prompt for the master key." + " Persist [y/n] (y)? ", True, options.master_key_persist) + if persist: + save_master_key(options, masterKey, get_master_key_location(properties) + os.sep + + SECURITY_MASTER_KEY_FILENAME, persist) + elif not persist and masterKeyFile: + try: + os.remove(masterKeyFile) + print_info_msg("Deleting master key file at location: " + str( + masterKeyFile)) + except Exception, e: + print 'ERROR: Could not remove master key file. %s' % e + # Blow up the credential store made with previous key, if any + store_file = get_credential_store_location(properties) + if os.path.exists(store_file): + try: + os.remove(store_file) + except: + print_warning_msg("Failed to remove credential store file.") + return masterKey, persist + + +def deryptPasswordsConfigs(db_password, db_sql_auth, masterKey, ts_password): + if db_sql_auth and db_password and is_alias_string(db_password): + db_password = read_passwd_for_alias(JDBC_RCA_PASSWORD_ALIAS, masterKey) + if ts_password and is_alias_string(ts_password): + ts_password = read_passwd_for_alias(SSL_TRUSTSTORE_PASSWORD_ALIAS, masterKey) + return db_password, ts_password + + +def printManualDecryptionWarning(db_password, db_sql_auth, ts_password): + print "To disable encryption, do the following:" + print "- Edit " + find_properties_file() + \ + " and set " + SECURITY_IS_ENCRYPTION_ENABLED + " = " + "false." + \ + " and set " + SECURITY_SENSITIVE_DATA_ENCRYPTON_ENABLED + " = " + "false." + \ + " and set all passwords and sensitive data in service configs to right value." + err = "{0} is already encrypted. Please call {1} to store unencrypted" \ + " password and call 'encrypt-passwords' again." + if db_sql_auth and db_password and is_alias_string(db_password): + print err.format('- Database password', "'" + SETUP_ACTION + "'") + if ts_password and is_alias_string(ts_password): + print err.format('TrustStore password', "'" + LDAP_SETUP_ACTION + "'") + def setup_ambari_krb5_jaas(options): jaas_conf_file = search_file(SECURITY_KERBEROS_JASS_FILENAME, get_conf_dir()) diff --git a/ambari-server/src/test/python/TestAmbariServer.py b/ambari-server/src/test/python/TestAmbariServer.py index ebf0a9d6bac..ff6703e2696 100644 --- a/ambari-server/src/test/python/TestAmbariServer.py +++ b/ambari-server/src/test/python/TestAmbariServer.py @@ -108,7 +108,7 @@ def search_file_proxy(filename, searchpatch, pathsep=os.pathsep): SSL_DATE_FORMAT, import_cert_and_key, is_valid_cert_host, setup_truststore, \ 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, \ + configure_ldap_password, setup_ldap, REGEX_HOSTNAME_PORT, REGEX_TRUE_FALSE, REGEX_ANYTHING, setup_sensitive_data_encryption, \ 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 @@ -6764,7 +6764,7 @@ def test_setup_master_key_not_persist(self, is_root_method, exists_mock.return_value = False options = self._create_empty_options_mock() - setup_master_key(options) + setup_sensitive_data_encryption(options) self.assertTrue(get_YN_input_method.called) self.assertTrue(read_master_key_method.called) @@ -6828,7 +6828,7 @@ def test_setup_master_key_persist(self, is_root_method, save_passwd_for_alias_method.return_value = 0 options = self._create_empty_options_mock() - setup_master_key(options) + setup_sensitive_data_encryption(options) self.assertTrue(get_YN_input_method.called) self.assertTrue(read_master_key_method.called) @@ -6891,7 +6891,7 @@ def test_reset_master_key_persisted(self, is_root_method, options = self._create_empty_options_mock() - setup_master_key(options) + setup_sensitive_data_encryption(options) self.assertTrue(save_master_key_method.called) self.assertTrue(get_YN_input_method.called) @@ -6998,7 +6998,7 @@ def test_reset_master_key_not_persisted(self, is_root_method, get_is_persisted_method.return_value = (True, "filePath") options = self._create_empty_options_mock() - setup_master_key(options) + setup_sensitive_data_encryption(options) self.assertFalse(save_master_key_method.called) self.assertTrue(get_YN_input_method.called) From 1cd747b78d0e808b003d18d64aee45b807c5953b Mon Sep 17 00:00:00 2001 From: Lisnichenko Dmitro Date: Thu, 17 Jan 2019 20:16:31 +0200 Subject: [PATCH 3/3] AMBARI-24745. Enable encryption of sensitive data in Ambari DB using Ambari CLI (dlysnichenko) --- .../ambari_server/serverConfiguration.py | 2 +- .../python/ambari_server/setupSecurity.py | 7 +- .../src/test/python/TestAmbariServer.py | 272 +------ .../python/TestSensitiveDataEncryption.py | 667 ++++++++++++++++++ 4 files changed, 677 insertions(+), 271 deletions(-) create mode 100644 ambari-server/src/test/python/TestSensitiveDataEncryption.py diff --git a/ambari-server/src/main/python/ambari_server/serverConfiguration.py b/ambari-server/src/main/python/ambari_server/serverConfiguration.py index 6fcf7c5ad88..f340ff67ce8 100644 --- a/ambari-server/src/main/python/ambari_server/serverConfiguration.py +++ b/ambari-server/src/main/python/ambari_server/serverConfiguration.py @@ -1051,7 +1051,7 @@ def get_original_master_key(properties, options = None): masterKey = options.master_key if not masterKey: masterKey = get_validated_string_input('Enter current Master Key: ', - "", ".*", "", True, False) + "", ".*", "", True, True) if options is not None: options.master_key = masterKey except KeyboardInterrupt: diff --git a/ambari-server/src/main/python/ambari_server/setupSecurity.py b/ambari-server/src/main/python/ambari_server/setupSecurity.py index 2707d3abec9..460e147739c 100644 --- a/ambari-server/src/main/python/ambari_server/setupSecurity.py +++ b/ambari-server/src/main/python/ambari_server/setupSecurity.py @@ -537,7 +537,8 @@ def setup_sensitive_data_encryption(options): if isSecure: print "Password encryption is enabled." decrypt = get_YN_input("Do you want to decrypt passwords managed by Ambari? [y/n] (n): ", False) - resetKey = get_YN_input("Do you want to reset Master Key? [y/n] (n): ", False) + if not decrypt: + resetKey = get_YN_input("Do you want to reset Master Key? [y/n] (n): ", False) # Make sure both passwords are clear-text if master key is lost if resetKey or decrypt: @@ -561,14 +562,14 @@ def setup_sensitive_data_encryption(options): if not decrypt: if resetKey or not isSecure: # Read master key and encrypt sensitive data, if non-secure or reset is true - masterKey, persist = setup_master_key(masterKeyFile, options, properties, resetKey) + masterKey, isPersisted = setup_master_key(masterKeyFile, options, properties, resetKey) else: if not isPersisted: # For encrypting of only unencrypted passwords without resetting the key ask # for master key if not persisted. print "Master Key not persisted." masterKey = get_original_master_key(properties, options) - encrypt_sensitive_data(db_password, masterKey, options, persist, properties, ts_password) + encrypt_sensitive_data(db_password, masterKey, options, isPersisted, properties, ts_password) # Since files for store and master are created we need to ensure correct # permissions diff --git a/ambari-server/src/test/python/TestAmbariServer.py b/ambari-server/src/test/python/TestAmbariServer.py index ff6703e2696..7089ecf070f 100644 --- a/ambari-server/src/test/python/TestAmbariServer.py +++ b/ambari-server/src/test/python/TestAmbariServer.py @@ -92,7 +92,7 @@ def search_file_proxy(filename, searchpatch, pathsep=os.pathsep): RESOURCES_DIR_PROPERTY, JDBC_RCA_PASSWORD_ALIAS, JDBC_RCA_SCHEMA_PROPERTY, \ SSL_API, SSL_API_PORT, CLIENT_API_PORT_PROPERTY,\ JDBC_CONNECTION_POOL_TYPE, 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_IS_ENCRYPTION_ENABLED, PID_DIR_PROPERTY, \ SECURITY_MASTER_KEY_LOCATION, SECURITY_KEYS_DIR, store_password_file, \ get_pass_file_path, GET_FQDN_SERVICE_URL, SECURITY_KEY_ENV_VAR_NAME, \ JAVA_HOME_PROPERTY, JDK_NAME_PROPERTY, JCE_NAME_PROPERTY, STACK_LOCATION_KEY, SERVER_VERSION_FILE_PATH, \ @@ -108,7 +108,7 @@ def search_file_proxy(filename, searchpatch, pathsep=os.pathsep): SSL_DATE_FORMAT, import_cert_and_key, is_valid_cert_host, setup_truststore, \ 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_sensitive_data_encryption, \ + configure_ldap_password, setup_ldap, REGEX_HOSTNAME_PORT, REGEX_TRUE_FALSE, REGEX_ANYTHING,\ 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 @@ -313,13 +313,13 @@ def test_main_test_setup_security(self, init_logging_mock, setup_logging_mock, g @patch.object(OSCheck, "os_distribution", new = MagicMock(return_value = os_distro_value)) @patch.object(_ambari_server_, "setup_ambari_krb5_jaas") - @patch.object(_ambari_server_, "setup_master_key") + @patch.object(_ambari_server_, "setup_sensitive_data_encryption") @patch.object(_ambari_server_, "setup_truststore") @patch.object(_ambari_server_, "setup_https") @patch.object(_ambari_server_, "get_validated_string_input") @patch.object(_ambari_server_, "logger") def test_setup_security(self, logger_mock, get_validated_string_input_mock, setup_https_mock, - setup_truststore_mock, setup_master_key_mock, + setup_truststore_mock, setup_sensitive_data_encryption_mock, setup_ambari_krb5_jaas_mock): args = self._create_empty_options_mock() @@ -329,7 +329,7 @@ def test_setup_security(self, logger_mock, get_validated_string_input_mock, setu get_validated_string_input_mock.return_value = '2' _ambari_server_.setup_security(args) - self.assertTrue(setup_master_key_mock.called) + self.assertTrue(setup_sensitive_data_encryption_mock.called) get_validated_string_input_mock.return_value = '3' _ambari_server_.setup_security(args) @@ -6724,197 +6724,6 @@ def test_configure_database_password_silent(self): sys.stdout = sys.__stdout__ pass - @patch("os.path.exists") - @patch("ambari_server.setupSecurity.get_is_secure") - @patch("ambari_server.setupSecurity.get_is_persisted") - @patch("ambari_server.setupSecurity.remove_password_file") - @patch("ambari_server.setupSecurity.save_passwd_for_alias") - @patch("ambari_server.setupSecurity.read_master_key") - @patch("ambari_server.setupSecurity.read_ambari_user") - @patch("ambari_server.setupSecurity.get_master_key_location") - @patch("ambari_server.setupSecurity.update_properties_2") - @patch("ambari_server.setupSecurity.save_master_key") - @patch("ambari_server.setupSecurity.get_YN_input") - @patch("ambari_server.setupSecurity.search_file") - @patch("ambari_server.setupSecurity.get_ambari_properties") - @patch("ambari_server.setupSecurity.is_root") - def test_setup_master_key_not_persist(self, is_root_method, - get_ambari_properties_method, search_file_message, - get_YN_input_method, save_master_key_method, - update_properties_method, get_master_key_location_method, - read_ambari_user_method, read_master_key_method, - save_passwd_for_alias_method, remove_password_file_method, - get_is_persisted_method, get_is_secure_method, exists_mock): - - is_root_method.return_value = True - - p = Properties() - FAKE_PWD_STRING = "fakepasswd" - p.process_pair(JDBC_PASSWORD_PROPERTY, FAKE_PWD_STRING) - p.process_pair(SSL_TRUSTSTORE_PASSWORD_PROPERTY, FAKE_PWD_STRING) - p.process_pair(JDBC_RCA_PASSWORD_FILE_PROPERTY, FAKE_PWD_STRING) - get_ambari_properties_method.return_value = p - - read_master_key_method.return_value = "aaa" - get_YN_input_method.return_value = False - read_ambari_user_method.return_value = None - save_passwd_for_alias_method.return_value = 0 - get_is_persisted_method.return_value = (True, "filepath") - get_is_secure_method.return_value = False - exists_mock.return_value = False - - options = self._create_empty_options_mock() - setup_sensitive_data_encryption(options) - - self.assertTrue(get_YN_input_method.called) - self.assertTrue(read_master_key_method.called) - self.assertTrue(read_ambari_user_method.called) - self.assertTrue(update_properties_method.called) - self.assertFalse(save_master_key_method.called) - self.assertTrue(save_passwd_for_alias_method.called) - self.assertEquals(2, save_passwd_for_alias_method.call_count) - self.assertTrue(remove_password_file_method.called) - - result_expected = {JDBC_PASSWORD_PROPERTY: - get_alias_string(JDBC_RCA_PASSWORD_ALIAS), - JDBC_RCA_PASSWORD_FILE_PROPERTY: - get_alias_string(JDBC_RCA_PASSWORD_ALIAS), - SSL_TRUSTSTORE_PASSWORD_PROPERTY: - get_alias_string(SSL_TRUSTSTORE_PASSWORD_ALIAS), - SECURITY_IS_ENCRYPTION_ENABLED: 'true'} - - sorted_x = sorted(result_expected.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) - pass - - - @patch("ambari_server.setupSecurity.save_passwd_for_alias") - @patch("os.path.exists") - @patch("ambari_server.setupSecurity.get_is_secure") - @patch("ambari_server.setupSecurity.get_is_persisted") - @patch("ambari_server.setupSecurity.read_master_key") - @patch("ambari_server.setupSecurity.read_ambari_user") - @patch("ambari_server.setupSecurity.get_master_key_location") - @patch("ambari_server.setupSecurity.update_properties_2") - @patch("ambari_server.setupSecurity.save_master_key") - @patch("ambari_server.setupSecurity.get_YN_input") - @patch("ambari_server.serverConfiguration.search_file") - @patch("ambari_server.setupSecurity.get_ambari_properties") - @patch("ambari_server.setupSecurity.is_root") - def test_setup_master_key_persist(self, is_root_method, - get_ambari_properties_method, search_file_message, - get_YN_input_method, save_master_key_method, - update_properties_method, get_master_key_location_method, - read_ambari_user_method, read_master_key_method, - get_is_persisted_method, get_is_secure_method, exists_mock, - save_passwd_for_alias_method): - is_root_method.return_value = True - - p = Properties() - FAKE_PWD_STRING = "fakepasswd" - p.process_pair(JDBC_PASSWORD_PROPERTY, FAKE_PWD_STRING) - get_ambari_properties_method.return_value = p - - search_file_message.return_value = "propertiesfile" - - read_master_key_method.return_value = "aaa" - get_YN_input_method.side_effect = [True, False] - read_ambari_user_method.return_value = None - get_is_persisted_method.return_value = (True, "filepath") - get_is_secure_method.return_value = False - exists_mock.return_value = False - save_passwd_for_alias_method.return_value = 0 - - options = self._create_empty_options_mock() - setup_sensitive_data_encryption(options) - - self.assertTrue(get_YN_input_method.called) - self.assertTrue(read_master_key_method.called) - self.assertTrue(read_ambari_user_method.called) - self.assertTrue(update_properties_method.called) - self.assertTrue(save_master_key_method.called) - - result_expected = {JDBC_PASSWORD_PROPERTY: - get_alias_string(JDBC_RCA_PASSWORD_ALIAS), - SECURITY_IS_ENCRYPTION_ENABLED: 'true'} - - sorted_x = sorted(result_expected.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) - pass - - - @patch("ambari_server.setupSecurity.read_master_key") - @patch("ambari_server.setupSecurity.remove_password_file") - @patch("os.path.exists") - @patch("ambari_server.setupSecurity.read_ambari_user") - @patch("ambari_server.setupSecurity.get_master_key_location") - @patch("ambari_server.setupSecurity.save_passwd_for_alias") - @patch("ambari_server.setupSecurity.read_passwd_for_alias") - @patch("ambari_server.setupSecurity.update_properties_2") - @patch("ambari_server.setupSecurity.save_master_key") - @patch("ambari_server.setupSecurity.get_validated_string_input") - @patch("ambari_server.setupSecurity.get_YN_input") - @patch("ambari_server.setupSecurity.search_file") - @patch("ambari_server.setupSecurity.get_ambari_properties") - @patch("ambari_server.setupSecurity.is_root") - def test_reset_master_key_persisted(self, is_root_method, - get_ambari_properties_method, search_file_message, - get_YN_input_method, get_validated_string_input_method, - save_master_key_method, update_properties_method, - read_passwd_for_alias_method, save_passwd_for_alias_method, - get_master_key_location_method, - read_ambari_user_method, exists_mock, - remove_password_file_method, read_master_key_method): - - # Testing call under root - is_root_method.return_value = True - - search_file_message.return_value = "filepath" - read_ambari_user_method.return_value = None - - p = Properties() - FAKE_PWD_STRING = '${alias=fakealias}' - p.process_pair(JDBC_PASSWORD_PROPERTY, FAKE_PWD_STRING) - p.process_pair(SSL_TRUSTSTORE_PASSWORD_PROPERTY, FAKE_PWD_STRING) - p.process_pair(JDBC_RCA_PASSWORD_FILE_PROPERTY, FAKE_PWD_STRING) - get_ambari_properties_method.return_value = p - - get_YN_input_method.side_effect = [True, True] - read_master_key_method.return_value = "aaa" - read_passwd_for_alias_method.return_value = "fakepassword" - save_passwd_for_alias_method.return_value = 0 - exists_mock.return_value = False - - - options = self._create_empty_options_mock() - setup_sensitive_data_encryption(options) - - self.assertTrue(save_master_key_method.called) - self.assertTrue(get_YN_input_method.called) - self.assertTrue(read_master_key_method.called) - self.assertTrue(update_properties_method.called) - self.assertTrue(read_passwd_for_alias_method.called) - self.assertTrue(2, read_passwd_for_alias_method.call_count) - self.assertTrue(2, save_passwd_for_alias_method.call_count) - - result_expected = {JDBC_PASSWORD_PROPERTY: - get_alias_string(JDBC_RCA_PASSWORD_ALIAS), - JDBC_RCA_PASSWORD_FILE_PROPERTY: - get_alias_string(JDBC_RCA_PASSWORD_ALIAS), - SSL_TRUSTSTORE_PASSWORD_PROPERTY: - get_alias_string(SSL_TRUSTSTORE_PASSWORD_ALIAS), - SECURITY_IS_ENCRYPTION_ENABLED: 'true'} - - sorted_x = sorted(result_expected.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) - pass - @patch("os.path.isdir", new = MagicMock(return_value=True)) @patch("os.access", new = MagicMock(return_value=True)) @patch.object(ServerClassPath, "get_full_ambari_classpath_escaped_for_shell", new = MagicMock(return_value = 'test' + os.pathsep + 'path12')) @@ -6953,77 +6762,6 @@ def test_check_database(self, exitMock, getJavaExePathMock, pass - @patch("ambari_server.setupSecurity.get_is_persisted") - @patch("ambari_server.setupSecurity.get_is_secure") - @patch("ambari_server.setupSecurity.remove_password_file") - @patch("os.path.exists") - @patch("ambari_server.setupSecurity.read_ambari_user") - @patch("ambari_server.setupSecurity.get_master_key_location") - @patch("ambari_server.setupSecurity.save_passwd_for_alias") - @patch("ambari_server.setupSecurity.read_passwd_for_alias") - @patch("ambari_server.setupSecurity.update_properties_2") - @patch("ambari_server.setupSecurity.save_master_key") - @patch("ambari_server.setupSecurity.get_validated_string_input") - @patch("ambari_server.setupSecurity.get_YN_input") - @patch("ambari_server.setupSecurity.search_file") - @patch("ambari_server.setupSecurity.get_ambari_properties") - @patch("ambari_server.setupSecurity.is_root") - def test_reset_master_key_not_persisted(self, is_root_method, - get_ambari_properties_method, - search_file_message, get_YN_input_method, - get_validated_string_input_method, save_master_key_method, - update_properties_method, read_passwd_for_alias_method, - save_passwd_for_alias_method, - get_master_key_location_method, read_ambari_user_method, - exists_mock, remove_password_file_method, get_is_secure_method, - get_is_persisted_method): - - is_root_method.return_value = True - search_file_message.return_value = False - read_ambari_user_method.return_value = None - - p = Properties() - FAKE_PWD_STRING = '${alias=fakealias}' - p.process_pair(JDBC_PASSWORD_PROPERTY, FAKE_PWD_STRING) - p.process_pair(SSL_TRUSTSTORE_PASSWORD_PROPERTY, FAKE_PWD_STRING) - p.process_pair(JDBC_RCA_PASSWORD_FILE_PROPERTY, FAKE_PWD_STRING) - get_ambari_properties_method.return_value = p - - get_YN_input_method.side_effect = [True, False] - get_validated_string_input_method.return_value = "aaa" - read_passwd_for_alias_method.return_value = "fakepassword" - save_passwd_for_alias_method.return_value = 0 - exists_mock.return_value = False - get_is_secure_method.return_value = True - get_is_persisted_method.return_value = (True, "filePath") - - options = self._create_empty_options_mock() - setup_sensitive_data_encryption(options) - - self.assertFalse(save_master_key_method.called) - self.assertTrue(get_YN_input_method.called) - self.assertTrue(get_validated_string_input_method.called) - self.assertTrue(update_properties_method.called) - self.assertTrue(read_passwd_for_alias_method.called) - self.assertTrue(2, read_passwd_for_alias_method.call_count) - self.assertTrue(2, save_passwd_for_alias_method.call_count) - self.assertFalse(save_master_key_method.called) - - result_expected = {JDBC_PASSWORD_PROPERTY: - get_alias_string(JDBC_RCA_PASSWORD_ALIAS), - JDBC_RCA_PASSWORD_FILE_PROPERTY: - get_alias_string(JDBC_RCA_PASSWORD_ALIAS), - SSL_TRUSTSTORE_PASSWORD_PROPERTY: - get_alias_string(SSL_TRUSTSTORE_PASSWORD_ALIAS), - SECURITY_IS_ENCRYPTION_ENABLED: 'true'} - - sorted_x = sorted(result_expected.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) - pass - - @staticmethod @OsFamilyFuncImpl(OSConst.WINSRV_FAMILY) def _init_test_ldap_properties_map_invalid_input_1(): diff --git a/ambari-server/src/test/python/TestSensitiveDataEncryption.py b/ambari-server/src/test/python/TestSensitiveDataEncryption.py new file mode 100644 index 00000000000..4e839c4024c --- /dev/null +++ b/ambari-server/src/test/python/TestSensitiveDataEncryption.py @@ -0,0 +1,667 @@ +''' +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +''' +import os +import sys + +from ambari_commons.exceptions import FatalException +from mock.mock import patch, MagicMock, call + +with patch.object(os, "geteuid", new=MagicMock(return_value=0)): + from resource_management.core import sudo + reload(sudo) + +import operator +import platform +import StringIO +from unittest import TestCase +os.environ["ROOT"] = "" + +from only_for_platform import get_platform, os_distro_value, PLATFORM_WINDOWS +from ambari_commons import os_utils + +if get_platform() != PLATFORM_WINDOWS: + pass + +import shutil +project_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)),os.path.normpath("../../../../")) +shutil.copyfile(project_dir+"/ambari-server/conf/unix/ambari.properties", "/tmp/ambari.properties") + +# We have to use this import HACK because the filename contains a dash +_search_file = os_utils.search_file + + +def search_file_proxy(filename, searchpatch, pathsep=os.pathsep): + global _search_file + + if "ambari.properties" in filename: + return "/tmp/ambari.properties" + + return _search_file(filename, searchpatch, pathsep) + + +os_utils.search_file = search_file_proxy +with patch.object(platform, "linux_distribution", return_value = MagicMock(return_value=('Redhat', '6.4', 'Final'))): + with patch("os.path.isdir", return_value = MagicMock(return_value=True)): + with patch("os.access", return_value = MagicMock(return_value=True)): + with patch.object(os_utils, "parse_log4j_file", return_value={'ambari.log.dir': '/var/log/ambari-server'}): + with patch("platform.linux_distribution", return_value = os_distro_value): + with patch("os.symlink"): + with patch("glob.glob", return_value = ['/etc/init.d/postgresql-9.3']): + _ambari_server_ = __import__('ambari-server') + with patch("__builtin__.open"): + from ambari_server.properties import Properties + from ambari_server.serverConfiguration import configDefaults, JDBC_RCA_PASSWORD_FILE_PROPERTY, JDBC_PASSWORD_PROPERTY, \ + JDBC_RCA_PASSWORD_ALIAS, SSL_TRUSTSTORE_PASSWORD_PROPERTY, SECURITY_IS_ENCRYPTION_ENABLED, \ + SECURITY_SENSITIVE_DATA_ENCRYPTON_ENABLED, SSL_TRUSTSTORE_PASSWORD_ALIAS, SECURITY_KEY_ENV_VAR_NAME + from ambari_server.setupSecurity import get_alias_string, setup_sensitive_data_encryption, sensitive_data_encryption + from ambari_server.serverClassPath import ServerClassPath + + +@patch.object(platform, "linux_distribution", new = MagicMock(return_value=('Redhat', '6.4', 'Final'))) +@patch("ambari_server.dbConfiguration_linux.get_postgre_hba_dir", new = MagicMock(return_value = "/var/lib/pgsql/data")) +@patch("ambari_server.dbConfiguration_linux.get_postgre_running_status", new = MagicMock(return_value = "running")) +class TestSensitiveDataEncryption(TestCase): + def setUp(self): + out = StringIO.StringIO() + sys.stdout = out + + + def tearDown(self): + sys.stdout = sys.__stdout__ + + @patch("os.path.isdir", new = MagicMock(return_value=True)) + @patch("os.access", new = MagicMock(return_value=True)) + @patch.object(ServerClassPath, "get_full_ambari_classpath_escaped_for_shell", new = MagicMock(return_value = 'test' + os.pathsep + 'path12')) + @patch("ambari_server.setupSecurity.find_jdk") + @patch("ambari_server.setupSecurity.get_ambari_properties") + @patch("ambari_server.setupSecurity.run_os_command") + def test_sensitive_data_encryption(self, run_os_command_mock, get_ambari_properties_method, find_jdk_mock): + find_jdk_mock.return_value = "/" + environ = os.environ.copy() + + run_os_command_mock.return_value = 0,"","" + properties = Properties() + get_ambari_properties_method.return_value = properties + options = self._create_empty_options_mock() + sensitive_data_encryption(options, "encription") + run_os_command_mock.assert_called_with('None -cp test:path12 org.apache.ambari.server.security.encryption.SensitiveDataEncryption encription > /var/log/ambari-server/ambari-server.out 2>&1', environ) + pass + + @patch("ambari_server.setupSecurity.print_error_msg") + @patch("ambari_server.setupSecurity.find_jdk") + def test_sensitive_data_encryption_nojdk(self, find_jdk_mock, print_mock): + find_jdk_mock.return_value = None + + options = self._create_empty_options_mock() + code = sensitive_data_encryption(options, "encription") + self.assertEquals(code, 1) + print_mock.assert_called_with("No JDK found, please run the \"setup\" " + "command to install a JDK automatically or install any " + "JDK manually to " + configDefaults.JDK_INSTALL_DIR) + pass + + @patch("os.path.isdir", new = MagicMock(return_value=True)) + @patch("os.access", new = MagicMock(return_value=True)) + @patch.object(ServerClassPath, "get_full_ambari_classpath_escaped_for_shell", new = MagicMock(return_value = 'test' + os.pathsep + 'path12')) + @patch("ambari_server.setupSecurity.find_jdk") + @patch("ambari_server.setupSecurity.get_ambari_properties") + @patch("ambari_server.setupSecurity.run_os_command") + def test_sensitive_data_decryption_not_persisted(self, run_os_command_mock, get_ambari_properties_method, find_jdk_mock): + find_jdk_mock.return_value = "/" + environ = os.environ.copy() + master = "master" + environ[SECURITY_KEY_ENV_VAR_NAME] = master + + run_os_command_mock.return_value = 0,"","" + properties = Properties() + get_ambari_properties_method.return_value = properties + options = self._create_empty_options_mock() + sensitive_data_encryption(options, "decryption", master) + run_os_command_mock.assert_called_with('None -cp test:path12 org.apache.ambari.server.security.encryption.SensitiveDataEncryption decryption > /var/log/ambari-server/ambari-server.out 2>&1', environ) + pass + + @patch("ambari_server.setupSecurity.get_is_persisted") + @patch("ambari_server.setupSecurity.get_is_secure") + @patch("os.path.exists") + @patch("ambari_server.setupSecurity.read_ambari_user") + @patch("ambari_server.setupSecurity.save_passwd_for_alias") + @patch("ambari_server.setupSecurity.read_passwd_for_alias") + @patch("ambari_server.setupSecurity.update_properties_2") + @patch("ambari_server.setupSecurity.save_master_key") + @patch("ambari_server.setupSecurity.get_validated_string_input") + @patch("ambari_server.setupSecurity.get_YN_input") + @patch("ambari_server.setupSecurity.search_file") + @patch("ambari_server.setupSecurity.get_ambari_properties") + @patch("ambari_server.setupSecurity.is_root") + @patch("ambari_server.setupSecurity.sensitive_data_encryption") + @patch("ambari_server.setupSecurity.get_original_master_key") + def test_reset_master_key_not_persisted(self, get_original_master_key_mock, sensitive_data_encryption_metod, is_root_method, + get_ambari_properties_method, + search_file_message, get_YN_input_method, + get_validated_string_input_method, save_master_key_method, + update_properties_method, read_passwd_for_alias_method, + save_passwd_for_alias_method, + read_ambari_user_method, + exists_mock, get_is_secure_method, + get_is_persisted_method): + + is_root_method.return_value = True + search_file_message.return_value = False + read_ambari_user_method.return_value = None + + p = Properties() + FAKE_PWD_STRING = '${alias=fakealias}' + p.process_pair(JDBC_PASSWORD_PROPERTY, FAKE_PWD_STRING) + p.process_pair(SSL_TRUSTSTORE_PASSWORD_PROPERTY, FAKE_PWD_STRING) + p.process_pair(JDBC_RCA_PASSWORD_FILE_PROPERTY, FAKE_PWD_STRING) + get_ambari_properties_method.return_value = p + + master_key = "aaa" + get_YN_input_method.side_effect = [False, True, False] + get_validated_string_input_method.return_value = master_key + get_original_master_key_mock.return_value = master_key + read_passwd_for_alias_method.return_value = "fakepassword" + save_passwd_for_alias_method.return_value = 0 + exists_mock.return_value = False + get_is_secure_method.return_value = True + get_is_persisted_method.return_value = (False, "") + + options = self._create_empty_options_mock() + setup_sensitive_data_encryption(options) + calls = [call(options, "decryption", master_key), call(options, "encryption", master_key)] + sensitive_data_encryption_metod.assert_has_calls(calls) + + self.assertFalse(save_master_key_method.called) + self.assertTrue(get_original_master_key_mock.called) + self.assertTrue(get_YN_input_method.called) + self.assertTrue(get_validated_string_input_method.called) + self.assertTrue(update_properties_method.called) + self.assertTrue(read_passwd_for_alias_method.called) + self.assertTrue(2, read_passwd_for_alias_method.call_count) + self.assertTrue(2, save_passwd_for_alias_method.call_count) + self.assertFalse(save_master_key_method.called) + + result_expected = {JDBC_PASSWORD_PROPERTY: + get_alias_string(JDBC_RCA_PASSWORD_ALIAS), + JDBC_RCA_PASSWORD_FILE_PROPERTY: + get_alias_string(JDBC_RCA_PASSWORD_ALIAS), + SSL_TRUSTSTORE_PASSWORD_PROPERTY: + get_alias_string(SSL_TRUSTSTORE_PASSWORD_ALIAS), + SECURITY_IS_ENCRYPTION_ENABLED: 'true', + SECURITY_SENSITIVE_DATA_ENCRYPTON_ENABLED: 'true'} + + sorted_x = sorted(result_expected.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) + pass + + @patch("ambari_server.setupSecurity.get_is_persisted") + @patch("ambari_server.setupSecurity.get_is_secure") + @patch("os.path.exists") + @patch("ambari_server.setupSecurity.read_ambari_user") + @patch("ambari_server.setupSecurity.save_passwd_for_alias") + @patch("ambari_server.setupSecurity.read_passwd_for_alias") + @patch("ambari_server.setupSecurity.update_properties_2") + @patch("ambari_server.setupSecurity.save_master_key") + @patch("ambari_server.setupSecurity.get_YN_input") + @patch("ambari_server.setupSecurity.search_file") + @patch("ambari_server.setupSecurity.get_ambari_properties") + @patch("ambari_server.setupSecurity.is_root") + @patch("ambari_server.setupSecurity.sensitive_data_encryption") + @patch("ambari_server.setupSecurity.get_original_master_key") + def test_encrypt_part_not_persisted(self, get_original_master_key_mock, sensitive_data_encryption_metod, is_root_method, + get_ambari_properties_method, + search_file_message, get_YN_input_method, + save_master_key_method, + update_properties_method, read_passwd_for_alias_method, + save_passwd_for_alias_method, + read_ambari_user_method, + exists_mock, get_is_secure_method, + get_is_persisted_method): + + is_root_method.return_value = True + search_file_message.return_value = False + read_ambari_user_method.return_value = None + + p = Properties() + FAKE_PWD_STRING = '${alias=fakealias}' + p.process_pair(JDBC_PASSWORD_PROPERTY, get_alias_string(JDBC_RCA_PASSWORD_ALIAS)) + p.process_pair(SSL_TRUSTSTORE_PASSWORD_PROPERTY, FAKE_PWD_STRING) + p.process_pair(JDBC_RCA_PASSWORD_FILE_PROPERTY, FAKE_PWD_STRING) + get_ambari_properties_method.return_value = p + + master_key = "aaa" + get_YN_input_method.side_effect = [False, False, False] + get_original_master_key_mock.return_value = master_key + read_passwd_for_alias_method.return_value = "fakepassword" + save_passwd_for_alias_method.return_value = 0 + exists_mock.return_value = False + get_is_secure_method.return_value = True + get_is_persisted_method.return_value = (False, "filePath") + + options = self._create_empty_options_mock() + setup_sensitive_data_encryption(options) + calls = [call(options, "encryption", master_key)] + sensitive_data_encryption_metod.assert_has_calls(calls) + + self.assertFalse(save_master_key_method.called) + self.assertTrue(get_YN_input_method.called) + self.assertTrue(get_original_master_key_mock.called) + self.assertTrue(update_properties_method.called) + self.assertTrue(read_passwd_for_alias_method.called) + self.assertTrue(2, read_passwd_for_alias_method.call_count) + self.assertTrue(2, save_passwd_for_alias_method.call_count) + self.assertFalse(save_master_key_method.called) + + result_expected = {JDBC_PASSWORD_PROPERTY: + get_alias_string(JDBC_RCA_PASSWORD_ALIAS), + JDBC_RCA_PASSWORD_FILE_PROPERTY: + get_alias_string(JDBC_RCA_PASSWORD_ALIAS), + SSL_TRUSTSTORE_PASSWORD_PROPERTY: + get_alias_string(SSL_TRUSTSTORE_PASSWORD_ALIAS), + SECURITY_IS_ENCRYPTION_ENABLED: 'true', + SECURITY_SENSITIVE_DATA_ENCRYPTON_ENABLED: 'true'} + + sorted_x = sorted(result_expected.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) + pass + + @patch("ambari_server.setupSecurity.get_is_persisted") + @patch("ambari_server.setupSecurity.get_is_secure") + @patch("os.path.exists") + @patch("ambari_server.setupSecurity.read_ambari_user") + @patch("ambari_server.setupSecurity.save_passwd_for_alias") + @patch("ambari_server.setupSecurity.read_passwd_for_alias") + @patch("ambari_server.setupSecurity.save_master_key") + @patch("ambari_server.setupSecurity.get_YN_input") + @patch("ambari_server.setupSecurity.search_file") + @patch("ambari_server.setupSecurity.get_ambari_properties") + @patch("ambari_server.setupSecurity.is_root") + @patch("ambari_server.setupSecurity.get_original_master_key") + def test_decrypt_missed_masterkey_not_persisted(self, get_original_master_key_mock, is_root_method, + get_ambari_properties_method, + search_file_message, get_YN_input_method, + save_master_key_method, + read_passwd_for_alias_method, + save_passwd_for_alias_method, + read_ambari_user_method, + exists_mock, get_is_secure_method, + get_is_persisted_method): + + is_root_method.return_value = True + search_file_message.return_value = False + read_ambari_user_method.return_value = None + + p = Properties() + FAKE_PWD_STRING = '${alias=fakealias}' + p.process_pair(JDBC_PASSWORD_PROPERTY, get_alias_string(JDBC_RCA_PASSWORD_ALIAS)) + p.process_pair(SSL_TRUSTSTORE_PASSWORD_PROPERTY, FAKE_PWD_STRING) + p.process_pair(JDBC_RCA_PASSWORD_FILE_PROPERTY, FAKE_PWD_STRING) + get_ambari_properties_method.return_value = p + + get_YN_input_method.side_effect = [True, False] + get_original_master_key_mock.return_value = None + read_passwd_for_alias_method.return_value = "fakepassword" + save_passwd_for_alias_method.return_value = 0 + exists_mock.return_value = False + get_is_secure_method.return_value = True + get_is_persisted_method.return_value = (False, "filePath") + + options = self._create_empty_options_mock() + self.assertTrue(setup_sensitive_data_encryption(options) == 1) + + self.assertFalse(save_master_key_method.called) + self.assertTrue(get_YN_input_method.called) + pass + + @patch("ambari_server.setupSecurity.get_ambari_properties") + @patch("ambari_server.setupSecurity.is_root") + def test_setup_sensitive_data_encryption_no_ambari_prop_not_root(self, is_root_method, get_ambari_properties_method): + + is_root_method.return_value = False + get_ambari_properties_method.return_value = -1 + options = self._create_empty_options_mock() + + try: + setup_sensitive_data_encryption(options) + self.fail("Should throw exception") + except FatalException as fe: + self.assertTrue('Failed to read properties file.' == fe.reason) + pass + pass + + @patch("os.path.exists") + @patch("ambari_server.setupSecurity.get_is_secure") + @patch("ambari_server.setupSecurity.get_is_persisted") + @patch("ambari_server.setupSecurity.remove_password_file") + @patch("ambari_server.setupSecurity.save_passwd_for_alias") + @patch("ambari_server.setupSecurity.read_master_key") + @patch("ambari_server.setupSecurity.read_ambari_user") + @patch("ambari_server.setupSecurity.update_properties_2") + @patch("ambari_server.setupSecurity.save_master_key") + @patch("ambari_server.setupSecurity.get_YN_input") + @patch("ambari_server.setupSecurity.get_ambari_properties") + @patch("ambari_server.setupSecurity.is_root") + @patch("ambari_server.setupSecurity.sensitive_data_encryption") + @patch("ambari_server.setupSecurity.adjust_directory_permissions") + def test_setup_sensitive_data_encryption_not_persist(self, adjust_directory_permissions_mock, sensitive_data_encryption_metod, is_root_method, + get_ambari_properties_method, get_YN_input_method, save_master_key_method, + update_properties_method, + read_ambari_user_method, read_master_key_method, + save_passwd_for_alias_method, remove_password_file_method, + get_is_persisted_method, get_is_secure_method, exists_mock): + + is_root_method.return_value = True + + p = Properties() + FAKE_PWD_STRING = "fakepasswd" + p.process_pair(JDBC_PASSWORD_PROPERTY, FAKE_PWD_STRING) + p.process_pair(SSL_TRUSTSTORE_PASSWORD_PROPERTY, FAKE_PWD_STRING) + p.process_pair(JDBC_RCA_PASSWORD_FILE_PROPERTY, FAKE_PWD_STRING) + get_ambari_properties_method.return_value = p + + master_key = "aaa" + read_master_key_method.return_value = master_key + get_YN_input_method.return_value = False + read_ambari_user_method.return_value = "asd" + save_passwd_for_alias_method.return_value = 0 + get_is_persisted_method.return_value = (True, "filepath") + get_is_secure_method.return_value = False + exists_mock.return_value = False + + options = self._create_empty_options_mock() + setup_sensitive_data_encryption(options) + + self.assertTrue(get_YN_input_method.called) + self.assertTrue(read_master_key_method.called) + self.assertTrue(read_ambari_user_method.called) + self.assertTrue(update_properties_method.called) + self.assertFalse(save_master_key_method.called) + self.assertTrue(save_passwd_for_alias_method.called) + self.assertEquals(2, save_passwd_for_alias_method.call_count) + self.assertTrue(remove_password_file_method.called) + self.assertTrue(adjust_directory_permissions_mock.called) + sensitive_data_encryption_metod.assert_called_with(options, "encryption", master_key) + + result_expected = {JDBC_PASSWORD_PROPERTY: + get_alias_string(JDBC_RCA_PASSWORD_ALIAS), + JDBC_RCA_PASSWORD_FILE_PROPERTY: + get_alias_string(JDBC_RCA_PASSWORD_ALIAS), + SSL_TRUSTSTORE_PASSWORD_PROPERTY: + get_alias_string(SSL_TRUSTSTORE_PASSWORD_ALIAS), + SECURITY_IS_ENCRYPTION_ENABLED: 'true', + SECURITY_SENSITIVE_DATA_ENCRYPTON_ENABLED: 'true'} + + sorted_x = sorted(result_expected.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) + pass + + @patch("ambari_server.setupSecurity.save_passwd_for_alias") + @patch("os.path.exists") + @patch("ambari_server.setupSecurity.get_is_secure") + @patch("ambari_server.setupSecurity.get_is_persisted") + @patch("ambari_server.setupSecurity.read_master_key") + @patch("ambari_server.setupSecurity.read_ambari_user") + @patch("ambari_server.setupSecurity.update_properties_2") + @patch("ambari_server.setupSecurity.save_master_key") + @patch("ambari_server.setupSecurity.get_YN_input") + @patch("ambari_server.serverConfiguration.search_file") + @patch("ambari_server.setupSecurity.get_ambari_properties") + @patch("ambari_server.setupSecurity.is_root") + @patch("ambari_server.setupSecurity.sensitive_data_encryption") + def test_setup_sensitive_data_encryption_persist(self, sensitive_data_encryption_metod, is_root_method, + get_ambari_properties_method, search_file_message, + get_YN_input_method, save_master_key_method, + update_properties_method, + read_ambari_user_method, read_master_key_method, + get_is_persisted_method, get_is_secure_method, exists_mock, + save_passwd_for_alias_method): + is_root_method.return_value = True + + p = Properties() + FAKE_PWD_STRING = "fakepasswd" + p.process_pair(JDBC_PASSWORD_PROPERTY, FAKE_PWD_STRING) + get_ambari_properties_method.return_value = p + + search_file_message.return_value = "propertiesfile" + + master_key = "aaa" + read_master_key_method.return_value = master_key + get_YN_input_method.return_value = True + read_ambari_user_method.return_value = None + get_is_persisted_method.return_value = (True, "filepath") + get_is_secure_method.return_value = False + exists_mock.return_value = False + save_passwd_for_alias_method.return_value = 0 + + options = self._create_empty_options_mock() + setup_sensitive_data_encryption(options) + + self.assertTrue(get_YN_input_method.called) + self.assertTrue(read_master_key_method.called) + self.assertTrue(read_ambari_user_method.called) + self.assertTrue(update_properties_method.called) + self.assertTrue(save_master_key_method.called) + sensitive_data_encryption_metod.assert_called_with(options, "encryption") + + result_expected = {JDBC_PASSWORD_PROPERTY: + get_alias_string(JDBC_RCA_PASSWORD_ALIAS), + SECURITY_IS_ENCRYPTION_ENABLED: 'true', + SECURITY_SENSITIVE_DATA_ENCRYPTON_ENABLED: 'true'} + + sorted_x = sorted(result_expected.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) + pass + + @patch("ambari_server.setupSecurity.read_master_key") + @patch("os.path.exists") + @patch("ambari_server.setupSecurity.read_ambari_user") + @patch("ambari_server.setupSecurity.save_passwd_for_alias") + @patch("ambari_server.setupSecurity.read_passwd_for_alias") + @patch("ambari_server.setupSecurity.update_properties_2") + @patch("ambari_server.setupSecurity.save_master_key") + @patch("ambari_server.setupSecurity.get_YN_input") + @patch("ambari_server.setupSecurity.search_file") + @patch("ambari_server.setupSecurity.get_ambari_properties") + @patch("ambari_server.setupSecurity.is_root") + @patch("ambari_server.setupSecurity.sensitive_data_encryption") + @patch("ambari_server.setupSecurity.get_is_secure") + def test_reset_master_key_persisted(self, get_is_secure_method, sensitive_data_encryption_metod, is_root_method, + get_ambari_properties_method, search_file_message, + get_YN_input_method, + save_master_key_method, update_properties_method, + read_passwd_for_alias_method, save_passwd_for_alias_method, + read_ambari_user_method, exists_mock, + read_master_key_method): + + # Testing call under root + is_root_method.return_value = True + + search_file_message.return_value = "filepath" + read_ambari_user_method.return_value = None + + p = Properties() + FAKE_PWD_STRING = '${alias=fakealias}' + p.process_pair(JDBC_PASSWORD_PROPERTY, FAKE_PWD_STRING) + p.process_pair(SSL_TRUSTSTORE_PASSWORD_PROPERTY, FAKE_PWD_STRING) + p.process_pair(JDBC_RCA_PASSWORD_FILE_PROPERTY, FAKE_PWD_STRING) + get_ambari_properties_method.return_value = p + + master_key = "aaa" + + get_is_secure_method.return_value = True + get_YN_input_method.side_effect = [False, True, True] + read_master_key_method.return_value = master_key + read_passwd_for_alias_method.return_value = "fakepassword" + save_passwd_for_alias_method.return_value = 0 + exists_mock.return_value = False + + + options = self._create_empty_options_mock() + setup_sensitive_data_encryption(options) + calls = [call(options, "decryption"), call(options, "encryption")] + sensitive_data_encryption_metod.assert_has_calls(calls) + + self.assertTrue(save_master_key_method.called) + self.assertTrue(get_YN_input_method.called) + self.assertTrue(read_master_key_method.called) + self.assertTrue(update_properties_method.called) + self.assertTrue(read_passwd_for_alias_method.called) + self.assertTrue(2, read_passwd_for_alias_method.call_count) + self.assertTrue(2, save_passwd_for_alias_method.call_count) + + result_expected = {JDBC_PASSWORD_PROPERTY: + get_alias_string(JDBC_RCA_PASSWORD_ALIAS), + JDBC_RCA_PASSWORD_FILE_PROPERTY: + get_alias_string(JDBC_RCA_PASSWORD_ALIAS), + SSL_TRUSTSTORE_PASSWORD_PROPERTY: + get_alias_string(SSL_TRUSTSTORE_PASSWORD_ALIAS), + SECURITY_IS_ENCRYPTION_ENABLED: 'true', + SECURITY_SENSITIVE_DATA_ENCRYPTON_ENABLED: 'true'} + + sorted_x = sorted(result_expected.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) + pass + + @patch("ambari_server.setupSecurity.read_master_key") + @patch("os.path.exists") + @patch("ambari_server.setupSecurity.read_ambari_user") + @patch("ambari_server.setupSecurity.save_passwd_for_alias") + @patch("ambari_server.setupSecurity.read_passwd_for_alias") + @patch("ambari_server.setupSecurity.update_properties_2") + @patch("ambari_server.setupSecurity.get_YN_input") + @patch("ambari_server.setupSecurity.search_file") + @patch("ambari_server.setupSecurity.get_ambari_properties") + @patch("ambari_server.setupSecurity.is_root") + @patch("ambari_server.setupSecurity.sensitive_data_encryption") + @patch("ambari_server.setupSecurity.get_is_secure") + def test_decrypt_sensitive_data(self, get_is_secure_method, sensitive_data_encryption_metod, is_root_method, + get_ambari_properties_method, search_file_message, + get_YN_input_method, + update_properties_method, + read_passwd_for_alias_method, save_passwd_for_alias_method, + read_ambari_user_method, exists_mock, + read_master_key_method): + + # Testing call under root + is_root_method.return_value = True + + search_file_message.return_value = "filepath" + read_ambari_user_method.return_value = None + + p = Properties() + FAKE_PWD_STRING = '${alias=fakealias}' + p.process_pair(JDBC_PASSWORD_PROPERTY, FAKE_PWD_STRING) + p.process_pair(SSL_TRUSTSTORE_PASSWORD_PROPERTY, FAKE_PWD_STRING) + p.process_pair(JDBC_RCA_PASSWORD_FILE_PROPERTY, FAKE_PWD_STRING) + get_ambari_properties_method.return_value = p + + master_key = "aaa" + get_is_secure_method.return_value = True + get_YN_input_method.side_effect = [True, False] + read_master_key_method.return_value = master_key + read_passwd_for_alias_method.return_value = "fakepassword" + save_passwd_for_alias_method.return_value = 0 + exists_mock.return_value = False + + + options = self._create_empty_options_mock() + setup_sensitive_data_encryption(options) + calls = [call(options, "decryption")] + sensitive_data_encryption_metod.assert_has_calls(calls) + + self.assertTrue(get_YN_input_method.called) + self.assertTrue(update_properties_method.called) + self.assertTrue(read_passwd_for_alias_method.called) + self.assertTrue(2, read_passwd_for_alias_method.call_count) + self.assertTrue(2, save_passwd_for_alias_method.call_count) + + result_expected = {JDBC_PASSWORD_PROPERTY: "fakepassword", + JDBC_RCA_PASSWORD_FILE_PROPERTY: "fakepassword", + SSL_TRUSTSTORE_PASSWORD_PROPERTY: "fakepassword", + SECURITY_IS_ENCRYPTION_ENABLED: 'false', + SECURITY_SENSITIVE_DATA_ENCRYPTON_ENABLED: 'false'} + + sorted_x = sorted(result_expected.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) + pass + + def _create_empty_options_mock(self): + options = MagicMock() + options.ldap_enabled = None + options.ldap_enabled_ambari = None + options.ldap_manage_services = None + options.ldap_enabled_services = None + options.ldap_url = None + options.ldap_primary_host = None + options.ldap_primary_port = None + options.ldap_secondary_url = None + options.ldap_secondary_host = None + options.ldap_secondary_port = None + options.ldap_ssl = None + options.ldap_user_class = None + options.ldap_user_attr = None + options.ldap_user_group_member_attr = None + options.ldap_group_class = None + options.ldap_group_attr = None + options.ldap_member_attr = None + options.ldap_dn = None + options.ldap_base_dn = None + options.ldap_manager_dn = None + options.ldap_manager_password = None + options.ldap_save_settings = None + options.ldap_referral = None + options.ldap_bind_anonym = None + options.ldap_force_setup = None + options.ambari_admin_username = None + options.ambari_admin_password = None + options.ldap_sync_admin_name = None + options.ldap_sync_username_collisions_behavior = None + options.ldap_sync_disable_endpoint_identification = 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 + options.trust_store_path = None + options.trust_store_password = None + options.security_option = None + options.api_ssl = None + options.api_ssl_port = None + options.import_cert_path = None + options.import_cert_alias = None + options.pem_password = None + options.import_key_path = None + options.master_key = None + options.master_key_persist = None + options.jaas_principal = None + options.jaas_keytab = None + return options + +