jdk/test/javax/security/auth/login/modules/JaasModularClientTest.java
author ssahoo
Wed, 23 Aug 2017 09:13:32 -0700
changeset 46898 4d2a6afafb76
parent 45393 de4e1efc8eec
permissions -rw-r--r--
8183310: java/security/modules/ModularTest.java should clean up better Summary: This require cleaning up Test files. Reviewed-by: weijun

/*
 * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Arrays;
import java.io.File;
import java.io.OutputStream;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleDescriptor.Builder;
import jdk.internal.module.ModuleInfoWriter;
import java.util.stream.Stream;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.process.OutputAnalyzer;


/*
 * @test
 * @bug 8078813 8183310
 * @summary Test custom JAAS login module with all possible modular option.
 * @library /lib/testlibrary /test/lib
 * @modules java.base/jdk.internal.module
 * @build JarUtils
 * @build TestLoginModule JaasClient
 * @run main JaasModularClientTest false
 * @run main JaasModularClientTest true
 */
public class JaasModularClientTest {

    private static final Path SRC = Paths.get(System.getProperty("test.src"));
    private static final Path TEST_CLASSES
            = Paths.get(System.getProperty("test.classes"));
    private static final Path ARTIFACT_DIR = Paths.get("jars");
    private static final String PS = File.pathSeparator;
    private static final String L_TYPE = "login.TestLoginModule";
    private static final String C_TYPE = "client.JaasClient";

    /**
     * Here is the naming convention followed.
     * l.jar    - Unnamed login module jar.
     * ml.jar   - Modular login module jar.
     * msl.jar  - Modular login module jar provides login module service
     *            through module-info
     * c.jar    - Unnamed client jar.
     * mc.jar   - Modular client jar.
     * mcs.jar  - Modular client jar uses login module service through
     *            module-info.
     * amc.jar  - Modular client used for automatic login module jar.
     * amcs.jar - Modular client used for automatic login module jar and uses
     *            login module service through module-info.
     */
    private static final Path L_JAR = artifact("l.jar");
    private static final Path ML_JAR = artifact("ml.jar");
    private static final Path MSL_JAR = artifact("msl.jar");
    private static final Path C_JAR = artifact("c.jar");
    private static final Path MC_JAR = artifact("mc.jar");
    private static final Path MCS_JAR = artifact("mcs.jar");
    private static final Path AMC_JAR = artifact("amc.jar");
    private static final Path AMCS_JAR = artifact("amcs.jar");

    private final String unnL;
    private final String modL;
    private final String unnC;
    private final String modC;
    private final String autoMC;
    // Common set of VM arguments used in all test cases
    private final List<String> commonArgs;

    public JaasModularClientTest(boolean service) {

        System.out.printf("%n*** Login Module defined as service in "
                + "module-info: %s ***%n%n", service);
        List<String> argList = new LinkedList<>();
        argList.add("-Djava.security.auth.login.config="
                + toAbsPath(SRC.resolve("jaas.conf")));
        commonArgs = Collections.unmodifiableList(argList);

        // Based on Testcase, select unnamed/modular jar files to use.
        unnL = toAbsPath(L_JAR);
        modL = toAbsPath(service ? MSL_JAR : ML_JAR);
        unnC = toAbsPath(C_JAR);
        modC = toAbsPath(service ? MCS_JAR : MC_JAR);
        autoMC = toAbsPath(service ? AMCS_JAR : AMC_JAR);
    }

    /*
     * Test cases are based on the following logic,
     * for (definedAs : {"Service in module-info", "Class Type"}) {
     *     for (clientType : {"NAMED", "AUTOMATIC", "UNNAMED"}) {
     *         for (loginModuleType : {"NAMED", "AUTOMATIC", "UNNAMED"}) {
     *             Create and run java command for each possible case
     *         }
     *     }
     * }
     */
    public static void main(String[] args) throws Exception {

        // Generates unnamed and modular jars.
        setUp();
        boolean service = Boolean.valueOf(args[0]);
        JaasModularClientTest test = new JaasModularClientTest(service);
        test.process();
    }

    private void process() throws Exception {

        // Case: NAMED-NAMED, NAMED-AUTOMATIC, NAMED-UNNAMED
        System.out.println("Case: Modular Client and Modular Login module.");
        execute(String.format("--module-path %s%s%s -m mc/%s",
                modC, PS, modL, C_TYPE));
        System.out.println("Case: Modular Client and automatic Login module.");
        execute(String.format("--module-path %s%s%s --add-modules=l -m mc/%s",
                autoMC, PS, unnL, C_TYPE));
        System.out.println("Case: Modular Client and unnamed Login module.");
        execute(String.format("--module-path %s -cp %s -m mc/%s", autoMC,
                unnL, C_TYPE));

        // Case: AUTOMATIC-NAMED, AUTOMATIC-AUTOMATIC, AUTOMATIC-UNNAMED
        System.out.println("Case: Automatic Client and modular Login module.");
        execute(String.format("--module-path %s%s%s --add-modules=ml -m c/%s",
                unnC, PS, modL, C_TYPE));
        System.out.println("Case: Automatic Client and automatic Login module");
        execute(String.format("--module-path %s%s%s --add-modules=l -m c/%s",
                unnC, PS, unnL, C_TYPE));
        System.out.println("Case: Automatic Client and unnamed Login module.");
        execute(String.format("--module-path %s -cp %s -m c/%s", unnC,
                unnL, C_TYPE));

        // Case: UNNAMED-NAMED, UNNAMED-AUTOMATIC, UNNAMED-UNNAMED
        System.out.println("Case: Unnamed Client and modular Login module.");
        execute(String.format("-cp %s --module-path %s --add-modules=ml %s",
                unnC, modL, C_TYPE));
        System.out.println("Case: Unnamed Client and automatic Login module.");
        execute(String.format("-cp %s --module-path %s --add-modules=l %s",
                unnC, unnL, C_TYPE));
        System.out.println("Case: Unnamed Client and unnamed Login module.");
        execute(String.format("-cp %s%s%s %s", unnC, PS, unnL, C_TYPE));

        // Case: unnamed jars in --module-path and modular jars in -cp.
        System.out.println(
                "Case: Unnamed Client and Login module from modulepath.");
        execute(String.format("--module-path %s%s%s --add-modules=l -m c/%s",
                unnC, PS, unnL, C_TYPE));
        System.out.println(
                "Case: Modular Client and Login module in classpath.");
        execute(String.format("-cp %s%s%s %s", modC, PS, modL, C_TYPE));
    }

    /**
     * Execute with command arguments and process the result.
     */
    private void execute(String args) throws Exception {

        String[] safeArgs = Stream.concat(commonArgs.stream(),
                Stream.of(args.split("\\s+"))).filter(s -> {
            if (s.contains(" ")) {
                throw new RuntimeException("No spaces in args");
            }
            return !s.isEmpty();
        }).toArray(String[]::new);
        OutputAnalyzer out = ProcessTools.executeTestJvm(safeArgs);
        // Handle response.
        if (out.getExitValue() != 0) {
            System.out.printf("OUTPUT: %s", out.getOutput());
            throw new RuntimeException("FAIL: Unknown failure occured.");
        } else {
            System.out.println("Passed.");
        }
    }

    /**
     * Creates Unnamed/modular jar files for TestClient and TestClassLoader.
     */
    private static void setUp() throws Exception {

        if (ARTIFACT_DIR.toFile().exists()) {
            System.out.println("Skipping setup: Artifacts already exists.");
            return;
        }
        // Generate unnamed login module jar file.
        JarUtils.createJarFile(L_JAR, TEST_CLASSES,
                "login/TestLoginModule.class");
        // Generate unnamed client jar.
        JarUtils.createJarFile(C_JAR, TEST_CLASSES, "client/JaasClient.class",
                "client/JaasClient$MyCallbackHandler.class");

        Builder mBuilder = ModuleDescriptor.newModule("ml")
                .requires("jdk.security.auth");
        // Modular jar exports package to let the login module type accessible.
        generateJar(L_JAR, ML_JAR, mBuilder.exports("login").build());

        mBuilder = ModuleDescriptor.newModule("ml")
                .requires("jdk.security.auth")
                .provides("javax.security.auth.spi.LoginModule",
                        Arrays.asList(L_TYPE));
        // Modular login module as Service in module-info does not need to
        // export service package.
        generateJar(L_JAR, MSL_JAR, mBuilder.build());

        mBuilder = ModuleDescriptor.newModule("mc").exports("client")
                .requires("jdk.security.auth");
        // Generate modular client jar to use automatic login module jar.
        generateJar(C_JAR, AMC_JAR, mBuilder.build());
        // Generate modular client jar to use modular login module jar.
        generateJar(C_JAR, MC_JAR, mBuilder.requires("ml").build());

        mBuilder = ModuleDescriptor.newModule("mc").exports("client")
                .requires("jdk.security.auth")
                .uses("javax.security.auth.spi.LoginModule");
        // Generate modular client jar to use automatic login module service.
        generateJar(C_JAR, AMCS_JAR, mBuilder.build());
        // Generate modular client jar using modular login module service.
        generateJar(C_JAR, MCS_JAR, mBuilder.requires("ml").build());
    }

    /**
     * Update Unnamed jars and include module descriptor files.
     */
    private static void generateJar(Path sjar, Path djar,
            ModuleDescriptor mDesc) throws Exception {

        Files.copy(sjar, djar, StandardCopyOption.REPLACE_EXISTING);
        Path dir = Files.createTempDirectory("tmp");
        if (mDesc != null) {
            Path mi = dir.resolve("module-info.class");
            try (OutputStream out = Files.newOutputStream(mi)) {
                ModuleInfoWriter.write(mDesc, out);
            }
            System.out.format("Added 'module-info.class' in '%s'%n", djar);
        }
        JarUtils.updateJarFile(djar, dir);
    }

    /**
     * Look for file path in generated jars.
     */
    private static Path artifact(String file) {
        return ARTIFACT_DIR.resolve(file);
    }

    /**
     * Convert to absolute file path.
     */
    private static String toAbsPath(Path path) {
        return path.toFile().getAbsolutePath();
    }
}