1 /*
   2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import java.nio.file.Files;
  25 import java.nio.file.Path;
  26 import java.nio.file.Paths;
  27 import java.security.KeyStore;
  28 import java.security.cert.Certificate;
  29 import java.security.cert.X509Certificate;
  30 import java.util.LinkedHashMap;
  31 import java.util.List;
  32 import java.util.Map;
  33 import java.util.Arrays;
  34 import java.io.FileOutputStream;
  35 import java.io.IOException;
  36 import java.io.File;
  37 import java.io.OutputStream;
  38 import java.lang.module.ModuleDescriptor;
  39 import sun.security.tools.keytool.CertAndKeyGen;
  40 import sun.security.x509.X500Name;
  41 import jdk.internal.module.ModuleInfoWriter;
  42 import jdk.testlibrary.ProcessTools;
  43 import jdk.testlibrary.OutputAnalyzer;
  44 import jdk.testlibrary.JDKToolLauncher;
  45 
  46 /**
  47  * @test
  48  * @bug 8130360
  49  * @library /jdk/jigsaw/lib
  50  * @library /lib/testlibrary
  51  * @library /java/security/modules
  52  * @summary Test custom JCE provider module with all possible modular condition.
  53  *          The test includes different combination of JCE client/provider
  54  *          modules interaction with or without service description.
  55  *          The different module types used here are,
  56  *          EXPLICIT - Modules have module descriptor(module-info.java)
  57  *          defining the module.
  58  *          AUTO - Are regular jar files but provided in MODULE_PATH
  59  *          instead of CLASS_PATH.
  60  *          UNNAMED - Are regular jar but provided through CLASS_PATH.
  61  *          This test uses a boolean argument indicating to use signed jar
  62  *          for the third party JCE provider.
  63  * @run main/othervm -Duser.language=en -Duser.region=US JCEProviderModularTest
  64  *      false
  65  * @run main/othervm -Duser.language=en -Duser.region=US JCEProviderModularTest
  66  *      true
  67  */
  68 public class JCEProviderModularTest extends JigsawSecurityUtils {
  69 
  70     private static final String TEST_SRC = System.getProperty("test.src");
  71     private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
  72     private static final String DESCRIPTOR = "metaservice";
  73     private static final String MODULAR = "modular";
  74     private static final String AUTO = "autodepend";
  75     private static final String JAR_EXTN = ".jar";
  76 
  77     private static final String SERVICE_MODULE_NAME = "jceprovidermodule";
  78     private static final Path SERVICE_SRC_DIR
  79             = SRC_DIR.resolve(SERVICE_MODULE_NAME);
  80     private static final String SERVICE_PKG = "provider";
  81     private static final String SERVICE_JAR_NAME = SERVICE_PKG + JAR_EXTN;
  82     private static final String SERVICE_DESCRIPTOR_JAR_NAME
  83             = SERVICE_PKG + DESCRIPTOR + JAR_EXTN;
  84     private static final String MODULAR_SERVICE_JAR_NAME
  85             = MODULAR + SERVICE_PKG + JAR_EXTN;
  86     private static final String MODULE_SERVICE_DESCRIPTOR_JAR_NAME
  87             = MODULAR + SERVICE_PKG + DESCRIPTOR + JAR_EXTN;
  88 
  89     private static final String CLIENT_MODULE_NAME = "jceclientmodule";
  90     private static final Path CLIENT_SRC_DIR
  91             = SRC_DIR.resolve(CLIENT_MODULE_NAME);
  92     private static final String CLIENT_PKG = "client";
  93     private static final String CLIENT_JAR_NAME = CLIENT_PKG + JAR_EXTN;
  94     private static final String MODULAR_CLIENT_AUTO_DEPEND_JAR_NAME
  95             = MODULAR + CLIENT_PKG + AUTO + JAR_EXTN;
  96     private static final String MODULAR_CLIENT_JAR_NAME
  97             = MODULAR + CLIENT_PKG + JAR_EXTN;
  98 
  99     private static final Path BUILD_DIR = Paths.get(".").resolve("build");
 100     private static final Path COMPILE_DIR = BUILD_DIR.resolve("bin");
 101     private static final Path SERVICE_BUILD_DIR
 102             = COMPILE_DIR.resolve(SERVICE_PKG);
 103     private static final Path SERVICE_META_BUILD_DIR
 104             = COMPILE_DIR.resolve(SERVICE_PKG + DESCRIPTOR);
 105     private static final Path CLIENT_BUILD_DIR
 106             = COMPILE_DIR.resolve(CLIENT_PKG);
 107 
 108     private static final String EXPLICIT_MODULE_NAME = "jarmodule";
 109     private static final Path EXPLICIT_MODULE_BASE_PATH
 110             = BUILD_DIR.resolve(EXPLICIT_MODULE_NAME);
 111 
 112     private static final Path ARTIFACTS_DIR = BUILD_DIR.resolve("artifacts");
 113     private static final Path SERVICE_ARTIFACTS_DIR
 114             = ARTIFACTS_DIR.resolve(SERVICE_PKG);
 115     private static final Path REGULAR_SERVICE_JAR
 116             = SERVICE_ARTIFACTS_DIR.resolve(SERVICE_JAR_NAME);
 117     private static final Path REGULAR_SERVICE_WITH_DESCRIPTOR_JAR
 118             = SERVICE_ARTIFACTS_DIR.resolve(SERVICE_DESCRIPTOR_JAR_NAME);
 119     private static final Path MODULAR_SERVICE_JAR
 120             = SERVICE_ARTIFACTS_DIR.resolve(MODULAR_SERVICE_JAR_NAME);
 121     private static final Path MODULAR_SERVICE_WITH_DESCRIPTOR_JAR
 122             = SERVICE_ARTIFACTS_DIR.resolve(MODULE_SERVICE_DESCRIPTOR_JAR_NAME);
 123 
 124     private static final Path CLIENT_ARTIFACTS_DIR
 125             = ARTIFACTS_DIR.resolve(CLIENT_PKG);
 126     private static final Path REGULAR_CLIENT_JAR
 127             = CLIENT_ARTIFACTS_DIR.resolve(CLIENT_JAR_NAME);
 128     private static final Path MODULAR_CLIENT_JAR
 129             = CLIENT_ARTIFACTS_DIR.resolve(MODULAR_CLIENT_JAR_NAME);
 130     private static final Path MODULAR_CLIENT_AUTO_DEPEND_JAR
 131             = CLIENT_ARTIFACTS_DIR.resolve(MODULAR_CLIENT_AUTO_DEPEND_JAR_NAME);
 132 
 133     private static final Path KEYSTORE_DIR = BUILD_DIR.resolve("store");
 134     private static final Path KEYSTORE_PATH
 135             = KEYSTORE_DIR.resolve("test.keystore");
 136     private static final String STORE_PASSWORD = "password";
 137     private static final String ALIAS = "test";
 138 
 139     private static final String MAIN_CLASS = CLIENT_PKG + ".TestJCEClient";
 140     private static final String LOGIN_SERVICE_INTERFACE
 141             = "java.security.Provider";
 142     private static final String SERVICE_IMPL = SERVICE_PKG + ".TestJCEProvider";
 143     private static final List<String> REQUIRED_MODULES
 144             = Arrays.asList("java.base");
 145     private static final Path META_DESCRIPTOR = Paths.get("META-INF")
 146             .resolve("services").resolve(LOGIN_SERVICE_INTERFACE);
 147     private static final Path META_SERVICE_DESCRIPTOR
 148             = SERVICE_META_BUILD_DIR.resolve(META_DESCRIPTOR);
 149 
 150     private static final boolean WITH_SERVICE_DESCRIPTOR = true;
 151     private static final boolean WITHOUT_SERVICE_DESCRIPTOR = false;
 152     private static final boolean PASS = true;
 153     private static final String PROVIDER_CLASS_NOT_FOUND_MSG
 154             = "NoClassDefFoundError: provider/TestJCEProvider";
 155     private static final String PROVIDER_NOT_FOUND_BY_CLIENT_MSG
 156             = "Unable to find Test JCE Provider";
 157     private static final String CAN_NOT_ACCESS_MSG = "cannot access class";
 158     private static final String NO_FAILURE = null;
 159     private static final String USE_SERVICE_LOADER = "USE_SERVICE_LOADER";
 160     private static final String USE_CLASS_LOADER = "USE_CLASS_LOADER";
 161     private static final String USE_SECURITY_PROP = "USE_SECURITY_PROP";
 162     private static final List<String> MECHANISMS = Arrays.asList(
 163             USE_SERVICE_LOADER, USE_CLASS_LOADER, USE_SECURITY_PROP);
 164     private static final Path SECURITY_PROP_EXTN
 165             = Paths.get("./java.security.extn");
 166 
 167     public static void main(String[] args) {
 168 
 169         boolean success = true;
 170         boolean useSignedJar = (args != null && args.length > 0)
 171                 ? Boolean.valueOf(args[0]) : false;
 172 
 173         boolean ready = createArtifacts(useSignedJar);
 174         if (!ready) {
 175             throw new RuntimeException("Unable to prepare to run this test.");
 176         }
 177 
 178         for (String mechanism : MECHANISMS) {
 179             boolean useClassLoader = USE_CLASS_LOADER.equals(mechanism);
 180             //PARAMETER ORDERS -
 181             //client Module Type, Service Module Type,
 182             //Service META Descriptor Required, Expected Result
 183             success &= runTest(MODULE_TYPE.EXPLICIT, MODULE_TYPE.EXPLICIT,
 184                     WITH_SERVICE_DESCRIPTOR, PASS, NO_FAILURE,
 185                     useSignedJar, mechanism);
 186             success &= runTest(MODULE_TYPE.EXPLICIT, MODULE_TYPE.EXPLICIT,
 187                     WITHOUT_SERVICE_DESCRIPTOR, PASS, NO_FAILURE,
 188                     useSignedJar, mechanism);
 189             success &= runTest(MODULE_TYPE.EXPLICIT, MODULE_TYPE.AUTO,
 190                     WITH_SERVICE_DESCRIPTOR, PASS,
 191                     ((useClassLoader) ? CAN_NOT_ACCESS_MSG : NO_FAILURE),
 192                     useSignedJar, mechanism);
 193             success &= runTest(MODULE_TYPE.EXPLICIT, MODULE_TYPE.AUTO,
 194                     WITHOUT_SERVICE_DESCRIPTOR, PASS,
 195                     PROVIDER_CLASS_NOT_FOUND_MSG, useSignedJar, mechanism);
 196             success &= runTest(MODULE_TYPE.EXPLICIT, MODULE_TYPE.UNNAMED,
 197                     WITH_SERVICE_DESCRIPTOR, PASS,
 198                     ((useClassLoader) ? CAN_NOT_ACCESS_MSG : NO_FAILURE),
 199                     useSignedJar, mechanism);
 200             success &= runTest(MODULE_TYPE.EXPLICIT, MODULE_TYPE.UNNAMED,
 201                     WITHOUT_SERVICE_DESCRIPTOR, PASS, ((useClassLoader)
 202                             ? CAN_NOT_ACCESS_MSG
 203                             : PROVIDER_NOT_FOUND_BY_CLIENT_MSG),
 204                     useSignedJar, mechanism);
 205 
 206             success &= runTest(MODULE_TYPE.AUTO, MODULE_TYPE.EXPLICIT,
 207                     WITH_SERVICE_DESCRIPTOR, PASS, NO_FAILURE,
 208                     useSignedJar, mechanism);
 209             success &= runTest(MODULE_TYPE.AUTO, MODULE_TYPE.EXPLICIT,
 210                     WITHOUT_SERVICE_DESCRIPTOR, PASS, NO_FAILURE,
 211                     useSignedJar, mechanism);
 212             success &= runTest(MODULE_TYPE.AUTO, MODULE_TYPE.AUTO,
 213                     WITH_SERVICE_DESCRIPTOR, PASS, NO_FAILURE,
 214                     useSignedJar, mechanism);
 215             success &= runTest(MODULE_TYPE.AUTO, MODULE_TYPE.AUTO,
 216                     WITHOUT_SERVICE_DESCRIPTOR, PASS,
 217                     PROVIDER_CLASS_NOT_FOUND_MSG, useSignedJar, mechanism);
 218             success &= runTest(MODULE_TYPE.AUTO, MODULE_TYPE.UNNAMED,
 219                     WITH_SERVICE_DESCRIPTOR, PASS, NO_FAILURE,
 220                     useSignedJar, mechanism);
 221             success &= runTest(MODULE_TYPE.AUTO, MODULE_TYPE.UNNAMED,
 222                     WITHOUT_SERVICE_DESCRIPTOR, PASS,
 223                     ((useClassLoader) ? NO_FAILURE
 224                             : PROVIDER_NOT_FOUND_BY_CLIENT_MSG),
 225                     useSignedJar, mechanism);
 226 
 227             success &= runTest(MODULE_TYPE.UNNAMED, MODULE_TYPE.EXPLICIT,
 228                     WITH_SERVICE_DESCRIPTOR, PASS, NO_FAILURE,
 229                     useSignedJar, mechanism);
 230             success &= runTest(MODULE_TYPE.UNNAMED, MODULE_TYPE.EXPLICIT,
 231                     WITHOUT_SERVICE_DESCRIPTOR, PASS, NO_FAILURE,
 232                     useSignedJar, mechanism);
 233             success &= runTest(MODULE_TYPE.UNNAMED, MODULE_TYPE.AUTO,
 234                     WITH_SERVICE_DESCRIPTOR, PASS, NO_FAILURE,
 235                     useSignedJar, mechanism);
 236             success &= runTest(MODULE_TYPE.UNNAMED, MODULE_TYPE.AUTO,
 237                     WITHOUT_SERVICE_DESCRIPTOR, PASS,
 238                     PROVIDER_CLASS_NOT_FOUND_MSG, useSignedJar, mechanism);
 239             success &= runTest(MODULE_TYPE.UNNAMED, MODULE_TYPE.UNNAMED,
 240                     WITH_SERVICE_DESCRIPTOR, PASS, NO_FAILURE,
 241                     useSignedJar, mechanism);
 242             success &= runTest(MODULE_TYPE.UNNAMED, MODULE_TYPE.UNNAMED,
 243                     WITHOUT_SERVICE_DESCRIPTOR, PASS,
 244                     ((useClassLoader) ? NO_FAILURE
 245                             : PROVIDER_NOT_FOUND_BY_CLIENT_MSG),
 246                     useSignedJar, mechanism);
 247 
 248             if (!success) {
 249                 throw new RuntimeException("At least one test failed.");
 250             }
 251         }
 252     }
 253 
 254     public static boolean runTest(MODULE_TYPE clientModuleType,
 255             MODULE_TYPE serviceModuletype, boolean addMetaInfDescriptor,
 256             boolean expectedResult, String expectedFailure,
 257             boolean useSignedJar, String mechanism) {
 258 
 259         boolean result = true;
 260         try {
 261 
 262             String testName = (clientModuleType + "_")
 263                     + (serviceModuletype + "_")
 264                     + ((addMetaInfDescriptor) ? "DESCRIPTOR" : "NO_DESCRIPTOR");
 265 
 266             System.out.println(String.format(
 267                     "Starting Test case: '%s'", testName));
 268             Path clientJarPath = findJarPath(false, clientModuleType, false,
 269                     (serviceModuletype == MODULE_TYPE.EXPLICIT));
 270             Path serviceJarPath = findJarPath(
 271                     true, serviceModuletype, addMetaInfDescriptor, false);
 272             System.out.println(String.format(
 273                     "Client jar path : %s ", clientJarPath));
 274             System.out.println(String.format(
 275                     "Service jar path : %s ", serviceJarPath));
 276             //For automated/explicit module type copy the corresponding
 277             //jars to module base folder, which will be considered as
 278             //module base path during execution.
 279             if (!(clientModuleType == MODULE_TYPE.UNNAMED
 280                     && serviceModuletype == MODULE_TYPE.UNNAMED)) {
 281                 copyJarsToModuleBase(clientModuleType, clientJarPath,
 282                         serviceModuletype, serviceJarPath);
 283             }
 284 
 285             System.out.println("Started executing java client with required"
 286                     + " custom JCE provider in class/module path.");
 287             String moduleName
 288                     = getClientModuleName(clientModuleType, clientJarPath);
 289             Path moduleBasePath = (clientModuleType != MODULE_TYPE.UNNAMED
 290                     || serviceModuletype != MODULE_TYPE.UNNAMED)
 291                             ? EXPLICIT_MODULE_BASE_PATH : null;
 292             StringBuilder classPath
 293                     = getClassPath(clientModuleType, clientJarPath,
 294                             serviceModuletype, serviceJarPath);
 295 
 296             final Map<String, String> VM_ARGS = new LinkedHashMap<>();
 297             VM_ARGS.put("-Duser.language=", "en");
 298             VM_ARGS.put("-Duser.region=", "US");
 299             if (USE_SECURITY_PROP.equals(mechanism)) {
 300                 VM_ARGS.put("-Djava.security.properties=",
 301                         SECURITY_PROP_EXTN.toFile().getCanonicalPath());
 302             }
 303             OutputAnalyzer output = ProcessTools.executeTestJava(
 304                     getJavaCommand(moduleBasePath, classPath, moduleName,
 305                             MAIN_CLASS, VM_ARGS, mechanism))
 306                     .outputTo(System.out)
 307                     .errorTo(System.out);
 308 
 309             if (output.getExitValue() != 0) {
 310                 if (expectedFailure != null
 311                         && output.getOutput().contains(expectedFailure)) {
 312                     System.out.println("PASS: Test is expected to fail here.");
 313                 } else {
 314                     System.out.println(String.format(
 315                             "Unexpected failure occured during executing '%s'"
 316                             + " with exit code '%s'.",
 317                             MAIN_CLASS, output.getExitValue()));
 318                     result = false;
 319                 }
 320             }
 321         } catch (Exception e) {
 322             e.printStackTrace(System.out);
 323             result = false;
 324         } finally {
 325             //clean module path so that the modulepath can only hold
 326             //the required jars for next run.
 327             cleanModuleBasePath();
 328         }
 329 
 330         return (expectedResult == result);
 331     }
 332 
 333     //Decide the pre-generated client/service jar path for a given module type.
 334     private static Path findJarPath(boolean service, MODULE_TYPE moduleType,
 335             boolean addMetaInfDescriptor, boolean dependsOnServiceModule) {
 336         if (service) {
 337             if (moduleType == MODULE_TYPE.EXPLICIT) {
 338                 if (addMetaInfDescriptor) {
 339                     return MODULAR_SERVICE_WITH_DESCRIPTOR_JAR;
 340                 } else {
 341                     return MODULAR_SERVICE_JAR;
 342                 }
 343             } else {
 344                 if (addMetaInfDescriptor) {
 345                     return REGULAR_SERVICE_WITH_DESCRIPTOR_JAR;
 346                 } else {
 347                     return REGULAR_SERVICE_JAR;
 348                 }
 349             }
 350         } else {
 351             if (moduleType == MODULE_TYPE.EXPLICIT) {
 352                 if (dependsOnServiceModule) {
 353                     return MODULAR_CLIENT_JAR;
 354                 } else {
 355                     return MODULAR_CLIENT_AUTO_DEPEND_JAR;
 356                 }
 357             } else {
 358                 return REGULAR_CLIENT_JAR;
 359             }
 360         }
 361     }
 362 
 363     //Copy pre-generated jar files to the base module path based on module type.
 364     private static void copyJarsToModuleBase(MODULE_TYPE clientModuleType,
 365             Path modularClientJarPath, MODULE_TYPE serviceModuletype,
 366             Path modularServiceJarPath) throws IOException {
 367 
 368         if (EXPLICIT_MODULE_BASE_PATH != null) {
 369             Files.createDirectories(EXPLICIT_MODULE_BASE_PATH);
 370         }
 371         if (clientModuleType != MODULE_TYPE.UNNAMED) {
 372             Path clientArtifactName = EXPLICIT_MODULE_BASE_PATH.resolve(
 373                     modularClientJarPath.getFileName());
 374             System.out.println(String.format("Copy client jar path: '%s'"
 375                     + " to module base path: %s", modularClientJarPath,
 376                     clientArtifactName));
 377             Files.copy(modularClientJarPath, clientArtifactName);
 378         }
 379         if (serviceModuletype != MODULE_TYPE.UNNAMED) {
 380             Path serviceArtifactName = EXPLICIT_MODULE_BASE_PATH.resolve(
 381                     modularServiceJarPath.getFileName());
 382             System.out.println(String.format("Copy service jar path: '%s'"
 383                     + " to module base path: %s", modularServiceJarPath,
 384                     serviceArtifactName));
 385             Files.copy(modularServiceJarPath, serviceArtifactName);
 386         }
 387     }
 388 
 389     //Pre-compile and generate the artifacts required to run this test.
 390     private static boolean createArtifacts(boolean useSignedJar) {
 391 
 392         boolean done = true;
 393         try {
 394             Files.write(SECURITY_PROP_EXTN,
 395                     "security.provider.13=TEST".getBytes());
 396             //If signed jar required then prepare the keystore for first time.
 397             if (useSignedJar) {
 398                 done &= generateKeyStore(KEYSTORE_PATH.toString(),
 399                         STORE_PASSWORD, ALIAS);
 400             }
 401             done &= CompilerUtils.compile(SERVICE_SRC_DIR, SERVICE_BUILD_DIR);
 402             done &= CompilerUtils.compile(SERVICE_SRC_DIR,
 403                     SERVICE_META_BUILD_DIR);
 404             done &= createMetaInfServiceDescriptor(META_SERVICE_DESCRIPTOR,
 405                     SERVICE_IMPL);
 406             //Generate regular/modular jars with(out) META-INF
 407             //service descriptor
 408             generateJar(true, MODULE_TYPE.EXPLICIT, MODULAR_SERVICE_JAR,
 409                     SERVICE_BUILD_DIR, false, useSignedJar);
 410             generateJar(true, MODULE_TYPE.EXPLICIT,
 411                     MODULAR_SERVICE_WITH_DESCRIPTOR_JAR,
 412                     SERVICE_META_BUILD_DIR, false, useSignedJar);
 413             generateJar(true, MODULE_TYPE.UNNAMED, REGULAR_SERVICE_JAR,
 414                     SERVICE_BUILD_DIR, false, useSignedJar);
 415             generateJar(true, MODULE_TYPE.UNNAMED,
 416                     REGULAR_SERVICE_WITH_DESCRIPTOR_JAR,
 417                     SERVICE_META_BUILD_DIR, false, useSignedJar);
 418             //Generate regular/modular(depends on explicit/auto service)
 419             //jars for client
 420             done &= CompilerUtils.compile(CLIENT_SRC_DIR, CLIENT_BUILD_DIR,
 421                     "-cp", REGULAR_SERVICE_JAR.toRealPath().toString());
 422             generateJar(false, MODULE_TYPE.EXPLICIT, MODULAR_CLIENT_JAR,
 423                     CLIENT_BUILD_DIR, true, useSignedJar);
 424             generateJar(false, MODULE_TYPE.EXPLICIT,
 425                     MODULAR_CLIENT_AUTO_DEPEND_JAR, CLIENT_BUILD_DIR,
 426                     false, useSignedJar);
 427             generateJar(false, MODULE_TYPE.UNNAMED,
 428                     REGULAR_CLIENT_JAR, CLIENT_BUILD_DIR, false, useSignedJar);
 429 
 430             System.out.println(String.format(
 431                     "Artifacts generated successfully? '%s'", done));
 432         } catch (IOException e) {
 433             e.printStackTrace(System.out);
 434             done = false;
 435         }
 436         return done;
 437     }
 438 
 439     //Generate modular/regular jar based on module type.
 440     private static void generateJar(boolean service, MODULE_TYPE moduleType,
 441             Path jarFile, Path compilePath, boolean depends,
 442             boolean useSignedJar) throws IOException {
 443 
 444         ModuleDescriptor moduleDescriptor = null;
 445         if (service) {
 446             moduleDescriptor = generateModuleDescriptor(service, moduleType,
 447                     SERVICE_MODULE_NAME, SERVICE_PKG,
 448                     LOGIN_SERVICE_INTERFACE, SERVICE_IMPL, null,
 449                     REQUIRED_MODULES, depends);
 450         } else {
 451             moduleDescriptor = generateModuleDescriptor(service,
 452                     moduleType, CLIENT_MODULE_NAME, CLIENT_PKG,
 453                     LOGIN_SERVICE_INTERFACE, null, SERVICE_MODULE_NAME,
 454                     REQUIRED_MODULES, depends);
 455         }
 456         System.out.println(String.format(
 457                 "Creating jar file '%s'", jarFile));
 458         JarUtils.createJarFile(jarFile, compilePath);
 459         if (moduleDescriptor != null) {
 460             Path dir = Files.createTempDirectory("tmp");
 461             Path mi = dir.resolve("module-info.class");
 462             try (OutputStream out = Files.newOutputStream(mi)) {
 463                 ModuleInfoWriter.write(moduleDescriptor, out);
 464             }
 465             System.out.println(String.format(
 466                     "Adding 'module-info.class' to jar file '%s'", jarFile));
 467             JarUtils.updateJarFile(jarFile, dir);
 468         }
 469         //If the jar holds provider implementation then sign it.
 470         if (service && useSignedJar) {
 471             signJar(jarFile, KEYSTORE_PATH.toRealPath().toString(),
 472                     STORE_PASSWORD, ALIAS);
 473         }
 474     }
 475 
 476     //Construct class path argument value.
 477     private static StringBuilder getClassPath(MODULE_TYPE clientModuleType,
 478             Path clientJarPath, MODULE_TYPE serviceModuletype,
 479             Path serviceJarPath) throws IOException {
 480 
 481         StringBuilder classPath = new StringBuilder();
 482         classPath.append((clientModuleType == MODULE_TYPE.UNNAMED)
 483                 ? (clientJarPath.toRealPath().toString()
 484                 + File.pathSeparatorChar) : "");
 485         classPath.append((serviceModuletype == MODULE_TYPE.UNNAMED)
 486                 ? serviceJarPath.toRealPath().toString() : "");
 487         return classPath;
 488     }
 489 
 490     //Construct client modulename to run the client. It is fixed for explicit
 491     //module type while it is same as jar file name for automated module type.
 492     private static String getClientModuleName(MODULE_TYPE clientModuleType,
 493             Path clientJarPath) {
 494 
 495         String jarFileName = clientJarPath.toFile().getName();
 496         return (clientModuleType == MODULE_TYPE.EXPLICIT)
 497                 ? CLIENT_MODULE_NAME
 498                 : ((clientModuleType == MODULE_TYPE.AUTO)
 499                         ? jarFileName.substring(
 500                                 0, jarFileName.indexOf(JAR_EXTN)) : "");
 501     }
 502 
 503     //Delete all the files inside the base module path.
 504     private static void cleanModuleBasePath() {
 505 
 506         Arrays.asList(EXPLICIT_MODULE_BASE_PATH.toFile().listFiles())
 507                 .forEach(f -> {
 508                     System.out.println("delete " + f);
 509                     f.delete();
 510                 });
 511         System.out.println("------------------------------------------------");
 512     }
 513 
 514     //Generate a keystore with random keys.
 515     public static boolean generateKeyStore(String keyStoreFile,
 516             String password, String alias) throws IOException {
 517         boolean created = true;
 518         Path parent = KEYSTORE_PATH.getParent();
 519         if (parent != null) {
 520             Files.createDirectories(parent);
 521         }
 522         try (FileOutputStream keyStoreOut
 523                 = new FileOutputStream(keyStoreFile)) {
 524 
 525             KeyStore keyStore = KeyStore.getInstance("JKS");
 526             keyStore.load(null, null);
 527 
 528             CertAndKeyGen keyGen
 529                     = new CertAndKeyGen("RSA", "SHA1WithRSA", null);
 530             keyGen.generate(2048);
 531             //Generate self signed certificate
 532             Certificate[] chain = new X509Certificate[1];
 533             chain[0] = keyGen.getSelfCertificate(
 534                     new X500Name("CN=ROOT"), (long) 365 * 24 * 3600);
 535             keyStore.setKeyEntry(alias, keyGen.getPrivateKey(),
 536                     password.toCharArray(), chain);
 537 
 538             keyStore.store(keyStoreOut, password.toCharArray());
 539         } catch (Exception e) {
 540             created = false;
 541             e.printStackTrace(System.out);
 542         }
 543         return created;
 544     }
 545 
 546     //Sign a jar file by provided keystore file.
 547     public static void signJar(Path jarFile, String keyStore,
 548             String password, String alias) {
 549         try {
 550             JDKToolLauncher jarsigner = JDKToolLauncher.create("jarsigner")
 551                     .addToolArg("-keystore")
 552                     .addToolArg(keyStore)
 553                     .addToolArg("-storepass")
 554                     .addToolArg(password)
 555                     .addToolArg("-keypass")
 556                     .addToolArg(password)
 557                     .addToolArg(jarFile.toFile().getCanonicalPath())
 558                     .addToolArg(alias);
 559             ProcessBuilder processBuilder
 560                     = new ProcessBuilder(jarsigner.getCommand());
 561             OutputAnalyzer output = ProcessTools.executeProcess(processBuilder);
 562             System.out.println(
 563                     "_________________BEGIN JAR SIGN OUTPUT__________________");
 564             System.out.println(output.getOutput());
 565             System.out.println(
 566                     "_______________________END OUTPUT_______________________");
 567             output.shouldHaveExitValue(0);
 568         } catch (Exception e) {
 569             throw new RuntimeException(String.format(
 570                     "Unable to sign Jar file '%s'", jarFile));
 571         }
 572     }
 573 
 574 }