1 /*
   2  * Copyright (c) 2016, 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.nio.file.StandardCopyOption;
  28 import java.util.Collections;
  29 import java.util.LinkedList;
  30 import java.util.List;
  31 import java.io.File;
  32 import java.io.OutputStream;
  33 import java.lang.module.ModuleDescriptor;
  34 import java.lang.module.ModuleDescriptor.Builder;
  35 import jdk.internal.module.ModuleInfoWriter;
  36 import java.util.stream.Stream;
  37 import jdk.test.lib.process.ProcessTools;
  38 import jdk.test.lib.process.OutputAnalyzer;
  39 import jdk.test.lib.util.JarUtils;
  40 
  41 /*
  42  * @test
  43  * @bug 8151654 8183310
  44  * @summary Test default callback handler with all possible modular option.
  45  * @library /test/lib
  46  * @modules java.base/jdk.internal.module
  47  * @build jdk.test.lib.util.JarUtils
  48  * @build TestCallbackHandler TestLoginModule JaasClientWithDefaultHandler
  49  * @run main JaasModularDefaultHandlerTest
  50  */
  51 public class JaasModularDefaultHandlerTest {
  52 
  53     private static final Path SRC = Paths.get(System.getProperty("test.src"));
  54     private static final Path TEST_CLASSES
  55             = Paths.get(System.getProperty("test.classes"));
  56     private static final Path ARTIFACT_DIR = Paths.get("jars");
  57     private static final String PS = File.pathSeparator;
  58     private static final String H_TYPE = "handler.TestCallbackHandler";
  59     private static final String C_TYPE = "login.JaasClientWithDefaultHandler";
  60 
  61     /**
  62      * Here is the naming convention followed for each jar.
  63      * h.jar   - Unnamed handler jar.
  64      * mh.jar  - Modular handler jar.
  65      * c.jar   - Unnamed client jar.
  66      * mc.jar  - Modular client jar.
  67      * amc.jar - Modular client used for automatic handler jar.
  68      */
  69     private static final Path H_JAR = artifact("h.jar");
  70     private static final Path MH_JAR = artifact("mh.jar");
  71     private static final Path C_JAR = artifact("c.jar");
  72     private static final Path MC_JAR = artifact("mc.jar");
  73     private static final Path AMC_JAR = artifact("amc.jar");
  74 
  75     private final String unnH;
  76     private final String modH;
  77     private final String unnC;
  78     private final String modC;
  79     private final String autoMC;
  80     // Common set of VM arguments used in all test cases
  81     private final List<String> commonArgs;
  82 
  83     public JaasModularDefaultHandlerTest() {
  84 
  85         List<String> argList = new LinkedList<>();
  86         argList.add("-Djava.security.auth.login.config="
  87                 + toAbsPath(SRC.resolve("jaas.conf")));
  88         commonArgs = Collections.unmodifiableList(argList);
  89 
  90         // Based on Testcase, select unnamed/modular jar files to use.
  91         unnH = toAbsPath(H_JAR);
  92         modH = toAbsPath(MH_JAR);
  93         unnC = toAbsPath(C_JAR);
  94         modC = toAbsPath(MC_JAR);
  95         autoMC = toAbsPath(AMC_JAR);
  96     }
  97 
  98     /*
  99      * Test cases are based on the following logic,
 100      * for (clientType : {"NAMED", "AUTOMATIC", "UNNAMED"}) {
 101      *     for (handlerType : {"NAMED", "AUTOMATIC", "UNNAMED"}) {
 102      *         Create and run java command for each possible case
 103      *     }
 104      * }
 105      */
 106     public static void main(String[] args) throws Exception {
 107 
 108         // Generates unnamed and modular jars.
 109         setUp();
 110         JaasModularDefaultHandlerTest jt = new JaasModularDefaultHandlerTest();
 111         jt.process();
 112     }
 113 
 114     private void process() throws Exception {
 115 
 116         // Case: NAMED-NAMED, NAMED-AUTOMATIC, NAMED-UNNAMED
 117         System.out.println("Case: Modular Client and Modular Handler");
 118         execute(String.format("--module-path %s%s%s -m mc/%s %s",
 119                 modC, PS, modH, C_TYPE, H_TYPE));
 120         System.out.println("Case: Modular Client and automatic Handler");
 121         execute(String.format("--module-path %s%s%s --add-modules=h -m mc/%s %s",
 122                 autoMC, PS, unnH, C_TYPE, H_TYPE));
 123         System.out.println("Case: Modular Client and unnamed Handler");
 124         execute(String.format("--module-path %s -cp %s -m mc/%s %s", autoMC,
 125                 unnH, C_TYPE, H_TYPE));
 126 
 127         // Case: AUTOMATIC-NAMED, AUTOMATIC-AUTOMATIC, AUTOMATIC-UNNAMED
 128         System.out.println("Case: Automatic Client and modular Handler");
 129         execute(String.format("--module-path %s%s%s --add-modules=mh -m c/%s %s",
 130                 unnC, PS, modH, C_TYPE, H_TYPE));
 131         System.out.println("Case: Automatic Client and automatic Handler");
 132         execute(String.format("--module-path %s%s%s --add-modules=h -m c/%s %s",
 133                 unnC, PS, unnH, C_TYPE, H_TYPE));
 134         System.out.println("Case: Automatic Client and unnamed Handler");
 135         execute(String.format("--module-path %s -cp %s -m c/%s %s", unnC,
 136                 unnH, C_TYPE, H_TYPE));
 137 
 138         // Case: UNNAMED-NAMED, UNNAMED-AUTOMATIC, UNNAMED-UNNAMED
 139         System.out.println("Case: Unnamed Client and modular Handler");
 140         execute(String.format("-cp %s --module-path %s --add-modules=mh %s %s",
 141                 unnC, modH, C_TYPE, H_TYPE));
 142         System.out.println("Case: Unnamed Client and automatic Handler");
 143         execute(String.format("-cp %s --module-path %s --add-modules=h %s %s",
 144                 unnC, unnH, C_TYPE, H_TYPE));
 145         System.out.println("Case: Unnamed Client and unnamed Handler");
 146         execute(String.format("-cp %s%s%s %s %s", unnC, PS, unnH, C_TYPE,
 147                 H_TYPE));
 148 
 149         // Case: unnamed jars in --module-path and modular jars in -cp.
 150         System.out.println("Case: Unnamed Client and Handler in modulepath");
 151         execute(String.format("--module-path %s%s%s --add-modules=h -m c/%s %s",
 152                 unnC, PS, unnH, C_TYPE, H_TYPE));
 153         System.out.println("Case: Modular Client and Provider in classpath");
 154         execute(String.format("-cp %s%s%s %s %s",
 155                 modC, PS, modH, C_TYPE, H_TYPE));
 156     }
 157 
 158     /**
 159      * Execute with command arguments and process the result.
 160      */
 161     private void execute(String args) throws Exception {
 162 
 163         String[] safeArgs = Stream.concat(commonArgs.stream(),
 164                 Stream.of(args.split("\\s+"))).filter(s -> {
 165             if (s.contains(" ")) {
 166                 throw new RuntimeException("No spaces in args");
 167             }
 168             return !s.isEmpty();
 169         }).toArray(String[]::new);
 170         OutputAnalyzer out = ProcessTools.executeTestJvm(safeArgs);
 171         // Handle response.
 172         if (out.getExitValue() != 0) {
 173             System.out.printf("OUTPUT: %s", out.getOutput());
 174             throw new RuntimeException("FAIL: Unknown failure occured.");
 175         } else {
 176             System.out.println("Passed.");
 177         }
 178     }
 179 
 180     /**
 181      * Creates Unnamed/modular jar files for TestClient and TestClassLoader.
 182      */
 183     private static void setUp() throws Exception {
 184 
 185         if (ARTIFACT_DIR.toFile().exists()) {
 186             System.out.println("Skipping setup: Artifacts already exists.");
 187             return;
 188         }
 189         // Generate unnamed handler jar file.
 190         JarUtils.createJarFile(H_JAR, TEST_CLASSES,
 191                 "handler/TestCallbackHandler.class");
 192         // Generate unnamed client jar file.
 193         JarUtils.createJarFile(C_JAR, TEST_CLASSES,
 194                 "login/TestLoginModule.class",
 195                 "login/JaasClientWithDefaultHandler.class");
 196 
 197         Builder mBuilder = ModuleDescriptor.newModule("mh");
 198         // Modular jar exports package to let the handler type accessible.
 199         generateJar(H_JAR, MH_JAR, mBuilder.exports("handler").build());
 200 
 201         mBuilder = ModuleDescriptor.newModule("mc").exports("login")
 202                 .requires("jdk.security.auth");
 203         // Generate modular client jar file to use automatic handler jar.
 204         generateJar(C_JAR, AMC_JAR, mBuilder.build());
 205         // Generate modular client jar file to use modular handler jar.
 206         generateJar(C_JAR, MC_JAR, mBuilder.requires("mh").build());
 207     }
 208 
 209     /**
 210      * Update Unnamed jars and include module descriptor files.
 211      */
 212     private static void generateJar(Path sjar, Path djar,
 213             ModuleDescriptor mDesc) throws Exception {
 214 
 215         Files.copy(sjar, djar, StandardCopyOption.REPLACE_EXISTING);
 216         Path dir = Files.createTempDirectory("tmp");
 217         if (mDesc != null) {
 218             Path mi = dir.resolve("module-info.class");
 219             try (OutputStream out = Files.newOutputStream(mi)) {
 220                 ModuleInfoWriter.write(mDesc, out);
 221             }
 222             System.out.format("Added 'module-info.class' in '%s'%n", djar);
 223         }
 224         JarUtils.updateJarFile(djar, dir);
 225     }
 226 
 227     /**
 228      * Look for file path in generated jars.
 229      */
 230     private static Path artifact(String file) {
 231         return ARTIFACT_DIR.resolve(file);
 232     }
 233 
 234     /**
 235      * Convert to absolute file path.
 236      */
 237     private static String toAbsPath(Path path) {
 238         return path.toFile().getAbsolutePath();
 239     }
 240 }