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