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