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 /jdk/jigsaw/lib
  42  * @library /lib/testlibrary
  43  * @library /java/security/modules
  44  * @modules java.base/jdk.internal.module
  45  * @build CompilerUtils JarUtils
  46  * @summary Test custom security provider module with all possible modular
  47  *          condition. The test includes different combination of security
  48  *          client/provider modules interaction with or without service
  49  *          description.
  50  * @run testng SecurityProviderModularTest
  51  */
  52 public class SecurityProviderModularTest extends ModularTest {
  53 
  54     private static final Path S_SRC = SRC.resolve("TestSecurityProvider.java");
  55     private static final String S_PKG = "provider";
  56     private static final String S_JAR_NAME = S_PKG + JAR_EXTN;
  57     private static final String S_WITH_DESCR_JAR_NAME = S_PKG + DESCRIPTOR
  58             + JAR_EXTN;
  59     private static final String MS_JAR_NAME = MODULAR + S_PKG + JAR_EXTN;
  60     private static final String MS_WITH_DESCR_JAR_NAME = MODULAR + S_PKG
  61             + DESCRIPTOR + JAR_EXTN;
  62 
  63     private static final Path C_SRC = SRC.resolve(
  64             "TestSecurityProviderClient.java");
  65     private static final String C_PKG = "client";
  66     private static final String C_JAR_NAME = C_PKG + JAR_EXTN;
  67     private static final String MC_DEPENDS_ON_AUTO_SERVICE_JAR_NAME = MODULAR
  68             + C_PKG + AUTO + 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_BUILD_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 MC_DEPENDS_ON_AUTO_SERVICE_JAR = C_ARTIFACTS_DIR
  93             .resolve(MC_DEPENDS_ON_AUTO_SERVICE_JAR_NAME);
  94 
  95     private static final String MAIN = C_PKG + ".TestSecurityProviderClient";
  96     private static final String S_INTERFACE = "java.security.Provider";
  97     private static final String S_IMPL = S_PKG + ".TestSecurityProvider";
  98     private static final List<String> M_REQUIRED = Arrays.asList("java.base");
  99     private static final Path META_DESCR_PATH = Paths.get("META-INF")
 100             .resolve("services").resolve(S_INTERFACE);
 101     private static final Path S_META_DESCR_FPATH = S_WITH_META_DESCR_BUILD_DIR
 102             .resolve(META_DESCR_PATH);
 103 
 104     private static final boolean WITH_S_DESCR = true;
 105     private static final boolean WITHOUT_S_DESCR = false;
 106     private static final String CLASS_NOT_FOUND_MSG = "NoClassDefFoundError:"
 107             + " provider/TestSecurityProvider";
 108     private static final String PROVIDER_NOT_FOUND_MSG = "Unable to find Test"
 109             + " Security Provider";
 110     private static final String CAN_NOT_ACCESS_MSG = "cannot access class";
 111     private static final String NO_FAILURE = null;
 112     private static final String SERVICE_LOADER = "SERVICE_LOADER";
 113     private static final String CLASS_LOADER = "CLASS_LOADER";
 114     private static final String SECURITY_PROP = "SECURITY_PROP";
 115     private static final List<String> MECHANISMS = Arrays.asList(SERVICE_LOADER,
 116             CLASS_LOADER, SECURITY_PROP);
 117     private static final Path SECURE_PROP_EXTN = Paths.get("./java.secure.ext");
 118 
 119     /**
 120      * Generates Test specific input parameters.
 121      */
 122     @Override
 123     public Object[][] getTestInput() {
 124 
 125         List<List<Object>> params = new ArrayList<>();
 126         MECHANISMS.stream().forEach((mechanism) -> {
 127             boolean useCLoader = CLASS_LOADER.equals(mechanism);
 128             boolean useSLoader = SERVICE_LOADER.equals(mechanism);
 129             String[] args = new String[]{mechanism};
 130             //PARAMETER ORDERS -
 131             //client Module Type, Service Module Type,
 132             //Service META Descriptor Required, 
 133             //Expected Failure message, mech used to find the provider
 134             params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.EXPLICIT,
 135                     WITH_S_DESCR, NO_FAILURE, args));
 136             params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.EXPLICIT,
 137                     WITHOUT_S_DESCR, NO_FAILURE, args));
 138             params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.AUTO,
 139                     WITH_S_DESCR, ((useCLoader) ? CAN_NOT_ACCESS_MSG
 140                             : NO_FAILURE), args));
 141             params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.AUTO,
 142                     WITHOUT_S_DESCR, CLASS_NOT_FOUND_MSG, args));
 143             params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.UNNAMED,
 144                     WITH_S_DESCR, ((useCLoader) ? CAN_NOT_ACCESS_MSG
 145                             : NO_FAILURE), args));
 146             params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.UNNAMED,
 147                     WITHOUT_S_DESCR, ((useCLoader) ? CAN_NOT_ACCESS_MSG
 148                             : ((useSLoader) ? PROVIDER_NOT_FOUND_MSG
 149                                     : NO_FAILURE)), args));
 150 
 151             params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.EXPLICIT,
 152                     WITH_S_DESCR, NO_FAILURE, args));
 153             params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.EXPLICIT,
 154                     WITH_S_DESCR, NO_FAILURE, args));
 155             params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.AUTO,
 156                     WITH_S_DESCR, NO_FAILURE, args));
 157             params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.AUTO,
 158                     WITHOUT_S_DESCR, CLASS_NOT_FOUND_MSG, args));
 159             params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.UNNAMED,
 160                     WITH_S_DESCR, NO_FAILURE, args));
 161             params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.UNNAMED,
 162                     WITHOUT_S_DESCR, ((useSLoader) ? PROVIDER_NOT_FOUND_MSG
 163                             : NO_FAILURE), args));
 164 
 165             params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.EXPLICIT,
 166                     WITH_S_DESCR, NO_FAILURE, args));
 167             params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.EXPLICIT,
 168                     WITHOUT_S_DESCR, NO_FAILURE, args));
 169             params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.AUTO,
 170                     WITH_S_DESCR, NO_FAILURE, args));
 171             params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.AUTO,
 172                     WITHOUT_S_DESCR, CLASS_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 regular/modular 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             //Generate regular/modular(depends on explicit/auto Service)
 204             //jars for client
 205             done &= CompilerUtils.compile(C_SRC, C_BUILD_DIR, "-cp",
 206                     S_JAR.toFile().getCanonicalPath());
 207             generateJar(false, MODULE_TYPE.EXPLICIT, MC_JAR, C_BUILD_DIR, true);
 208             generateJar(false, MODULE_TYPE.EXPLICIT,
 209                     MC_DEPENDS_ON_AUTO_SERVICE_JAR, C_BUILD_DIR, false);
 210             generateJar(false, MODULE_TYPE.UNNAMED, C_JAR, C_BUILD_DIR, false);
 211             System.out.format("%nArtifacts generated successfully? %s", done);
 212             if (!done) {
 213                 throw new RuntimeException("Artifacts generation failed");
 214             }
 215         } catch (IOException e) {
 216             throw new RuntimeException(e);
 217         }
 218     }
 219 
 220     /**
 221      * Generate modular/regular jar based on module type for this test.
 222      */
 223     private void generateJar(boolean isService, MODULE_TYPE moduleType,
 224             Path jar, Path compilePath, boolean depends) throws IOException {
 225 
 226         ModuleDescriptor mDescriptor = null;
 227         if (isService) {
 228             mDescriptor = generateModuleDescriptor(isService, moduleType, S_PKG,
 229                     S_PKG, S_INTERFACE, S_IMPL, null, M_REQUIRED, depends);
 230         } else {
 231             mDescriptor = generateModuleDescriptor(isService, moduleType, C_PKG,
 232                     C_PKG, S_INTERFACE, null, S_PKG, M_REQUIRED, depends);
 233         }
 234         generateJar(mDescriptor, jar, compilePath);
 235     }
 236 
 237     /**
 238      * Holds Logic for the test. This method will get called with each test
 239      * parameter.
 240      */
 241     @Override
 242     public OutputAnalyzer executeTestClient(MODULE_TYPE cModuleType,
 243             Path cJarPath, MODULE_TYPE sModuletype, Path sJarPath,
 244             String... args) throws Exception {
 245 
 246         OutputAnalyzer output = null;
 247         try {
 248 
 249             //For automated/explicit module type 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> VM_ARGS = getVMArgs(sModuletype, args);
 267             output = ProcessTools.executeTestJava(
 268                     getJavaCommand(cmBasePath, cPath, mName, MAIN, VM_ARGS,
 269                             args)).outputTo(System.out).errorTo(System.out);
 270         } finally {
 271             //clean module path so that the modulepath can hold only
 272             //the required jars for next run.
 273             cleanModuleBasePath(M_BASE_PATH);
 274             System.out.println("--------------------------------------------");
 275         }
 276         return output;
 277     }
 278 
 279     /**
 280      * Decide the pre-generated client/service jar path for each test case
 281      * based on client/service module type.
 282      */
 283     @Override
 284     public Path findJarPath(boolean isService, MODULE_TYPE moduleType,
 285             boolean addMetaDesc, boolean dependsOnServiceModule) {
 286         if (isService) {
 287             if (moduleType == MODULE_TYPE.EXPLICIT) {
 288                 if (addMetaDesc) {
 289                     return MS_WITH_DESCR_JAR;
 290                 } else {
 291                     return MS_JAR;
 292                 }
 293             } else {
 294                 if (addMetaDesc) {
 295                     return S_WITH_DESCRIPTOR_JAR;
 296                 } else {
 297                     return S_JAR;
 298                 }
 299             }
 300         } else {
 301             if (moduleType == MODULE_TYPE.EXPLICIT) {
 302                 if (dependsOnServiceModule) {
 303                     return MC_JAR;
 304                 } else {
 305                     return MC_DEPENDS_ON_AUTO_SERVICE_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... args) throws IOException {
 318         final Map<String, String> VM_ARGS = new LinkedHashMap<>();
 319         VM_ARGS.put("-Duser.language=", "en");
 320         VM_ARGS.put("-Duser.region=", "US");
 321         //If mechanism selected to find the provider through 
 322         //Security.getProvider() then use providerName/ProviderClassName based
 323         //on modular/regular provider jar in security configuration file.
 324         if (args != null && args.length > 0 && SECURITY_PROP.equals(args[0])) {
 325             if (sModuletype == MODULE_TYPE.UNNAMED) {
 326                 Files.write(SECURE_PROP_EXTN, ("security.provider.10=" + S_IMPL)
 327                         .getBytes());
 328             } else {
 329                 Files.write(SECURE_PROP_EXTN, "security.provider.10=TEST"
 330                         .getBytes());
 331             }
 332             VM_ARGS.put("-Djava.security.properties=", SECURE_PROP_EXTN.toFile()
 333                     .getCanonicalPath());
 334         }
 335         return VM_ARGS;
 336     }
 337 
 338 }