diff --git a/core/src/main/java/oracle/weblogic/deploy/util/FileUtils.java b/core/src/main/java/oracle/weblogic/deploy/util/FileUtils.java index 790558067..c12f57f5b 100644 --- a/core/src/main/java/oracle/weblogic/deploy/util/FileUtils.java +++ b/core/src/main/java/oracle/weblogic/deploy/util/FileUtils.java @@ -618,7 +618,7 @@ public static byte[] readInputStreamToByteArray(InputStream input) throws IOExce } public static File writeInputStreamToFile(InputStream input, String fileName) throws IOException { - File tmpdir = new File(System.getProperty("java.io.tmpdir")); + File tmpdir = getTmpDir(); File file = new File(tmpdir, fileName); try (FileOutputStream fos = new FileOutputStream(file)) { byte[] byteArray = FileUtils.readInputStreamToByteArray(input); @@ -627,6 +627,9 @@ public static File writeInputStreamToFile(InputStream input, String fileName) th return file; } + public static File getTmpDir() { + return new File(System.getProperty("java.io.tmpdir")); + } public static void extractZipFileContent(WLSDeployArchive archiveFile, String zipEntry, String extractPath) { final String METHOD = "extractZipFileContent"; diff --git a/core/src/main/java/oracle/weblogic/deploy/util/WLSDeployArchive.java b/core/src/main/java/oracle/weblogic/deploy/util/WLSDeployArchive.java index aca36b397..88317a059 100644 --- a/core/src/main/java/oracle/weblogic/deploy/util/WLSDeployArchive.java +++ b/core/src/main/java/oracle/weblogic/deploy/util/WLSDeployArchive.java @@ -615,6 +615,15 @@ public String addApplication(String appPath) throws WLSDeployArchiveIOException return newName; } + public String replaceApplication(String appPath, String tempFile) throws WLSDeployArchiveIOException { + final String METHOD = "replaceApplication"; + LOGGER.entering(CLASS, METHOD, appPath); + getZipFile().removeZipEntry(appPath); + String newName = addApplication(tempFile); + LOGGER.exiting(CLASS, METHOD, newName); + return newName; + } + public String addApplicationFolder(String appName, String appPath) throws WLSDeployArchiveIOException { final String METHOD = "addApplicationFolder"; diff --git a/core/src/main/python/discover.py b/core/src/main/python/discover.py index a8f59cdc6..6d5a98703 100644 --- a/core/src/main/python/discover.py +++ b/core/src/main/python/discover.py @@ -219,13 +219,14 @@ def __process_domain_home(arg_map, wlst_mode): arg_map[CommandLineArgUtil.DOMAIN_HOME_SWITCH] = full_path -def __discover(model_context, aliases, credential_injector, helper): +def __discover(model_context, aliases, credential_injector, helper, extra_tokens): """ Populate the model from the domain. :param model_context: the model context :param aliases: aliases instance for discover :param credential_injector: credential injector instance :param helper: wlst_helper instance + :param extra_tokens: dictionary to store non-credential tokens during credential search :return: the fully-populated model :raises DiscoverException: if an error occurred while discover the domain """ @@ -233,7 +234,6 @@ def __discover(model_context, aliases, credential_injector, helper): model = Model() base_location = LocationContext() __connect_to_domain(model_context, helper) - try: _add_domain_name(base_location, aliases, helper) DomainInfoDiscoverer(model_context, model.get_model_domain_info(), base_location, wlst_mode=__wlst_mode, @@ -243,7 +243,8 @@ def __discover(model_context, aliases, credential_injector, helper): ResourcesDiscoverer(model_context, model.get_model_resources(), base_location, wlst_mode=__wlst_mode, aliases=aliases, credential_injector=credential_injector).discover() DeploymentsDiscoverer(model_context, model.get_model_app_deployments(), base_location, wlst_mode=__wlst_mode, - aliases=aliases, credential_injector=credential_injector).discover() + aliases=aliases, credential_injector=credential_injector, + extra_tokens=extra_tokens).discover() __discover_multi_tenant(model, model_context, base_location, aliases, credential_injector) except AliasException, ae: wls_version = WebLogicHelper(__logger).get_actual_weblogic_version() @@ -448,7 +449,7 @@ def __persist_model(model, model_context): __logger.exiting(class_name=_class_name, method_name=_method_name) -def __check_and_customize_model(model, model_context, aliases, credential_injector): +def __check_and_customize_model(model, model_context, aliases, credential_injector, extra_tokens): """ Customize the model dictionary before persisting. Validate the model after customization for informational purposes. Any validation errors will not stop the discovered model to be persisted. @@ -456,6 +457,7 @@ def __check_and_customize_model(model, model_context, aliases, credential_inject :param model_context: configuration from command-line :param aliases: used for validation if model changes are made :param credential_injector: injector created to collect and tokenize credentials, possibly None + :param extra_tokens: dictionary to handle non-credential tokenized arguments """ _method_name = '__check_and_customize_model' __logger.entering(class_name=_class_name, method_name=_method_name) @@ -492,9 +494,12 @@ def __check_and_customize_model(model, model_context, aliases, credential_inject # Apply the injectors specified in model_variable_injector.json, or in the target configuration. # Include the variable mappings that were collected in credential_cache. + variable_injector = VariableInjector(_program_name, model.get_model(), model_context, WebLogicHelper(__logger).get_actual_weblogic_version(), credential_cache) + variable_injector.add_to_cache(dictionary=extra_tokens) + inserted, variable_model, variable_file_name = variable_injector.inject_variables_keyword_file() if inserted: @@ -589,10 +594,11 @@ def main(model_context): else: __logger.info('WLSDPLY-06024', class_name=_class_name, method_name=_method_name) + extra_tokens = {} try: - model = __discover(model_context, aliases, credential_injector, helper) + model = __discover(model_context, aliases, credential_injector, helper, extra_tokens) - model = __check_and_customize_model(model, model_context, aliases, credential_injector) + model = __check_and_customize_model(model, model_context, aliases, credential_injector, extra_tokens) __remote_report(model_context) except DiscoverException, ex: diff --git a/core/src/main/python/wlsdeploy/aliases/model_constants.py b/core/src/main/python/wlsdeploy/aliases/model_constants.py index 57ebb37b2..00a3cde90 100644 --- a/core/src/main/python/wlsdeploy/aliases/model_constants.py +++ b/core/src/main/python/wlsdeploy/aliases/model_constants.py @@ -192,6 +192,7 @@ MESSAGE_LOGGING_PARAMS = 'MessageLoggingParams' MESSAGING_BRIDGE = 'MessagingBridge' METHOD = 'Method' +MODULE_TYPE = 'ModuleType' MULTICAST = 'Multicast' MULTICAST_ADDRESS = 'MulticastAddress' MULTICAST_PORT = 'MulticastPort' diff --git a/core/src/main/python/wlsdeploy/tool/discover/deployments_discoverer.py b/core/src/main/python/wlsdeploy/tool/discover/deployments_discoverer.py index 65b9ec1c1..28ef1f7e0 100644 --- a/core/src/main/python/wlsdeploy/tool/discover/deployments_discoverer.py +++ b/core/src/main/python/wlsdeploy/tool/discover/deployments_discoverer.py @@ -4,14 +4,22 @@ """ import os +from java.io import BufferedReader +from java.io import BufferedWriter from java.io import File +from java.io import FileReader +from java.io import FileWriter from java.lang import IllegalArgumentException +from java.lang import StringBuilder +from java.util.regex import Pattern from oracle.weblogic.deploy.util import PyOrderedDict as OrderedDict +from oracle.weblogic.deploy.util import FileUtils from oracle.weblogic.deploy.util import StringUtils from oracle.weblogic.deploy.util import WLSDeployArchiveIOException from oracle.weblogic.deploy.util import WLSDeployArchive +from wlsdeploy.aliases.alias_constants import PASSWORD_TOKEN from wlsdeploy.aliases import model_constants from wlsdeploy.aliases.location_context import LocationContext from wlsdeploy.aliases.wlst_modes import WlstModes @@ -19,6 +27,7 @@ from wlsdeploy.logging.platform_logger import PlatformLogger from wlsdeploy.tool.discover import discoverer from wlsdeploy.tool.discover.discoverer import Discoverer +from wlsdeploy.util import dictionary_utils from wlsdeploy.util import path_utils _class_name = 'DeploymentsDiscoverer' @@ -32,9 +41,10 @@ class DeploymentsDiscoverer(Discoverer): """ def __init__(self, model_context, deployments_dictionary, base_location, - wlst_mode=WlstModes.OFFLINE, aliases=None, credential_injector=None): + wlst_mode=WlstModes.OFFLINE, aliases=None, credential_injector=None, extra_tokens=None): Discoverer.__init__(self, model_context, base_location, wlst_mode, aliases, credential_injector) self._dictionary = deployments_dictionary + self._extra_tokens = extra_tokens def discover(self): """ @@ -241,6 +251,7 @@ def _add_application_to_archive(self, application_name, application_dict): """ _method_name = 'add_application_to_archive' _logger.entering(application_name, class_name=_class_name, method_name=_method_name) + archive_file = self._model_context.get_archive_file() if model_constants.SOURCE_PATH in application_dict: if model_constants.PLAN_DIR in application_dict and \ @@ -265,6 +276,11 @@ def _add_application_to_archive(self, application_name, application_dict): method_name=_method_name) try: new_source_name = archive_file.addApplication(file_name_path) + module_type = dictionary_utils.get_dictionary_element(application_dict, + model_constants.MODULE_TYPE) + if module_type == 'jdbc': + self._jdbc_password_fix(new_source_name) + except IllegalArgumentException, iae: self._disconnect_target(application_name, application_dict, iae.getLocalizedMessage()) except WLSDeployArchiveIOException, wioe: @@ -325,6 +341,78 @@ def _create_app_folder(self, application_name, application_dict): _logger.exiting(class_name=_class_name, method_name=_method_name) + def _jdbc_password_fix(self, source_name): + """ + This will look for password and userid in the jdbc standalone xml and + replace with either fix password token or a token in the xml and variable file. + It extracts the jdbc xml from the archive and then replaces it with the updated file. + :param source_name: Name of the path and file for the standalone xml file + """ + _method_name = '_jdbc_password_fix' + _logger.entering(source_name, class_name=_class_name, method_name=_method_name) + archive_file = self._model_context.get_archive_file() + tmp_dir = FileUtils.getTmpDir(); + temp_file = FileUtils.createTempDirectory(tmp_dir, 'jdbc-xml') + jdbc_file = archive_file.extractFile(source_name, temp_file) + jdbc_out = FileUtils.createTempDirectory(tmp_dir, 'jdbc-out') + jdbc_out = archive_file.extractFile(source_name, jdbc_out) + bis = BufferedReader(FileReader(jdbc_file)) + bos = BufferedWriter(FileWriter(jdbc_out)) + cache = StringBuilder() + while bis.ready(): + cache.append(bis.readLine()).append("\n") + bis.close() + pattern = Pattern.compile("(\s?)user(\s?)") + matcher = pattern.matcher(cache.toString()) + end = -1 + if matcher.find(): + end = matcher.end() + result = cache.toString() + if end >= 0: + pattern = Pattern.compile("(.+?)") + matcher = pattern.matcher(result[end:]) + matcher.find() + username = matcher.group() + username = username[len(''):len(username) - len('')] + pattern = Pattern.compile(matcher.group()) + matcher = pattern.matcher(cache.toString()) + result = matcher.replaceFirst(self._get_pass_replacement(jdbc_file, '-user:username', + 'value', username=username)) + + pattern = Pattern.compile('(.+?)') + matcher = pattern.matcher(result) + result = matcher.replaceFirst(self._get_pass_replacement(jdbc_file, '-user:password', 'password-encrypted')) + + pattern = Pattern.compile('(\s*)(.+?)(\s*)') + matcher = pattern.matcher(result) + matcher.find() + result = matcher.replaceFirst(self._get_pass_replacement(jdbc_file, '-url', 'url', + properties=matcher.group(2))) + + pattern = Pattern.compile('(.+?)') + matcher = pattern.matcher(result) + result = matcher.replaceFirst(self._get_pass_replacement(jdbc_file, '-ons-pass-encrypt:password', + 'ons-wallet-password-encrypted')) + bos.write(result) + bos.close() + archive_file.replaceApplication(source_name, jdbc_out) + _logger.exiting(class_name=_class_name, method_name=_method_name) + + def _get_pass_replacement(self, jdbc_file, name, type, properties=None, username=''): + if self._credential_injector is not None: + head, tail = os.path.split(jdbc_file) + token = tail[:len(tail) - len('.xml')] + token = token + name + if properties is not None: + self._extra_tokens[token] = properties + result = self._credential_injector.get_property_token(None, token) + else: + result = self._credential_injector.injection_out_of_model(token, username) + else: + result = PASSWORD_TOKEN + result = '<' + type + '>' + result + '' + return result + def _test_app_folder(self, source_path, plan_dir): app_folder = False app_dir = File(source_path).getParent() diff --git a/core/src/main/python/wlsdeploy/tool/util/credential_injector.py b/core/src/main/python/wlsdeploy/tool/util/credential_injector.py index ba3de4976..c30a54732 100644 --- a/core/src/main/python/wlsdeploy/tool/util/credential_injector.py +++ b/core/src/main/python/wlsdeploy/tool/util/credential_injector.py @@ -81,6 +81,8 @@ def __init__(self, program_name, model, model_context, version=None, variable_di VariableInjector.__init__(self, program_name, model, model_context, version=version, variable_dictionary=variable_dictionary) self._model_context = model_context + self._no_filter_keys_cache = [] + self._no_filter_keys_cache.append(self.NO_FILTER_KEYS) def check_and_tokenize(self, model_dict, attribute, location): """ @@ -138,6 +140,22 @@ def check_and_tokenize(self, model_dict, attribute, location): assigns.append('%s=%s' % (key, properties[key])) model_dict[attribute] = split_value.join(assigns) + def injection_out_of_model(self, token, username=''): + """ + This is for tokenizing variables that are not in the model but need to be in the variable file + :param token: name for cache to create a token for + :param username: usernames appear as part of property value + :return: tokenized name + """ + _method_name = 'injection_out_of_model' + _logger.entering(token, class_name=_class_name, method_name=_method_name) + result = self.get_variable_token(None, token) + self.add_to_cache(token_name=token, token_value=username) + + self._no_filter_keys_cache.append(token) + _logger.exiting(class_name=_class_name, method_name=_method_name, result=result) + return result + def get_variable_name(self, attribute_location, attribute, suffix=None): """ Override method to possibly create secret token names instead of property names. @@ -191,6 +209,9 @@ def get_variable_token(self, attribute, variable_name): else: return VariableInjector.get_variable_token(self, attribute, variable_name) + def get_property_token(self, attribute, variable_name): + return VariableInjector.get_variable_token(self, attribute, variable_name) + def _check_tokenized(self, attribute_value): """ Override to return true if target uses credentials and the value is formatted like @@SECRET:xyz:abc@@. @@ -222,7 +243,7 @@ def filter_unused_credentials(self, model_dictionary): cache_keys = self.get_variable_cache().keys() for key in cache_keys: - if key in self.NO_FILTER_KEYS: + if key in self._no_filter_keys_cache: continue if credentials_method == SECRETS_METHOD: diff --git a/core/src/main/python/wlsdeploy/util/target_configuration_helper.py b/core/src/main/python/wlsdeploy/util/target_configuration_helper.py index 9d697207a..bfc7c4f0a 100644 --- a/core/src/main/python/wlsdeploy/util/target_configuration_helper.py +++ b/core/src/main/python/wlsdeploy/util/target_configuration_helper.py @@ -33,6 +33,15 @@ WEBLOGIC_CREDENTIALS_SECRET_NAME = 'weblogic-credentials' WEBLOGIC_CREDENTIALS_SECRET_SUFFIX = '-' + WEBLOGIC_CREDENTIALS_SECRET_NAME +JDBC_CREDENTIALS_SECRET_USER_NAME = 'standalone-jdbc.xml.user' +JDBC_CREDENTIALS_SECRET_USER_SUFFIX = '-' + JDBC_CREDENTIALS_SECRET_USER_NAME + +JDBC_CREDENTIALS_SECRET_PASS_NAME = 'standalone-jdbc.xml.pass.encrypt' +JDBC_CREDENTIALS_SECRET_PASS_SUFFIX = '-' + JDBC_CREDENTIALS_SECRET_PASS_NAME + +JDBC_CREDENTIALS_SECRET_ONS_PASS_NAME = 'standalone-jdbc.xml.ons.pass.encrypt' +JDBC_CREDENTIALS_SECRET_ONS_PASS_SUFFIX = '-' + JDBC_CREDENTIALS_SECRET_ONS_PASS_NAME + RUNTIME_ENCRYPTION_SECRET_NAME = 'runtime-encryption-secret' RUNTIME_ENCRYPTION_SECRET_SUFFIX = '-' + RUNTIME_ENCRYPTION_SECRET_NAME @@ -133,6 +142,7 @@ def _prepare_k8s_secrets(model_context, token_dictionary, model_dictionary): for secret_name in secret_names: secret_keys = secret_map[secret_name] user_name = dictionary_utils.get_element(secret_keys, SECRET_USERNAME_KEY) + if user_name is None: secrets.append(_build_secret_hash(secret_name, None, PASSWORD_TAG)) else: diff --git a/core/src/main/resources/oracle/weblogic/deploy/k8s/create_k8s_secrets.sh b/core/src/main/resources/oracle/weblogic/deploy/k8s/create_k8s_secrets.sh index c78f950a0..83ca1f055 100644 --- a/core/src/main/resources/oracle/weblogic/deploy/k8s/create_k8s_secrets.sh +++ b/core/src/main/resources/oracle/weblogic/deploy/k8s/create_k8s_secrets.sh @@ -34,7 +34,7 @@ function create_paired_k8s_secret { {{#comments}} # {{{comment}}} {{/comments}} -create_paired_k8s_secret {{{secretName}}} {{{user}}} {{{password}}} +create_paired_k8s_secret {{{secretName}}} "{{{user}}}" {{{password}}} {{/pairedSecrets}} {{#secrets}}