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