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