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