test/javax/management/remote/rest/RestAdapterSSLTest.java
author hb
Tue, 29 Aug 2017 13:34:15 +0530
branchjmx-rest-api
changeset 55985 0c5a02edfdef
permissions -rw-r--r--
REST Adapter Initial commit 1. Unit tested and working GET/POST interfaces 2. Unit tested and working JSON parser

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

import com.oracle.jmx.remote.rest.json.JSONArray;
import com.oracle.jmx.remote.rest.json.JSONElement;
import com.oracle.jmx.remote.rest.json.JSONObject;
import com.oracle.jmx.remote.rest.json.JSONPrimitive;
import com.oracle.jmx.remote.rest.json.parser.JSONParser;
import com.oracle.jmx.remote.rest.json.parser.ParseException;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.util.Base64;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.remote.rest.JmxRestAdapter;
import javax.management.remote.rest.PlatformRestAdapter;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.TrustManagerFactory;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

/**
 * @test
 * @modules java.logging
 *          java.management
 *          java.management.rest
 * @run testng/othervm RestAdapterSSLTest
 * 
 */
@Test
public class RestAdapterSSLTest {

    private static final String CHARSET = "UTF-8";
    private static String sslAgentConfig;
    private static String sslClientConfig;
    private static String passwordFile;
    private static String configFile;

    private void createAgentSslConfigFile(String fileName) throws IOException {
        File f = new File(fileName);
        if (f.exists()) {
            return;
        }
        Properties props = new Properties();
        String testDir = System.getProperty("test.src");
        props.setProperty("javax.net.ssl.keyStore", testDir + File.separator + "keystoreAgent");
        props.setProperty("javax.net.ssl.keyStorePassword", "glopglop");
        props.setProperty("javax.net.ssl.trustStore", testDir + File.separator + "truststoreAgent");
        props.setProperty("javax.net.ssl.trustStorePassword", "glopglop");

        try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))) {
            props.store(writer, "");
        }
    }

    private void createClientSslConfigFile(String fileName) throws IOException {
        File f = new File(fileName);
        if (f.exists()) {
            return;
        }
        Properties props = new Properties();
        String testDir = System.getProperty("test.src");
        props.setProperty("javax.net.ssl.keyStore", testDir + File.separator + "keystoreClient");
        props.setProperty("javax.net.ssl.keyStorePassword", "glopglop");
        props.setProperty("javax.net.ssl.trustStore", testDir + File.separator + "truststoreClient");
        props.setProperty("javax.net.ssl.trustStorePassword", "glopglop");

        try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))) {
            props.store(writer, "");
        }
    }

    private void setupMgmtConfig(String fileName) throws IOException {
        Properties props = new Properties();
        
        props.setProperty("com.sun.management.jmxremote.ssl", "true");
        props.setProperty("com.sun.management.jmxremote.ssl.config.file", sslAgentConfig);
        props.setProperty("com.sun.management.jmxremote.password.file", passwordFile);
        props.setProperty("com.sun.management.jmxremote.rest.port", "0");

        try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))) {
            props.store(writer, "");
        }
    }

    private void setupConfig() throws Exception {
        String testSrcRoot = System.getProperty("test.src") + File.separator;
        sslAgentConfig = testSrcRoot + "sslConfigAgent";
        sslClientConfig = testSrcRoot + "sslConfigClient";
        passwordFile = testSrcRoot + "password.properties";
        configFile = testSrcRoot + "mgmt.properties";
        createAgentSslConfigFile(sslAgentConfig);
        createClientSslConfigFile(sslClientConfig);
        setupMgmtConfig(configFile);
    }

    @BeforeClass
    public void setupAdapter() throws Exception {
        setupConfig();
        File file = new File(configFile);
        Properties props = new Properties();
        props.load(new FileInputStream(file));
        if (props.get("com.sun.management.jmxremote.rest.port") != null) {
            PlatformRestAdapter.init((String) props.get("com.sun.management.jmxremote.rest.port"), props);
        }
        PlatformRestAdapter.getInstance().start();
        SSLContext ctx = getSSlContext(sslClientConfig);
        HttpsURLConnection.setDefaultSSLSocketFactory(ctx.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier(
                (String hostname, javax.net.ssl.SSLSession sslSession) -> hostname.equals("Harsha-Wardhana-B"));
        setupMbean();
    }

    @AfterClass
    public void tearDown() {
        PlatformRestAdapter.stop();
    }

    @DataProvider
    public Object[][] getUrlList() {
        Object[][] data = new Object[7][1];
        data[0][0] = "?domain=default";
        data[1][0] = "mbeans";
        data[2][0] = "domains";
        data[3][0] = "java.lang:type=Memory";
        data[4][0] = "java.lang:type=Memory/HeapMemoryUsage";
        data[5][0] = "java.lang:type=Memory/?attributes=HeapMemoryUsage,ObjectPendingFinalizationCount,NonHeapMemoryUsage";
        data[6][0] = "java.lang:type=Memory/?attributes=all";
        return data;
    }

    @DataProvider
    public Object[][] getMalformedUrlList() {
        Object[][] data = new Object[1][1];
        data[0][0] = "com.example:type=QueueSamplerMBean";
        return data;
    }

    private String executeHttpRequest(String inputUrl) throws IOException {
        return executeHttpRequest(inputUrl, null);
    }

    private String executeHttpRequest(String inputUrl, String charset) throws IOException {
        if (inputUrl != null && !inputUrl.isEmpty()) {
            JmxRestAdapter adapter = PlatformRestAdapter.getInstance();
            URL url = new URL(adapter.getBaseUrl() + (charset != null ? URLEncoder.encode(inputUrl, charset) : inputUrl));
            HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
            con.setDoOutput(false);
            String userCredentials = "username1:password1";
            String basicAuth = "Basic " + Base64.getEncoder().encodeToString(userCredentials.getBytes());
            con.setRequestProperty("Authorization", basicAuth);
            if (charset != null && !charset.isEmpty()) {
                con.setRequestProperty("Content-Type", "application/json; charset=" + charset);
            }
            try {
                int status = con.getResponseCode();
                if (status == 200) {

                    StringBuilder sbuf;
                    try (BufferedReader br = new BufferedReader(
                            new InputStreamReader(con.getInputStream()))) {
                        sbuf = new StringBuilder();
                        String input;
                        while ((input = br.readLine()) != null) {
                            sbuf.append(charset != null ? URLDecoder.decode(input, charset) : input);
                        }
                    }
                    return sbuf.toString();
                } else {
                    StringBuilder sbuf;
                    try (BufferedReader br = new BufferedReader(
                            new InputStreamReader(con.getErrorStream()))) {
                        sbuf = new StringBuilder();
                        String input;
                        while ((input = br.readLine()) != null) {
                            sbuf.append(charset != null ? URLDecoder.decode(input, charset) : input);
                        }
                    }
                    return sbuf.toString();
                }
            } catch (IOException e) {
            }
        }
        return null;
    }

    @Test
    public void testMisc() throws IOException, ParseException {
        String mBeanInfo = executeHttpRequest("com.sun.management:type=DiagnosticCommand");
        System.out.println(mBeanInfo);
        JSONParser parser = new JSONParser(mBeanInfo);
        JSONObject response = (JSONObject) parser.parse();
        long status = (Long) ((JSONPrimitive) response.get("status")).getValue();
        Assert.assertEquals(status, 200);
    }

    @Test(enabled = false)
    public void testCharset() throws IOException {
        String result1 = executeHttpRequest("?domain=default");
        String result2 = executeHttpRequest("?domain=default", CHARSET);
        Assert.assertEquals(result1, result2);
    }

    @Test
    public void testPostMisc() throws IOException {
        JmxRestAdapter adapter = PlatformRestAdapter.getInstance();
        URL url = new URL(adapter.getBaseUrl());
        HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
        connection.setRequestProperty("Content-Type", "application/json; charset=" + CHARSET);
        connection.setDoOutput(true);
        connection.setRequestMethod("POST");
        String userCredentials = "username1:password1";
        String basicAuth = "Basic " + Base64.getEncoder().encodeToString(userCredentials.getBytes());
        connection.setRequestProperty("Authorization", basicAuth);

        String req = "{\n"
                + "    \"name\":\"java.lang:type=Memory\"\n"
                + "    \"write\":\"Verbose\"\n"
                + "    \"arguments\" : [true]\n"
                + "}";
        try (OutputStreamWriter out = new OutputStreamWriter(
                connection.getOutputStream(), CHARSET)) {
            out.write(URLEncoder.encode(req, CHARSET));
            out.flush();
        }

        print_content(connection);
    }

    @Test
    public void testBasicHttps() throws Exception {
        JmxRestAdapter adapter = PlatformRestAdapter.getInstance();
        URL url = new URL(adapter.getBaseUrl());
        HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
        con.setDoOutput(false);

        String userCredentials = "username1:password1";

        String basicAuth = "Basic " + Base64.getEncoder().encodeToString(userCredentials.getBytes());
        con.setRequestProperty("Authorization", basicAuth);
        print_https_cert(con);
        print_content(con);
    }

    @Test(dataProvider = "getUrlList")
    public void testGetRequests(String urlStr) throws Exception {
        String input = executeHttpRequest(urlStr);
        System.out.println("URL : [" + urlStr + "] ----> " + input);
        System.out.println(input);
        JSONParser parser = new JSONParser(input);
        JSONElement parse = parser.parse();
        JSONElement jstatus = ((JSONObject) parse).get("status");
        long status = (Long) ((JSONPrimitive) jstatus).getValue();
        Assert.assertEquals(status, 200);
    }

    @Test
    public void testAllGetMBeanInfo() throws Exception {
        String input = executeHttpRequest("mbeans");
        JSONParser parser = new JSONParser(input);
        JSONElement jsonObj = parser.parse();
        if (jsonObj instanceof JSONObject) {
            JSONElement jelem = ((JSONObject) jsonObj).get("response");
            if (jelem instanceof JSONArray) {
                for (JSONElement elem : ((JSONArray) jelem)) {
                    String objName = (String) ((JSONPrimitive) elem).getValue();
                    String mBeanInfo = executeHttpRequest(objName);
                    System.out.println(mBeanInfo);
                    parser = new JSONParser(mBeanInfo);
                    JSONObject response = (JSONObject) parser.parse();
                    long status = (Long) ((JSONPrimitive) response.get("status")).getValue();
                    Assert.assertEquals(status, 200);
                }
            }
        }
    }

    @Test(enabled = false, dataProvider = "getMalformedUrlList")
    public void negTestGetRequests(String urlStr) throws Exception {
        JmxRestAdapter adapter = PlatformRestAdapter.getInstance();
        URL url = new URL(adapter.getBaseUrl() + urlStr);
        HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
        con.setDoOutput(false);
        String userCredentials = "username1:password1";
        String basicAuth = "Basic " + Base64.getEncoder().encodeToString(userCredentials.getBytes());
        con.setRequestProperty("Authorization", basicAuth);
        print_content(con);
    }

    @Test
    public void testPost() throws Exception {
        JmxRestAdapter adapter = PlatformRestAdapter.getInstance();
        URL url = new URL(adapter.getBaseUrl());
        HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
        connection.setRequestProperty("Content-Type", "application/json; charset=" + CHARSET);
        connection.setDoOutput(true);
        connection.setRequestMethod("POST");
        String userCredentials = "username1:password1";
        String basicAuth = "Basic " + Base64.getEncoder().encodeToString(userCredentials.getBytes());
        connection.setRequestProperty("Authorization", basicAuth);

        String postReq = "{\"name\":\"com.example:type=QueueSampler\",\"exec\":\"testMethod1\",\"arguments\":[[1,2,3],\"abc\",5,[\"asd\",\"3\",\"67\",\"778\"],[{date:\"2016-03-02\",size:3,head:\"head\"}],[{date:\"2016-03-02\",size:3,head:\"head\"}]]}";
        JSONArray jarr = new JSONArray();

        JSONObject jobject = new JSONObject();
        jobject.put("name", "com.example:type=QueueSampler");
        jobject.put("write", "QueueName");
        JSONArray jarr1 = new JSONArray();
        jarr1.add(new JSONPrimitive("Dequeue"));
        jobject.put("arguments", jarr1);
        jarr.add(jobject);

        jobject = new JSONObject();
        jobject.put("name", "com.example:type=QueueSampler");
        jobject.put("read", "QueueName");
        jarr.add(jobject);

        jarr.add(new JSONParser(postReq).parse());

        try (OutputStreamWriter out = new OutputStreamWriter(
                connection.getOutputStream(), CHARSET)) {
            out.write(URLEncoder.encode(jarr.toJsonString(), CHARSET));
            out.flush();
        }
        print_content(connection);
    }

    @Test(enabled = false)
    public void testMBeanFilter() throws MalformedObjectNameException {
        // Add non-compliant MBean to platform mbean server
        ObjectName mbeanName = new ObjectName("com.example:type=QueueSamplerMBean");
    }

    private void setupMbean() throws Exception {
        // Get the Platform MBean Server
//        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
//
//        // Construct the ObjectName for the QueueSampler MXBean we will register
//        ObjectName mxbeanName = new ObjectName("com.example:type=QueueSampler");
//        ObjectName mbeanName = new ObjectName("com.example:type=QueueSamplerMBean");
//
//        // Create the Queue Sampler MXBean
//        Queue<String> queue = new ArrayBlockingQueue<>(10);
//        queue.add("Request-1");
//        queue.add("Request-2");
//        queue.add("Request-3");
//        QueueSampler mxbean = new QueueSampler(queue);
//        QueueSamplerBean mbean = new QueueSamplerBean(queue);
//
//        // Register the Queue Sampler MXBean
//        mbs.registerMBean(mxbean, mxbeanName);
//        mbs.registerMBean(mbean, mbeanName);
    }

    private void print_content(HttpURLConnection con) {
        if (con != null) {
            try {
                System.out.println("****** Content of the URL ********");
                int status = con.getResponseCode();

                System.out.println("Status = " + status);
                InputStream is;
                if (status == HttpURLConnection.HTTP_OK) {
                    is = con.getInputStream();
                } else {
                    is = con.getErrorStream();
                }
                BufferedReader br
                        = new BufferedReader(new InputStreamReader(is));
                String input;
                while ((input = br.readLine()) != null) {
                    System.out.println(URLDecoder.decode(input, CHARSET));
                }
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void print_https_cert(HttpsURLConnection con) {
        if (con != null) {
            try {
                System.out.println("Response Code : " + con.getResponseCode());
                System.out.println("Cipher Suite : " + con.getCipherSuite());
                System.out.println("\n");

                Certificate[] certs = con.getServerCertificates();
                for (Certificate cert : certs) {
                    System.out.println("Cert Type : " + cert.getType());
                    System.out.println("Cert Hash Code : " + cert.hashCode());
                    System.out.println("Cert Public Key Algorithm : "
                            + cert.getPublicKey().getAlgorithm());
                    System.out.println("Cert Public Key Format : "
                            + cert.getPublicKey().getFormat());
                    System.out.println("\n");
                }

            } catch (SSLPeerUnverifiedException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static SSLContext getSSlContext(String sslConfigFileName) {
        final String keyStore, keyStorePassword, trustStore, trustStorePassword;

        try {
            Properties p = new Properties();
            BufferedInputStream bin = new BufferedInputStream(new FileInputStream(sslConfigFileName));
            p.load(bin);
            keyStore = p.getProperty(PlatformRestAdapter.PropertyNames.SSL_KEYSTORE_FILE);
            keyStorePassword = p.getProperty(PlatformRestAdapter.PropertyNames.SSL_KEYSTORE_PASSWORD);
            trustStore = p.getProperty(PlatformRestAdapter.PropertyNames.SSL_TRUSTSTORE_FILE);
            trustStorePassword = p.getProperty(PlatformRestAdapter.PropertyNames.SSL_TRUSTSTORE_PASSWORD);

            char[] keyStorePasswd = null;
            if (keyStorePassword.length() != 0) {
                keyStorePasswd = keyStorePassword.toCharArray();
            }

            char[] trustStorePasswd = null;
            if (trustStorePassword.length() != 0) {
                trustStorePasswd = trustStorePassword.toCharArray();
            }

            KeyStore ks = null;
            if (keyStore != null) {
                ks = KeyStore.getInstance(KeyStore.getDefaultType());
                FileInputStream ksfis = new FileInputStream(keyStore);
                ks.load(ksfis, keyStorePasswd);

            }
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(
                    KeyManagerFactory.getDefaultAlgorithm());
            kmf.init(ks, keyStorePasswd);

            KeyStore ts = null;
            if (trustStore != null) {
                ts = KeyStore.getInstance(KeyStore.getDefaultType());
                FileInputStream tsfis = new FileInputStream(trustStore);
                ts.load(tsfis, trustStorePasswd);
            }
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(
                    TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(ts);

            SSLContext ctx = SSLContext.getInstance("SSL");
            ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
            return ctx;
        } catch (Exception ex) {
            Logger.getLogger(PlatformRestAdapter.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }
}