1 /*
   2  * Copyright (c) 2015, 2017, 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.util.ArrayList;
  28 import java.util.LinkedHashMap;
  29 import java.util.List;
  30 import java.util.Map;
  31 import java.util.Arrays;
  32 import java.io.IOException;
  33 import java.lang.module.ModuleDescriptor;
  34 import jdk.testlibrary.ProcessTools;
  35 import jdk.testlibrary.OutputAnalyzer;
  36 import jdk.test.lib.compiler.CompilerUtils;
  37 import org.testng.annotations.BeforeTest;
  38 
  39 /**
  40  * @test
  41  * @bug 8130360
  42  * @library /lib/testlibrary
  43  * @library /java/security/modules
  44  * @library /test/lib
  45  * @modules java.base/jdk.internal.module
  46  * @build jdk.test.lib.compiler.CompilerUtils JarUtils
  47  * @summary Test custom security provider module with all possible modular
  48  *          condition. The test includes different combination of security
  49  *          client/provider modules interaction with or without service
  50  *          description.
  51  * @run testng SecurityProviderModularTest
  52  */
  53 public class SecurityProviderModularTest extends ModularTest {
  54 
  55     private static final Path S_SRC = SRC.resolve("TestSecurityProvider.java");
  56     private static final String S_PKG = "provider";
  57     private static final String S_JAR_NAME = S_PKG + JAR_EXTN;
  58     private static final String S_WITH_DESCR_JAR_NAME = S_PKG + DESCRIPTOR
  59             + JAR_EXTN;
  60     private static final String MS_JAR_NAME = MODULAR + S_PKG + JAR_EXTN;
  61     private static final String MS_WITH_DESCR_JAR_NAME = MODULAR + S_PKG
  62             + DESCRIPTOR + JAR_EXTN;
  63 
  64     private static final Path C_SRC = SRC.resolve(
  65             "TestSecurityProviderClient.java");
  66     private static final String C_PKG = "client";
  67     private static final String C_JAR_NAME = C_PKG + JAR_EXTN;
  68     private static final String MCN_JAR_NAME = MODULAR + C_PKG + "N" + JAR_EXTN;
  69     private static final String MC_JAR_NAME = MODULAR + C_PKG + JAR_EXTN;
  70 
  71     private static final Path BUILD_DIR = Paths.get(".").resolve("build");
  72     private static final Path COMPILE_DIR = BUILD_DIR.resolve("bin");
  73     private static final Path S_BUILD_DIR = COMPILE_DIR.resolve(S_PKG);
  74     private static final Path S_WITH_META_DESCR_BUILD_DIR = COMPILE_DIR.resolve(
  75             S_PKG + DESCRIPTOR);
  76     private static final Path C_BLD_DIR = COMPILE_DIR.resolve(C_PKG);
  77     private static final Path M_BASE_PATH = BUILD_DIR.resolve("mbase");
  78     private static final Path ARTIFACTS_DIR = BUILD_DIR.resolve("artifacts");
  79 
  80     private static final Path S_ARTIFACTS_DIR = ARTIFACTS_DIR.resolve(S_PKG);
  81     private static final Path S_JAR = S_ARTIFACTS_DIR.resolve(S_JAR_NAME);
  82     private static final Path S_WITH_DESCRIPTOR_JAR = S_ARTIFACTS_DIR.resolve(
  83             S_WITH_DESCR_JAR_NAME);
  84     private static final Path MS_JAR = S_ARTIFACTS_DIR.resolve(
  85             MS_JAR_NAME);
  86     private static final Path MS_WITH_DESCR_JAR = S_ARTIFACTS_DIR.resolve(
  87             MS_WITH_DESCR_JAR_NAME);
  88 
  89     private static final Path C_ARTIFACTS_DIR = ARTIFACTS_DIR.resolve(C_PKG);
  90     private static final Path C_JAR = C_ARTIFACTS_DIR.resolve(C_JAR_NAME);
  91     private static final Path MC_JAR = C_ARTIFACTS_DIR.resolve(MC_JAR_NAME);
  92     private static final Path MCN_JAR = C_ARTIFACTS_DIR.resolve(MCN_JAR_NAME);
  93 
  94     private static final String MAIN = C_PKG + ".TestSecurityProviderClient";
  95     private static final String S_INTERFACE = "java.security.Provider";
  96     private static final String S_IMPL = S_PKG + ".TestSecurityProvider";
  97     private static final List<String> M_REQUIRED = Arrays.asList("java.base");
  98     private static final Path META_DESCR_PATH = Paths.get("META-INF")
  99             .resolve("services").resolve(S_INTERFACE);
 100     private static final Path S_META_DESCR_FPATH = S_WITH_META_DESCR_BUILD_DIR
 101             .resolve(META_DESCR_PATH);
 102 
 103     private static final boolean WITH_S_DESCR = true;
 104     private static final boolean WITHOUT_S_DESCR = false;
 105     private static final String PROVIDER_NOT_FOUND_MSG = "Unable to find Test"
 106             + " Security Provider";
 107     private static final String CAN_NOT_ACCESS_MSG = "cannot access class";
 108     private static final String NO_FAILURE = null;
 109     private static final String SERVICE_LOADER = "SERVICE_LOADER";
 110     private static final String CLASS_LOADER = "CLASS_LOADER";
 111     private static final String SECURITY_PROP = "SECURITY_PROP";
 112     private static final List<String> MECHANISMS = Arrays.asList(SERVICE_LOADER,
 113             CLASS_LOADER, SECURITY_PROP);
 114     private static final Path SECURE_PROP_EXTN = Paths.get("./java.secure.ext");
 115 
 116     /**
 117      * Generates Test specific input parameters.
 118      */
 119     @Override
 120     public Object[][] getTestInput() {
 121 
 122         List<List<Object>> params = new ArrayList<>();
 123         MECHANISMS.stream().forEach((mechanism) -> {
 124             boolean useCLoader = CLASS_LOADER.equals(mechanism);
 125             boolean useSLoader = SERVICE_LOADER.equals(mechanism);
 126             String[] args = new String[]{mechanism};
 127             // PARAMETER ORDERS -
 128             // Client Module Type, Service Module Type,
 129             // If Service META Descriptor Required,
 130             // Expected Failure message, mechanism used to find the provider
 131             params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.EXPLICIT,
 132                     WITH_S_DESCR, NO_FAILURE, args));
 133             params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.EXPLICIT,
 134                     WITHOUT_S_DESCR, NO_FAILURE, args));
 135             params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.AUTO,
 136                     WITH_S_DESCR, ((useCLoader) ? CAN_NOT_ACCESS_MSG
 137                             : NO_FAILURE), args));
 138             params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.AUTO,
 139                     WITHOUT_S_DESCR, ((useCLoader) ? CAN_NOT_ACCESS_MSG
 140                             : PROVIDER_NOT_FOUND_MSG), args));
 141             params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.UNNAMED,
 142                     WITH_S_DESCR, ((useCLoader) ? CAN_NOT_ACCESS_MSG
 143                             : NO_FAILURE), args));
 144             params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.UNNAMED,
 145                     WITHOUT_S_DESCR, ((useCLoader) ? CAN_NOT_ACCESS_MSG
 146                             : ((useSLoader) ? PROVIDER_NOT_FOUND_MSG
 147                                     : NO_FAILURE)), args));
 148 
 149             params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.EXPLICIT,
 150                     WITH_S_DESCR, NO_FAILURE, args));
 151             params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.EXPLICIT,
 152                     WITHOUT_S_DESCR, NO_FAILURE, args));
 153             params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.AUTO,
 154                     WITH_S_DESCR, NO_FAILURE, args));
 155             params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.AUTO,
 156                     WITHOUT_S_DESCR,
 157                     (useCLoader) ? NO_FAILURE : PROVIDER_NOT_FOUND_MSG, args));
 158             params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.UNNAMED,
 159                     WITH_S_DESCR, NO_FAILURE, args));
 160             params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.UNNAMED,
 161                     WITHOUT_S_DESCR, ((useSLoader) ? PROVIDER_NOT_FOUND_MSG
 162                             : NO_FAILURE), args));
 163 
 164             params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.EXPLICIT,
 165                     WITH_S_DESCR, NO_FAILURE, args));
 166             params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.EXPLICIT,
 167                     WITHOUT_S_DESCR, NO_FAILURE, args));
 168             params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.AUTO,
 169                     WITH_S_DESCR, NO_FAILURE, args));
 170             params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.AUTO,
 171                     WITHOUT_S_DESCR,
 172                     (useCLoader) ? NO_FAILURE : PROVIDER_NOT_FOUND_MSG, args));
 173             params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.UNNAMED,
 174                     WITH_S_DESCR, NO_FAILURE, args));
 175             params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.UNNAMED,
 176                     WITHOUT_S_DESCR, ((useSLoader) ? PROVIDER_NOT_FOUND_MSG
 177                             : NO_FAILURE), args));
 178         });
 179         return params.stream().map(p -> p.toArray()).toArray(Object[][]::new);
 180     }
 181 
 182     /**
 183      * Pre-compile and generate the artifacts required to run this test before
 184      * running each test cases.
 185      */
 186     @BeforeTest
 187     public void buildArtifacts() {
 188 
 189         boolean done = true;
 190         try {
 191 
 192             done &= CompilerUtils.compile(S_SRC, S_BUILD_DIR);
 193             done &= CompilerUtils.compile(S_SRC, S_WITH_META_DESCR_BUILD_DIR);
 194             done &= createMetaInfServiceDescriptor(S_META_DESCR_FPATH, S_IMPL);
 195             // Generate modular/regular jars with(out) META-INF
 196             // service descriptor
 197             generateJar(true, MODULE_TYPE.EXPLICIT, MS_JAR, S_BUILD_DIR, false);
 198             generateJar(true, MODULE_TYPE.EXPLICIT, MS_WITH_DESCR_JAR,
 199                     S_WITH_META_DESCR_BUILD_DIR, false);
 200             generateJar(true, MODULE_TYPE.UNNAMED, S_JAR, S_BUILD_DIR, false);
 201             generateJar(true, MODULE_TYPE.UNNAMED, S_WITH_DESCRIPTOR_JAR,
 202                     S_WITH_META_DESCR_BUILD_DIR, false);
 203             // Compile client source codes.
 204             done &= CompilerUtils.compile(C_SRC, C_BLD_DIR, "-cp",
 205                     S_JAR.toFile().getCanonicalPath());
 206             // Generate modular client jar with explicit dependency
 207             generateJar(false, MODULE_TYPE.EXPLICIT, MC_JAR, C_BLD_DIR, true);
 208             // Generate modular client jar without any dependency
 209             generateJar(false, MODULE_TYPE.EXPLICIT, MCN_JAR, C_BLD_DIR, false);
 210             // Generate regular client jar
 211             generateJar(false, MODULE_TYPE.UNNAMED, C_JAR, C_BLD_DIR, false);
 212             System.out.format("%nArtifacts generated successfully? %s", done);
 213             if (!done) {
 214                 throw new RuntimeException("Artifacts generation failed");
 215             }
 216         } catch (IOException e) {
 217             throw new RuntimeException(e);
 218         }
 219     }
 220 
 221     /**
 222      * Generate modular/regular jar based on module type for this test.
 223      */
 224     private void generateJar(boolean isService, MODULE_TYPE moduleType,
 225             Path jar, Path compilePath, boolean depends) throws IOException {
 226 
 227         ModuleDescriptor mDescriptor = null;
 228         if (isService) {
 229             mDescriptor = generateModuleDescriptor(isService, moduleType, S_PKG,
 230                     S_PKG, S_INTERFACE, S_IMPL, null, M_REQUIRED, depends);
 231         } else {
 232             mDescriptor = generateModuleDescriptor(isService, moduleType, C_PKG,
 233                     C_PKG, S_INTERFACE, null, S_PKG, M_REQUIRED, depends);
 234         }
 235         generateJar(mDescriptor, jar, compilePath);
 236     }
 237 
 238     /**
 239      * Holds Logic for the test. This method will get called with each test
 240      * parameter.
 241      */
 242     @Override
 243     public OutputAnalyzer executeTestClient(MODULE_TYPE cModuleType,
 244             Path cJarPath, MODULE_TYPE sModuletype, Path sJarPath,
 245             String... args) throws Exception {
 246 
 247         OutputAnalyzer output = null;
 248         try {
 249             // For automated/explicit module types, copy the corresponding
 250             // jars to module base folder, which will be considered as
 251             // module base path during execution.
 252             if (!(cModuleType == MODULE_TYPE.UNNAMED
 253                     && sModuletype == MODULE_TYPE.UNNAMED)) {
 254                 copyJarsToModuleBase(cModuleType, cJarPath, M_BASE_PATH);
 255                 copyJarsToModuleBase(sModuletype, sJarPath, M_BASE_PATH);
 256             }
 257 
 258             System.out.format("%nExecuting java client with required"
 259                     + " custom security provider in class/module path.");
 260             String mName = getModuleName(cModuleType, cJarPath, C_PKG);
 261             Path cmBasePath = (cModuleType != MODULE_TYPE.UNNAMED
 262                     || sModuletype != MODULE_TYPE.UNNAMED) ? M_BASE_PATH : null;
 263             String cPath = buildClassPath(cModuleType, cJarPath, sModuletype,
 264                     sJarPath);
 265 
 266             Map<String, String> vmArgs = getVMArgs(sModuletype,
 267                     getModuleName(sModuletype, sJarPath, S_PKG), args);
 268             output = ProcessTools.executeTestJava(
 269                     getJavaCommand(cmBasePath, cPath, mName, MAIN, vmArgs,
 270                             args)).outputTo(System.out).errorTo(System.out);
 271         } finally {
 272             // Clean module path to hold required jars for next run.
 273             cleanModuleBasePath(M_BASE_PATH);
 274         }
 275         return output;
 276     }
 277 
 278     /**
 279      * Decide the pre-generated client/service jar path for each test case
 280      * based on client/service module type.
 281      */
 282     @Override
 283     public Path findJarPath(boolean isService, MODULE_TYPE moduleType,
 284             boolean addMetaDesc, boolean dependsOnServiceModule) {
 285         if (isService) {
 286             if (moduleType == MODULE_TYPE.EXPLICIT) {
 287                 if (addMetaDesc) {
 288                     return MS_WITH_DESCR_JAR;
 289                 } else {
 290                     return MS_JAR;
 291                 }
 292             } else {
 293                 if (addMetaDesc) {
 294                     return S_WITH_DESCRIPTOR_JAR;
 295                 } else {
 296                     return S_JAR;
 297                 }
 298             }
 299         } else {
 300             // Choose corresponding client jar to use dependent module
 301             if (moduleType == MODULE_TYPE.EXPLICIT) {
 302                 if (dependsOnServiceModule) {
 303                     return MC_JAR;
 304                 } else {
 305                     return MCN_JAR;
 306                 }
 307             } else {
 308                 return C_JAR;
 309             }
 310         }
 311     }
 312 
 313     /**
 314      * VM argument required for the test.
 315      */
 316     private Map<String, String> getVMArgs(MODULE_TYPE sModuletype,
 317             String addModName, String... args) throws IOException {
 318         final Map<String, String> vmArgs = new LinkedHashMap<>();
 319         vmArgs.put("-Duser.language=", "en");
 320         vmArgs.put("-Duser.region=", "US");
 321         if (addModName != null && sModuletype == MODULE_TYPE.AUTO) {
 322             vmArgs.put("--add-modules=", addModName);
 323         }
 324         // If mechanism selected to find the provider through
 325         // Security.getProvider() then use providerName/ProviderClassName based
 326         // on modular/regular provider jar in security configuration file.
 327         if (args != null && args.length > 0 && SECURITY_PROP.equals(args[0])) {
 328             if (sModuletype == MODULE_TYPE.UNNAMED) {
 329                 Files.write(SECURE_PROP_EXTN, ("security.provider.10=" + S_IMPL)
 330                         .getBytes());
 331             } else {
 332                 Files.write(SECURE_PROP_EXTN, "security.provider.10=TEST"
 333                         .getBytes());
 334             }
 335             vmArgs.put("-Djava.security.properties=", SECURE_PROP_EXTN.toFile()
 336                     .getCanonicalPath());
 337         }
 338         return vmArgs;
 339     }
 340 
 341 }