org.apache.slider.server.services.security.CertificateManager.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.slider.server.services.security.CertificateManager.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.slider.server.services.security;

import com.google.inject.Singleton;
import org.apache.commons.io.FileUtils;
import org.apache.slider.common.SliderKeys;
import org.apache.slider.core.conf.MapOperations;
import org.apache.slider.core.exceptions.SliderException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.text.MessageFormat;

@Singleton
public class CertificateManager {

    private static final Logger LOG = LoggerFactory.getLogger(CertificateManager.class);

    private static final String GEN_SRVR_KEY = "openssl genrsa -des3 " + "-passout pass:{0} -out {1}/{2} 4096 ";
    private static final String GEN_SRVR_REQ = "openssl req -passin pass:{0} "
            + "-new -key {1}/{2} -out {1}/{5} -batch";
    private static final String SIGN_SRVR_CRT = "openssl ca -create_serial "
            + "-out {1}/{3} -days 365 -keyfile {1}/{2} -key {0} -selfsign "
            + "-extensions jdk7_ca -config {1}/ca.config -batch " + "-infiles {1}/{5}";
    private static final String EXPRT_KSTR = "openssl pkcs12 -export"
            + " -in {1}/{3} -inkey {1}/{2} -certfile {1}/{3} -out {1}/{4} "
            + "-password pass:{0} -passin pass:{0} \n";
    private static final String REVOKE_AGENT_CRT = "openssl ca "
            + "-config {0}/ca.config -keyfile {0}/{4} -revoke {0}/{2} -batch " + "-passin pass:{3} -cert {0}/{5}";
    private static final String SIGN_AGENT_CRT = "openssl ca -config "
            + "{0}/ca.config -in {0}/{1} -out {0}/{2} -batch -passin pass:{3} " + "-keyfile {0}/{4} -cert {0}/{5}";
    private static final String GEN_AGENT_KEY = "openssl req -new -newkey "
            + "rsa:1024 -nodes -keyout {0}/{2}.key -subj /OU={1}/CN={2} -out {0}/{2}.csr";
    private String passphrase;

    /**
      * Verify that root certificate exists, generate it otherwise.
      */
    public void initialize(MapOperations compOperations) {
        SecurityUtils.initializeSecurityParameters(compOperations);

        LOG.info("Initialization of root certificate");
        boolean certExists = isCertExists();
        LOG.info("Certificate exists:" + certExists);

        if (!certExists) {
            generateServerCertificate();
        }

    }

    /**
     * Checks root certificate state.
     * @return "true" if certificate exists
     */
    private boolean isCertExists() {

        String srvrKstrDir = SecurityUtils.getSecurityDir();
        String srvrCrtName = SliderKeys.CRT_FILE_NAME;
        File certFile = new File(srvrKstrDir + File.separator + srvrCrtName);
        LOG.debug("srvrKstrDir = " + srvrKstrDir);
        LOG.debug("srvrCrtName = " + srvrCrtName);
        LOG.debug("certFile = " + certFile.getAbsolutePath());

        return certFile.exists();
    }

    public void setPassphrase(String passphrase) {
        this.passphrase = passphrase;
    }

    class StreamConsumer extends Thread {
        InputStream is;
        boolean logOutput;

        StreamConsumer(InputStream is, boolean logOutput) {
            this.is = is;
            this.logOutput = logOutput;
        }

        StreamConsumer(InputStream is) {
            this(is, false);
        }

        public void run() {
            try {
                InputStreamReader isr = new InputStreamReader(is, Charset.forName("UTF8"));
                BufferedReader br = new BufferedReader(isr);
                String line;
                while ((line = br.readLine()) != null)
                    if (logOutput) {
                        LOG.info(line);
                    }
            } catch (IOException e) {
                LOG.error("Error during processing of process stream", e);
            }
        }
    }

    /**
     * Runs os command
     *
     * @return command execution exit code
     */
    private int runCommand(String command) throws SliderException {
        int exitCode = -1;
        String line = null;
        Process process = null;
        BufferedReader br = null;
        try {
            process = Runtime.getRuntime().exec(command);
            StreamConsumer outputConsumer = new StreamConsumer(process.getInputStream(), true);
            StreamConsumer errorConsumer = new StreamConsumer(process.getErrorStream());

            outputConsumer.start();
            errorConsumer.start();

            try {
                process.waitFor();
                SecurityUtils.logOpenSslExitCode(command, process.exitValue());
                exitCode = process.exitValue();
                if (exitCode != 0) {
                    throw new SliderException(exitCode, "Error running command %s", command);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                }
            }
        }

        return exitCode;//some exception occurred

    }

    public synchronized void generateAgentCertificate(String agentHostname, String containerId) {
        LOG.info("Generation of agent certificate for {}", agentHostname);

        String srvrKstrDir = SecurityUtils.getSecurityDir();
        Object[] scriptArgs = { srvrKstrDir, agentHostname, containerId };

        try {
            String command = MessageFormat.format(GEN_AGENT_KEY, scriptArgs);
            runCommand(command);

            signAgentCertificate(containerId);

        } catch (SliderException e) {
            LOG.error("Error generating the agent certificate", e);
        }
    }

    private void generateServerCertificate() {
        LOG.info("Generation of server certificate");

        String srvrKstrDir = SecurityUtils.getSecurityDir();
        String srvrCrtName = SliderKeys.CRT_FILE_NAME;
        String srvrCsrName = SliderKeys.CSR_FILE_NAME;
        String srvrKeyName = SliderKeys.KEY_FILE_NAME;
        String kstrName = SliderKeys.KEYSTORE_FILE_NAME;
        String srvrCrtPass = SecurityUtils.getKeystorePass();

        Object[] scriptArgs = { srvrCrtPass, srvrKstrDir, srvrKeyName, srvrCrtName, kstrName, srvrCsrName };

        try {
            String command = MessageFormat.format(GEN_SRVR_KEY, scriptArgs);
            runCommand(command);

            command = MessageFormat.format(GEN_SRVR_REQ, scriptArgs);
            runCommand(command);

            command = MessageFormat.format(SIGN_SRVR_CRT, scriptArgs);
            runCommand(command);

            command = MessageFormat.format(EXPRT_KSTR, scriptArgs);
            runCommand(command);
        } catch (SliderException e) {
            LOG.error("Error generating the server certificate", e);
        }

    }

    /**
     * Returns server certificate content
     * @return string with server certificate content
     */
    public String getServerCert() {
        File certFile = getServerCertficateFilePath();
        String srvrCrtContent = null;
        try {
            srvrCrtContent = FileUtils.readFileToString(certFile);
        } catch (IOException e) {
            LOG.error(e.getMessage());
        }
        return srvrCrtContent;
    }

    public static File getServerCertficateFilePath() {
        return new File(SecurityUtils.getSecurityDir() + File.separator + SliderKeys.CRT_FILE_NAME);
    }

    public static File getAgentCertficateFilePath(String containerId) {
        return new File(SecurityUtils.getSecurityDir() + File.separator + containerId + ".crt");
    }

    public static File getAgentKeyFilePath(String containerId) {
        return new File(SecurityUtils.getSecurityDir() + File.separator + containerId + ".key");
    }

    /**
     * Signs agent certificate
     * Adds agent certificate to server keystore
     * @return string with agent signed certificate content
     */
    public synchronized SignCertResponse signAgentCrt(String agentHostname, String agentCrtReqContent,
            String passphraseAgent) {
        SignCertResponse response = new SignCertResponse();
        LOG.info("Signing of agent certificate");
        LOG.info("Verifying passphrase");

        if (!this.passphrase.equals(passphraseAgent.trim())) {
            LOG.warn("Incorrect passphrase from the agent");
            response.setResult(SignCertResponse.ERROR_STATUS);
            response.setMessage("Incorrect passphrase from the agent");
            return response;
        }

        String srvrKstrDir = SecurityUtils.getSecurityDir();
        String srvrCrtPass = SecurityUtils.getKeystorePass();
        String srvrCrtName = SliderKeys.CRT_FILE_NAME;
        String srvrKeyName = SliderKeys.KEY_FILE_NAME;
        String agentCrtReqName = agentHostname + ".csr";
        String agentCrtName = agentHostname + ".crt";

        Object[] scriptArgs = { srvrKstrDir, agentCrtReqName, agentCrtName, srvrCrtPass, srvrKeyName, srvrCrtName };

        //Revoke previous agent certificate if exists
        File agentCrtFile = new File(srvrKstrDir + File.separator + agentCrtName);

        String command = null;
        if (agentCrtFile.exists()) {
            LOG.info("Revoking of " + agentHostname + " certificate.");
            command = MessageFormat.format(REVOKE_AGENT_CRT, scriptArgs);
            try {
                runCommand(command);
            } catch (SliderException e) {
                int commandExitCode = e.getExitCode();
                response.setResult(SignCertResponse.ERROR_STATUS);
                response.setMessage(SecurityUtils.getOpenSslCommandResult(command, commandExitCode));
                return response;
            }
        }

        File agentCrtReqFile = new File(srvrKstrDir + File.separator + agentCrtReqName);
        try {
            FileUtils.writeStringToFile(agentCrtReqFile, agentCrtReqContent);
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

        command = MessageFormat.format(SIGN_AGENT_CRT, scriptArgs);

        LOG.debug(SecurityUtils.hideOpenSslPassword(command));
        try {
            runCommand(command);
        } catch (SliderException e) {
            int commandExitCode = e.getExitCode();
            response.setResult(SignCertResponse.ERROR_STATUS);
            response.setMessage(SecurityUtils.getOpenSslCommandResult(command, commandExitCode));
            return response;
        }

        String agentCrtContent = "";
        try {
            agentCrtContent = FileUtils.readFileToString(agentCrtFile);
        } catch (IOException e) {
            e.printStackTrace();
            LOG.error("Error reading signed agent certificate");
            response.setResult(SignCertResponse.ERROR_STATUS);
            response.setMessage("Error reading signed agent certificate");
            return response;
        }
        response.setResult(SignCertResponse.OK_STATUS);
        response.setSignedCa(agentCrtContent);
        //LOG.info(ShellCommandUtil.getOpenSslCommandResult(command, commandExitCode));
        return response;
    }

    private String signAgentCertificate(String containerId) throws SliderException {
        String srvrKstrDir = SecurityUtils.getSecurityDir();
        String srvrCrtPass = SecurityUtils.getKeystorePass();
        String srvrCrtName = SliderKeys.CRT_FILE_NAME;
        String srvrKeyName = SliderKeys.KEY_FILE_NAME;
        String agentCrtReqName = containerId + ".csr";
        String agentCrtName = containerId + ".crt";

        Object[] scriptArgs = { srvrKstrDir, agentCrtReqName, agentCrtName, srvrCrtPass, srvrKeyName, srvrCrtName };

        //Revoke previous agent certificate if exists
        File agentCrtFile = new File(srvrKstrDir + File.separator + agentCrtName);

        String command;
        if (agentCrtFile.exists()) {
            LOG.info("Revoking of " + containerId + " certificate.");
            command = MessageFormat.format(REVOKE_AGENT_CRT, scriptArgs);
            runCommand(command);
        }

        command = MessageFormat.format(SIGN_AGENT_CRT, scriptArgs);

        LOG.debug(SecurityUtils.hideOpenSslPassword(command));
        runCommand(command);

        return agentCrtName;

    }
}