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