From b780d859029fbbdfa4e5668507e6c9035dbedf2a Mon Sep 17 00:00:00 2001 From: jjiwooLim Date: Fri, 15 Sep 2023 17:09:25 -0400 Subject: [PATCH] enable signature verification --- .../plugins/util/InstallFeatureUtil.java | 334 ++++++++++++------ .../plugins/util/PrepareFeatureUtil.java | 4 +- .../plugins/util/ServerFeatureUtil.java | 122 +++++++ .../util/BaseInstallFeatureUtilTest.java | 20 +- .../InstallFeatureUtilGetInstallMapTest.java | 4 +- .../plugins/util/InstallFeatureUtilTest.java | 37 +- 6 files changed, 394 insertions(+), 127 deletions(-) diff --git a/src/main/java/io/openliberty/tools/common/plugins/util/InstallFeatureUtil.java b/src/main/java/io/openliberty/tools/common/plugins/util/InstallFeatureUtil.java index 041694a90..7cc1a3e16 100644 --- a/src/main/java/io/openliberty/tools/common/plugins/util/InstallFeatureUtil.java +++ b/src/main/java/io/openliberty/tools/common/plugins/util/InstallFeatureUtil.java @@ -25,6 +25,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; @@ -49,6 +50,7 @@ import java.util.logging.Level; import java.util.regex.MatchResult; import java.util.regex.Pattern; +import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.regex.Matcher; @@ -76,8 +78,6 @@ public abstract class InstallFeatureUtil extends ServerFeatureUtil { private final File buildDirectory; - private File installJarFile; - private final List propertiesList; private final String to; @@ -88,17 +88,31 @@ public abstract class InstallFeatureUtil extends ServerFeatureUtil { private final Set pluginListedEsas; + private final VerifyOption verifyOption; + + private final Collection> keyMap; + + + + /** + * An enum for specifying verify option + */ + public enum VerifyOption { + enforce, warn, skip, all; + } + //Map (symbolic name, short name) of the manually installed user feature. private Map manuallyInstalledUsrFeatureMap; private static final String INSTALL_MAP_PREFIX = "com.ibm.ws.install.map"; - private static final String INSTALL_MAP_SUFFIX = ".jar"; + private static final String JAR_EXT = ".jar"; private static final String OPEN_LIBERTY_PRODUCT_ID = "io.openliberty"; private static final String CLOSED_LIBERTY_PRODUCT_ID = "com.ibm.websphere.appserver"; private static final String FEATURES_BOM_ARTIFACT_ID = "features-bom"; private static final String FEATURES_JSON_ARTIFACT_ID = "features"; private static final String TO_USER = "usr"; private static final String MIN_USER_FEATURE_VERSION = "21.0.0.11"; + private static final String MIN_VERIFY_FEATURE_VERSION = "23.0.0.9"; private String openLibertyVersion; private static Boolean saveURLCacheStatus = null; @@ -126,7 +140,7 @@ public abstract class InstallFeatureUtil extends ServerFeatureUtil { * @throws PluginExecutionException If properties files cannot be found in the * installDirectory/lib/versions */ - public InstallFeatureUtil(File installDirectory, File buildDirectory, String from, String to, Set pluginListedEsas, List propertiesList, String openLibertyVersion, String containerName, List additionalJsons) throws PluginScenarioException, PluginExecutionException { + public InstallFeatureUtil(File installDirectory, File buildDirectory, String from, String to, Set pluginListedEsas, List propertiesList, String openLibertyVersion, String containerName, List additionalJsons, String verifyValue, Collection> keyMap) throws PluginScenarioException, PluginExecutionException { this.installDirectory = installDirectory; this.buildDirectory = buildDirectory; this.to = to; @@ -137,6 +151,18 @@ public InstallFeatureUtil(File installDirectory, File buildDirectory, String fro this.pluginListedEsas = pluginListedEsas; this.manuallyInstalledUsrFeatureMap = new HashMap(); + if(keyMap == null) { + this.keyMap = new ArrayList<>(); + }else { + this.keyMap = keyMap; + } + + try { + this.verifyOption = VerifyOption.valueOf(verifyValue); + } catch (IllegalArgumentException e) { + throw new PluginExecutionException("The "+ verifyValue + " verify option isn't valid. Specify one of the following valid options: enforce, warn, skip, all"); + } + if (containerName == null) { installJarFile = loadInstallJarFile(installDirectory); if (installJarFile == null) { @@ -207,16 +233,6 @@ private Set getAdditionalJsons() { return Jsons; } - private File loadInstallJarFile(File installDirectory) { - if (openLibertyVersion != null) { - File installJarOverride = downloadOverrideJar(OPEN_LIBERTY_GROUP_ID, INSTALL_MAP_ARTIFACT_ID); - if (installJarOverride != null && installJarOverride.exists()) { - return installJarOverride; - } - } - return getMapBasedInstallKernelJar(new File(installDirectory, "lib")); - } - /** * Log debug * @@ -288,6 +304,21 @@ private File loadInstallJarFile(File installDirectory) { */ public abstract File downloadArtifact(String groupId, String artifactId, String type, String version) throws PluginExecutionException; + /** + * Download the signature file from the specified Maven coordinates, or retrieve it + * from the cache if it already exists. This is same as downloadArtifact method, but for Gradle + * the signature file need to be copied to ESA file directory to be verified. + * + * @param esa The ESA file for the signature + * @param groupId The group ID + * @param artifactId The artifact ID + * @param type The type e.g. esa + * @param version The version + * @return The file corresponding to the downloaded artifact + * @throws PluginExecutionException If the artifact could not be downloaded + */ + public abstract File downloadSignature(File esa, String groupId, String artifactId, String type, String version) + throws PluginExecutionException; /** * Combine the given String collections into a set using case-insensitive @@ -458,7 +489,21 @@ private File downloadEsaArtifact(String mavenCoordinates) throws PluginExecution String groupId = mavenCoordinateArray[0]; String artifactId = mavenCoordinateArray[1]; String version = mavenCoordinateArray[2]; - return downloadArtifact(groupId, artifactId, "esa", version); + File downloadedEsa = downloadArtifact(groupId, artifactId, "esa", version); + if(this.verifyOption != VerifyOption.skip) { + //download signature file for this esa + try { + downloadSignature(downloadedEsa, groupId, artifactId, "esa.asc", version); + }catch(PluginExecutionException e) { + if(this.verifyOption == VerifyOption.all) { + throw e; + }else { + warn("Signature at coordinates " + mavenCoordinates + " could not be downloaded." + e.getMessage()); + } + } + + } + return downloadedEsa; } private Map downloadEsas(Collection mavenCoordsList, Map artifactIdToExt) throws PluginExecutionException { @@ -615,7 +660,6 @@ public void installFeatures(boolean isAcceptLicense, List featuresList) info("Neither InstallUtility nor FeatureUtility is available to install user feature esa."); info("Attempting to manually install the user feature esa without resolving its dependencies."); info("Recommended user action: upgrade to OpenLiberty version " + MIN_USER_FEATURE_VERSION + " or higher and provide features-bom file for the user feature esa."); - info("To directly install the esa file without providing features-bom file, upgrade to OpenLiberty version 23.0.0.2 or later."); copyUserFeature(pluginListedEsas, installDirectory); } @@ -637,16 +681,18 @@ public void installFeatures(boolean isAcceptLicense, List featuresList) } if(featuresToInstall.isEmpty()) { + info("featuresToInstall is empty"); return; } + + + info("featuresToInstall is not empty: " + featuresToInstall.toString()); if (containerName != null) { - installFeaturesOnContainer(featuresToInstall, isAcceptLicense); + installFeaturesOnContainer(featuresToInstall, isAcceptLicense, verifyOption); return; } - - info("Installing features: " + featuresToInstall); - + List jsonRepos = new ArrayList(downloadedJsons); debug("JSON repos: " + jsonRepos); @@ -659,51 +705,31 @@ public void installFeatures(boolean isAcceptLicense, List featuresList) } catch (MalformedURLException e) { throw new PluginExecutionException("Could not resolve URL from file " + installJarFile, e); } - Map mapBasedInstallKernel = null; disableCacheInURLClassLoader(); - try (final URLClassLoader loader = new URLClassLoader(new URL[] { installJarURL }, getClass().getClassLoader())) { - mapBasedInstallKernel = createMapBasedInstallKernelInstance(loader, installDirectory); - mapBasedInstallKernel.put("install.local.esa", true); - mapBasedInstallKernel.put("single.json.file", jsonRepos); - mapBasedInstallKernel.put("features.to.resolve", featuresToInstall); - mapBasedInstallKernel.put("license.accept", acceptLicenseMapValue); - mapBasedInstallKernel.put("is.install.server.feature", true); - - if (isDebugEnabled()) { - mapBasedInstallKernel.put("debug", Level.FINEST); - } - - Collection resolvedFeatures = (Collection) mapBasedInstallKernel.get("action.result"); - if (resolvedFeatures == null) { - debug("action.exception.stacktrace: " + mapBasedInstallKernel.get("action.exception.stacktrace")); - String exceptionMessage = (String) mapBasedInstallKernel.get("action.error.message"); - throw new PluginExecutionException(exceptionMessage); - } else if (resolvedFeatures.isEmpty()) { - debug("action.exception.stacktrace: " + mapBasedInstallKernel.get("action.exception.stacktrace")); - String exceptionMessage = (String) mapBasedInstallKernel.get("action.error.message"); - if (exceptionMessage == null) { - debug("resolvedFeatures was empty but the install kernel did not issue any messages"); - info("The features are already installed, so no action is needed."); - return; - } else if (exceptionMessage.contains("CWWKF1250I")) { - info(exceptionMessage); - info("The features are already installed, so no action is needed."); - return; - } else { - if (isFeatureConflict(exceptionMessage)) { - throw new PluginExecutionException( - CONFLICT_MESSAGE + featuresToInstall - + ": " + exceptionMessage); - } - throw new PluginExecutionException(exceptionMessage); - } - } + try { + String bundle = getOverrideBundleDescriptor(OPEN_LIBERTY_GROUP_ID, REPOSITORY_RESOLVER_ARTIFACT_ID); + mapBasedInstallKernel = createMapBasedInstallKernelInstance(bundle, installDirectory); + + + Collection resolvedFeatures = resolveFeatures(featuresToInstall, jsonRepos, acceptLicenseMapValue); + if(resolvedFeatures == null || resolvedFeatures.isEmpty()) { + return; + } + Map artifactsToExt = downloadEsas(resolvedFeatures, featureToExtMap); Set artifacts = artifactsToExt.keySet(); + + + if (verifyOption != null && verifyOption != VerifyOption.skip) { + verifyFeatures(artifacts, installJarURL); + } + + info("Installing features: " + featuresToInstall); StringBuilder installedFeaturesBuilder = new StringBuilder(); Collection actionReturnResult = new ArrayList(); + info("local esa install: " + mapBasedInstallKernel.get("install.local.esa")); for (File esaFile : artifacts) { mapBasedInstallKernel.put("license.accept", acceptLicenseMapValue); mapBasedInstallKernel.put("action.install", esaFile); @@ -767,6 +793,54 @@ public void installFeatures(boolean isAcceptLicense, List featuresList) } } + + + /** + * @param featuresToInstall + * @param jsonRepos + * @param acceptLicenseMapValue + * @return Collection of resolved features + * @throws PluginExecutionException + */ + private Collection resolveFeatures(List featuresToInstall, List jsonRepos, + boolean acceptLicenseMapValue) throws PluginExecutionException { + info("Resolving features... " ); + + mapBasedInstallKernel.put("install.local.esa", true); + mapBasedInstallKernel.put("single.json.file", jsonRepos); + mapBasedInstallKernel.put("features.to.resolve", featuresToInstall); + mapBasedInstallKernel.put("license.accept", acceptLicenseMapValue); + mapBasedInstallKernel.put("is.install.server.feature", true); + + + Collection resolvedFeatures = (Collection) mapBasedInstallKernel.get("action.result"); + if (resolvedFeatures == null) { + debug("action.exception.stacktrace: " + mapBasedInstallKernel.get("action.exception.stacktrace")); + String exceptionMessage = (String) mapBasedInstallKernel.get("action.error.message"); + throw new PluginExecutionException(exceptionMessage); + } else if (resolvedFeatures.isEmpty()) { + debug("action.exception.stacktrace: " + mapBasedInstallKernel.get("action.exception.stacktrace")); + String exceptionMessage = (String) mapBasedInstallKernel.get("action.error.message"); + if (exceptionMessage == null) { + debug("resolvedFeatures was empty but the install kernel did not issue any messages"); + info("The features are already installed, so no action is needed."); + return resolvedFeatures; + } else if (exceptionMessage.contains("CWWKF1250I")) { + info(exceptionMessage); + info("The features are already installed, so no action is needed."); + return resolvedFeatures; + } else { + if (isFeatureConflict(exceptionMessage)) { + throw new PluginExecutionException( + CONFLICT_MESSAGE + featuresToInstall + + ": " + exceptionMessage); + } + throw new PluginExecutionException(exceptionMessage); + } + } + return resolvedFeatures; + } + // Attempt to disable connection caching in the URLClassLoader so that the jar files will // all close when we close the class loader. Use reflection because this is not supported // in Java 8. Save the current value to restore it later for performance reasons. @@ -804,46 +878,34 @@ private synchronized void restoreCacheInURLClassLoader() { saveURLCacheStatus = null; } } - - private Map createMapBasedInstallKernelInstance(final ClassLoader loader, File installDirectory) - throws PrivilegedActionException, PluginExecutionException { - Map mapBasedInstallKernel = AccessController.doPrivileged(new PrivilegedExceptionAction>() { - @SuppressWarnings({ "unchecked" }) - @Override - public Map run() throws Exception { - - Class> clazz; - clazz = (Class>) loader.loadClass("com.ibm.ws.install.map.InstallMap"); - return clazz.newInstance(); - } - }); - if (mapBasedInstallKernel == null){ - throw new PluginExecutionException("Cannot run install jar file " + installJarFile); - } - - // Init - String bundle = getOverrideBundleDescriptor(OPEN_LIBERTY_GROUP_ID, REPOSITORY_RESOLVER_ARTIFACT_ID); - if (bundle != null) { - List bundles = new ArrayList(); - bundles.add(bundle); - debug("Overriding jar using: " + bundle); - mapBasedInstallKernel.put("override.jar.bundles", bundles); - } - mapBasedInstallKernel.put("runtime.install.dir", installDirectory); + + private File downloadOverrideJar(String groupId, String artifactId) { try { - mapBasedInstallKernel.put("install.map.jar.file", installJarFile); - debug("install.map.jar.file: " + installJarFile); - } catch (RuntimeException e) { - debug("This version of the install map does not support the key \"install.map.jar.file\"", e); - String installJarFileSubpath = installJarFile.getParentFile().getName() + File.separator + installJarFile.getName(); - mapBasedInstallKernel.put("install.map.jar", installJarFileSubpath); - debug("install.map.jar: " + installJarFileSubpath); + return downloadArtifact(groupId, artifactId, "jar", + String.format("[%s)", openLibertyVersion + ", " + getNextProductVersion(openLibertyVersion))); + } catch (PluginExecutionException e) { + debug("Using jar from Liberty directory for " + artifactId + " bundle."); + return null; } - debug("install.kernel.init.code: " + mapBasedInstallKernel.get("install.kernel.init.code")); - debug("install.kernel.init.error.message: " + mapBasedInstallKernel.get("install.kernel.init.error.message")); - File usrDir = new File(installDirectory, "usr"); - mapBasedInstallKernel.put("target.user.directory", usrDir); - return mapBasedInstallKernel; + } + + private File loadInstallJarFile(File installDirectory) { + if(installJarFile == null) { + if (openLibertyVersion != null) { + File installJarOverride = downloadOverrideJar(OPEN_LIBERTY_GROUP_ID, INSTALL_MAP_ARTIFACT_ID); + if (installJarOverride != null && installJarOverride.exists()) { + installJarFile = installJarOverride; + } else { + installJarFile = getMapBasedInstallKernelJar(new File(installDirectory, "lib"), INSTALL_MAP_PREFIX, + JAR_EXT); + } + } else { + installJarFile = getMapBasedInstallKernelJar(new File(installDirectory, "lib"), INSTALL_MAP_PREFIX, + JAR_EXT); + } + } + + return installJarFile; } /** @@ -870,15 +932,7 @@ public String getOverrideBundleDescriptor(String groupId, String artifactId) thr return null; } - private File downloadOverrideJar(String groupId, String artifactId) { - try { - return downloadArtifact(groupId, artifactId, "jar", - String.format("[%s)", openLibertyVersion + ", " + getNextProductVersion(openLibertyVersion))); - } catch (PluginExecutionException e) { - debug("Using jar from Liberty directory for " + artifactId + " bundle."); - return null; - } - } + /** * Gets the next product version number. @@ -929,19 +983,17 @@ public static String extractSymbolicName(File jar) throws PluginExecutionExcepti } } } - } - - /** + } /** * Find latest install map jar from specified directory * * @return the install map jar file */ - public static File getMapBasedInstallKernelJar(File dir) { + public static File getMapBasedInstallKernelJar(File dir, String prefix, String suffix) { File[] installMapJars = dir.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { - return name.startsWith(INSTALL_MAP_PREFIX) && name.endsWith(INSTALL_MAP_SUFFIX); + return name.startsWith(INSTALL_MAP_PREFIX) && name.endsWith(JAR_EXT); } }); @@ -984,7 +1036,7 @@ private static boolean isReplacementJar(File file1, File file2) { */ private static String extractVersion(String fileName) { int startIndex = INSTALL_MAP_PREFIX.length() + 1; // skip the underscore after the prefix - int endIndex = fileName.lastIndexOf(INSTALL_MAP_SUFFIX); + int endIndex = fileName.lastIndexOf(JAR_EXT); if (startIndex < endIndex) { return fileName.substring(startIndex, endIndex); } else { @@ -1116,8 +1168,13 @@ private void installFeaturesOnContainer(List features, boolean acceptLic featureUtilityCommand += "--acceptLicense"; } - String cmdResult = execContainerCmd(featureUtilityCommand, 600, false); - if (cmdResult.contains(" RC=")) { // This piece of the string is added in execContainerCmd if there is an error + + if(verifyOption != null) { + featureUtilityCommand += "--verify=" + verifyOption.name(); + } + + String cmdResult = execDockerCmd(featureUtilityCommand, 600, false); + if (cmdResult.contains(" RC=")) { // This piece of the string is added in execDockerCmd if there is an error if (cmdResult.contains("CWWKF1250I")) { // The features are already installed message debug(cmdResult); @@ -1140,4 +1197,55 @@ private boolean isFeatureConflict(String exceptionMessage) { Matcher m = conflictPattern.matcher(exceptionMessage); return m.find(); } + + + /** + * Verifies signatures(.asc) of downloaded artifacts(.esa), which is available from Liberty 23.0.0.9 + * @param artifacts downloaded artifacts + * @param installJarURL + * @throws PluginExecutionException + */ + public void verifyFeatures(Set artifacts, URL installJarURL) throws PluginExecutionException { + + if (VersionUtility.compareArtifactVersion(openLibertyVersion, MIN_VERIFY_FEATURE_VERSION, true) < 0) { + warn("Skipping feature verification. Minimum required Liberty version is " + MIN_VERIFY_FEATURE_VERSION); + return; + } + + downloadPublicKeys(); + + info("Verifying features"); + mapBasedInstallKernel.put("action.verify", artifacts.stream().collect(Collectors.toList())); + mapBasedInstallKernel.get("action.result"); + if (mapBasedInstallKernel.get("action.error.message") != null) { + // error with installation + if (mapBasedInstallKernel.get("action.exception.stacktrace") != null) { + debug("action.exception.stacktrace: " + mapBasedInstallKernel.get("action.exception.stacktrace")); + } + throw new PluginExecutionException((String) mapBasedInstallKernel.get("action.error.message")); + } + + } + + + + /** + * Downloads public key to verify signatures + * @throws PluginExecutionException + */ + private void downloadPublicKeys() throws PluginExecutionException { + info("Downloading public key(s) for signature verification"); + mapBasedInstallKernel.get("environment.variable.map"); + mapBasedInstallKernel.put("verify.option", verifyOption.name()); + mapBasedInstallKernel.put("user.public.keys", keyMap); + mapBasedInstallKernel.get("download.pubkeys"); + + if (mapBasedInstallKernel.get("action.error.message") != null) { + if (mapBasedInstallKernel.get("action.exception.stacktrace") != null) { + debug("action.exception.stacktrace: " + mapBasedInstallKernel.get("action.exception.stacktrace")); + } + throw new PluginExecutionException((String) mapBasedInstallKernel.get("action.error.message")); + } + } + } diff --git a/src/main/java/io/openliberty/tools/common/plugins/util/PrepareFeatureUtil.java b/src/main/java/io/openliberty/tools/common/plugins/util/PrepareFeatureUtil.java index 6187760f3..af51788e2 100644 --- a/src/main/java/io/openliberty/tools/common/plugins/util/PrepareFeatureUtil.java +++ b/src/main/java/io/openliberty/tools/common/plugins/util/PrepareFeatureUtil.java @@ -52,6 +52,8 @@ public abstract class PrepareFeatureUtil extends ServerFeatureUtil { public static final String INSTALL_MAP_ARTIFACT_ID = "install-map"; public static final String FEATURES_JSON_ARTIFACT_ID = "features"; private static final String MIN_USER_FEATURE_VERSION = "21.0.0.11"; + private static final String INSTALL_MAP_PREFIX = "com.ibm.ws.install.map"; + private static final String JAR_EXT = ".jar"; private File installJarFile; private File jsonFile; @@ -301,7 +303,7 @@ private File loadInstallJarFile(File installDirectory) { return installJarOverride; } } - return InstallFeatureUtil.getMapBasedInstallKernelJar(new File(installDirectory, "lib")); + return InstallFeatureUtil.getMapBasedInstallKernelJar(new File(installDirectory, "lib"), INSTALL_MAP_PREFIX, JAR_EXT); } private File downloadOverrideJar(String groupId, String artifactId) { diff --git a/src/main/java/io/openliberty/tools/common/plugins/util/ServerFeatureUtil.java b/src/main/java/io/openliberty/tools/common/plugins/util/ServerFeatureUtil.java index 478fd5f8d..5e241e285 100644 --- a/src/main/java/io/openliberty/tools/common/plugins/util/ServerFeatureUtil.java +++ b/src/main/java/io/openliberty/tools/common/plugins/util/ServerFeatureUtil.java @@ -20,9 +20,14 @@ import java.io.FileInputStream; import java.io.FilenameFilter; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; +import java.net.URLClassLoader; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -33,6 +38,7 @@ import java.util.Map; import java.util.Properties; import java.util.Set; +import java.util.logging.Level; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -71,6 +77,11 @@ public abstract class ServerFeatureUtil extends AbstractContainerSupportUtil imp private boolean lowerCaseFeatures = true; protected boolean suppressLogs = false; // set to true when info and warning messages should not be displayed to // users, messages are logged as debug instead + + protected File installJarFile; + private URLClassLoader installMapLoader = null; + private Class> installMapClass = null; + protected Map mapBasedInstallKernel= null; /** * Log debug @@ -534,5 +545,116 @@ protected File getUserExtensionPath() { } return libertyDirectoryPropertyToFile.get(USR_EXTENSION_DIR); } + + /** + * @return ClassLoader of com.ibm.ws.install.map.jar + * @throws MalformedURLException + * @throws PluginExecutionException + */ + private ClassLoader getInstallMapClassLoader() throws MalformedURLException, PluginExecutionException { + if (installJarFile == null) { + throw new PluginExecutionException("Install map jar not found."); + } + + if (installMapLoader == null) { + ClassLoader cl = this.getClass().getClassLoader(); + installMapLoader = new URLClassLoader(new URL[] { installJarFile.toURI().toURL() }, cl); + } + return installMapLoader; + } + + /** + * @return com.ibm.ws.install.map.InstallMap.class + * @throws MalformedURLException + * @throws PrivilegedActionException + * @throws PluginExecutionException + */ + private Class> getInstallMapClass() throws MalformedURLException, PrivilegedActionException, PluginExecutionException { + if (installMapClass == null) { + final ClassLoader cl = getInstallMapClassLoader(); + installMapClass = AccessController.doPrivileged(new PrivilegedExceptionAction >>() { + @SuppressWarnings({ "unchecked" }) + @Override + public Class> run() throws Exception { + installMapClass = (Class>) cl.loadClass("com.ibm.ws.install.map.InstallMap"); + return installMapClass; + } + }); + } + + if (installMapClass == null){ + throw new PluginExecutionException("Cannot run install jar file " + installJarFile); + } + + return installMapClass; + } + + /** + * @return creates a new instance of com.ibm.ws.install.map.InstallMap.class + * @throws MalformedURLException + * @throws PluginExecutionException + * @throws SecurityException + * @throws PrivilegedActionException + */ + private Map getInstallMapObject() + throws MalformedURLException, PluginExecutionException, SecurityException, PrivilegedActionException { + if (mapBasedInstallKernel == null) { + Class> clazz = getInstallMapClass(); + try { + mapBasedInstallKernel = (Map) clazz.getDeclaredConstructor().newInstance(); + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException + | InvocationTargetException | NoSuchMethodException | SecurityException e) { + // TODO Auto-generated catch block + throw new PluginExecutionException("Error finding install kernel map using reflection", e); + } + + if (mapBasedInstallKernel == null) { + throw new PluginExecutionException("Error finding install kernel map using reflection"); + } + } + return mapBasedInstallKernel; + } + + /** + * This creates a Install map and initializes basic information such as installDir, usrDir, logging level, etc. + * @param jars to override + * @param installDirectory + * @return Map of Install map + * @throws PrivilegedActionException + * @throws PluginExecutionException + * @throws MalformedURLException + */ + protected Map createMapBasedInstallKernelInstance(String bundle, File installDirectory) + throws PrivilegedActionException, PluginExecutionException, MalformedURLException { + mapBasedInstallKernel = getInstallMapObject(); + + // Init + if (bundle != null) { + List bundles = new ArrayList(); + bundles.add(bundle); + debug("Overriding jar using: " + bundle); + mapBasedInstallKernel.put("override.jar.bundles", bundles); + } + mapBasedInstallKernel.put("runtime.install.dir", installDirectory); + try { + mapBasedInstallKernel.put("install.map.jar.file", installJarFile); + debug("install.map.jar.file: " + installJarFile); + } catch (RuntimeException e) { + debug("This version of the install map does not support the key \"install.map.jar.file\"", e); + String installJarFileSubpath = installJarFile.getParentFile().getName() + File.separator + installJarFile.getName(); + mapBasedInstallKernel.put("install.map.jar", installJarFileSubpath); + debug("install.map.jar: " + installJarFileSubpath); + } + debug("install.kernel.init.code: " + mapBasedInstallKernel.get("install.kernel.init.code")); + debug("install.kernel.init.error.message: " + mapBasedInstallKernel.get("install.kernel.init.error.message")); + File usrDir = new File(installDirectory, "usr"); + mapBasedInstallKernel.put("target.user.directory", usrDir); + if (isDebugEnabled()) { + mapBasedInstallKernel.put("debug", Level.FINEST); + }else { + mapBasedInstallKernel.put("debug", Level.INFO); + } + return mapBasedInstallKernel; + } } \ No newline at end of file diff --git a/src/test/java/io/openliberty/tools/common/plugins/util/BaseInstallFeatureUtilTest.java b/src/test/java/io/openliberty/tools/common/plugins/util/BaseInstallFeatureUtilTest.java index 47631bd54..ff13eba17 100644 --- a/src/test/java/io/openliberty/tools/common/plugins/util/BaseInstallFeatureUtilTest.java +++ b/src/test/java/io/openliberty/tools/common/plugins/util/BaseInstallFeatureUtilTest.java @@ -18,8 +18,11 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import org.apache.commons.io.FileUtils; @@ -37,6 +40,7 @@ public class BaseInstallFeatureUtilTest { public File installDir; public File buildDir; + public String verify = "enforce"; @Rule public TemporaryFolder temp = new TemporaryFolder(); @@ -51,8 +55,8 @@ public void setupInstallDir() throws IOException { } public class InstallFeatureTestUtil extends InstallFeatureUtil { - public InstallFeatureTestUtil(File installDirectory, File buildDirectory, String from, String to, Set pluginListedEsas, List propertiesList, String openLibertyVersion, List additionalJsons) throws PluginScenarioException, PluginExecutionException { - super(installDirectory, buildDirectory, from, to, pluginListedEsas, propertiesList, openLibertyVersion, null, additionalJsons); + public InstallFeatureTestUtil(File installDirectory, File buildDirectory, String from, String to, Set pluginListedEsas, List propertiesList, String openLibertyVersion, List additionalJsons, String verifyOption, Collection> keyMap) throws PluginScenarioException, PluginExecutionException { + super(installDirectory, buildDirectory, from, to, pluginListedEsas, propertiesList, openLibertyVersion, null, additionalJsons, verifyOption, keyMap); } @Override @@ -99,18 +103,24 @@ public boolean isDebugEnabled() { public File downloadArtifact(String groupId, String artifactId, String type, String version) throws PluginExecutionException { return new File("dummy"); } + + @Override + public File downloadSignature(File esa, String groupId, String artifactId, String type, String version) throws PluginExecutionException { + return new File("dummy"); + } } public InstallFeatureUtil getNewInstallFeatureUtil() throws PluginExecutionException, PluginScenarioException { - return getNewInstallFeatureUtil(installDir, buildDir, null, null, new HashSet()); + return getNewInstallFeatureUtil(installDir, buildDir, null, null, new HashSet(), verify); } - public InstallFeatureUtil getNewInstallFeatureUtil(File installDirectory, File buildDirectory, String from, String to, Set pluginListedEsas) throws PluginExecutionException, PluginScenarioException { + public InstallFeatureUtil getNewInstallFeatureUtil(File installDirectory, File buildDirectory, String from, String to, Set pluginListedEsas, String verifyOption) throws PluginExecutionException, PluginScenarioException { List propertiesList = InstallFeatureUtil.loadProperties(installDirectory); String openLibertyVersion = InstallFeatureUtil.getOpenLibertyVersion(propertiesList); List additionalJsons = new ArrayList(); + Collection> keyMap = new ArrayList<>(); - return new InstallFeatureTestUtil(installDirectory, buildDirectory, from, to, pluginListedEsas, propertiesList, openLibertyVersion, additionalJsons); + return new InstallFeatureTestUtil(installDirectory, buildDirectory, from, to, pluginListedEsas, propertiesList, openLibertyVersion, additionalJsons, verifyOption, keyMap); } } diff --git a/src/test/java/io/openliberty/tools/common/plugins/util/InstallFeatureUtilGetInstallMapTest.java b/src/test/java/io/openliberty/tools/common/plugins/util/InstallFeatureUtilGetInstallMapTest.java index dece4673f..698a6e7a2 100644 --- a/src/test/java/io/openliberty/tools/common/plugins/util/InstallFeatureUtilGetInstallMapTest.java +++ b/src/test/java/io/openliberty/tools/common/plugins/util/InstallFeatureUtilGetInstallMapTest.java @@ -38,6 +38,8 @@ public class InstallFeatureUtilGetInstallMapTest { private String[] input; private String expected; + private static final String INSTALL_MAP_PREFIX = "com.ibm.ws.install.map"; + private static final String JAR_EXT = ".jar"; /** * Initialize test data for finding the install map jar @@ -109,7 +111,7 @@ public void test() throws IOException { File testFile = new File(installMapDir, testFileName); assertTrue(testFile.createNewFile()); } - String result = InstallFeatureUtil.getMapBasedInstallKernelJar(installMapDir).getName(); + String result = InstallFeatureUtil.getMapBasedInstallKernelJar(installMapDir, INSTALL_MAP_PREFIX, JAR_EXT).getName(); assertEquals(expected, result); } diff --git a/src/test/java/io/openliberty/tools/common/plugins/util/InstallFeatureUtilTest.java b/src/test/java/io/openliberty/tools/common/plugins/util/InstallFeatureUtilTest.java index 24602c520..9956fa533 100644 --- a/src/test/java/io/openliberty/tools/common/plugins/util/InstallFeatureUtilTest.java +++ b/src/test/java/io/openliberty/tools/common/plugins/util/InstallFeatureUtilTest.java @@ -7,8 +7,11 @@ import java.io.File; import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import org.junit.Test; @@ -32,7 +35,7 @@ public void testConstructorNoProperties() throws Exception { File wlProps = new File(installDir, "lib/versions/WebSphereApplicationServer.properties"); assertTrue(olProps.delete()); assertTrue(wlProps.delete()); - getNewInstallFeatureUtil(installDir, buildDir, null, null, new HashSet()); + getNewInstallFeatureUtil(installDir, buildDir, null, null, new HashSet(), verify); } /** @@ -42,7 +45,7 @@ public void testConstructorNoProperties() throws Exception { public void testConstructorNoInstallMap() throws Exception { File installMap = new File(installDir, "lib/com.ibm.ws.install.map_1.0.21.jar"); assertTrue(installMap.delete()); - getNewInstallFeatureUtil(installDir, buildDir, null, null, new HashSet()); + getNewInstallFeatureUtil(installDir, buildDir, null, null, new HashSet(), verify); } /** @@ -52,7 +55,7 @@ public void testConstructorNoInstallMap() throws Exception { public void testConstructorNoOpenLibertyProperties() throws Exception { File olProps = new File(installDir, "lib/versions/openliberty.properties"); assertTrue(olProps.delete()); - getNewInstallFeatureUtil(installDir, buildDir, null, null, new HashSet()); + getNewInstallFeatureUtil(installDir, buildDir, null, null, new HashSet(), verify); } /** @@ -64,12 +67,12 @@ public void testConstructorNoInstallMapNoOpenLibertyProperties() throws Exceptio assertTrue(olProps.delete()); File installMap = new File(installDir, "lib/com.ibm.ws.install.map_1.0.21.jar"); assertTrue(installMap.delete()); - getNewInstallFeatureUtil(installDir, buildDir, null, null, new HashSet()); + getNewInstallFeatureUtil(installDir, buildDir, null, null, new HashSet(), verify); } @Test public void testConstructorTo() throws Exception { - InstallFeatureUtil util = getNewInstallFeatureUtil(installDir, buildDir, null, "myextension", new HashSet()); + InstallFeatureUtil util = getNewInstallFeatureUtil(installDir, buildDir, null, "myextension", new HashSet(), verify); assertNotNull(util); } @@ -78,7 +81,7 @@ public void testConstructorTo() throws Exception { */ @Test(expected = PluginScenarioException.class) public void testConstructorFrom() throws Exception { - getNewInstallFeatureUtil(installDir, buildDir, installDir.getAbsolutePath(), null, new HashSet()); + getNewInstallFeatureUtil(installDir, buildDir, installDir.getAbsolutePath(), null, new HashSet(), verify); } @@ -171,7 +174,9 @@ public void testDownloadOverrideBundle() throws Exception { List propertiesList = InstallFeatureUtil.loadProperties(installDir); String openLibertyVersion = InstallFeatureUtil.getOpenLibertyVersion(propertiesList); List additionalJsons = new ArrayList(); - InstallFeatureUtil util = new InstallFeatureTestUtil(installDir, buildDir, null, null, new HashSet(), propertiesList, openLibertyVersion, additionalJsons) { + String verifyOption = "enforce"; + Collection> keyMap = new ArrayList<>(); + InstallFeatureUtil util = new InstallFeatureTestUtil(installDir, buildDir, null, null, new HashSet(), propertiesList, openLibertyVersion, additionalJsons, verifyOption, keyMap) { @Override public File downloadArtifact(String groupId, String artifactId, String type, String version) throws PluginExecutionException { @@ -246,4 +251,22 @@ public void testContainsIgnoreCase() throws Exception { target.add("other"); assertFalse("Collection " + reference + " should not contain all of the elements from " + target + " ignoring case", InstallFeatureUtil.containsIgnoreCase(reference, target)); } + + /** + * Test valid verify option + */ + @Test + public void testVerify() throws Exception { + getNewInstallFeatureUtil(installDir, buildDir, null, null, new HashSet(), "all"); + getNewInstallFeatureUtil(installDir, buildDir, null, null, new HashSet(), "skip"); + getNewInstallFeatureUtil(installDir, buildDir, null, null, new HashSet(), "enforce"); + getNewInstallFeatureUtil(installDir, buildDir, null, null, new HashSet(), "warn"); + } + + @Test(expected = PluginExecutionException.class) + public void testInvalidVerifyOption() throws Exception { + getNewInstallFeatureUtil(installDir, buildDir, null, null, new HashSet(), "invalid"); + } } + +