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

Java tutorial

Introduction

Here is the source code for org.apache.slider.server.services.security.TestCertificateManager.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 org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.security.alias.CredentialProvider;
import org.apache.hadoop.security.alias.CredentialProviderFactory;
import org.apache.hadoop.security.alias.JavaKeyStoreProvider;
import org.apache.slider.Slider;
import org.apache.slider.common.SliderKeys;
import org.apache.slider.common.SliderXmlConfKeys;
import org.apache.slider.core.conf.AggregateConf;
import org.apache.slider.core.conf.MapOperations;
import org.apache.slider.core.exceptions.SliderException;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;

import static org.junit.Assert.assertEquals;

/**
 *
 */
public class TestCertificateManager {
    @Rule
    public TemporaryFolder workDir = new TemporaryFolder();
    private File secDir;
    private CertificateManager certMan;

    @Before
    public void setup() throws Exception {
        certMan = new CertificateManager();
        MapOperations compOperations = new MapOperations();
        secDir = new File(workDir.getRoot(), SliderKeys.SECURITY_DIR);
        File keystoreFile = new File(secDir, SliderKeys.KEYSTORE_FILE_NAME);
        compOperations.put(SliderXmlConfKeys.KEY_KEYSTORE_LOCATION, keystoreFile.getAbsolutePath());
        certMan.initialize(compOperations, "cahost", null, null);
    }

    @Test
    public void testServerCertificateGenerated() throws Exception {
        File serverCrt = new File(secDir, SliderKeys.CRT_FILE_NAME);
        Assert.assertTrue("Server CRD does not exist:" + serverCrt, serverCrt.exists());
    }

    @Test
    public void testAMKeystoreGenerated() throws Exception {
        File keystoreFile = new File(secDir, SliderKeys.KEYSTORE_FILE_NAME);
        Assert.assertTrue("Keystore does not exist: " + keystoreFile, keystoreFile.exists());
        InputStream is = null;
        try {

            is = new FileInputStream(keystoreFile);
            KeyStore keystore = KeyStore.getInstance("pkcs12");
            String password = SecurityUtils.getKeystorePass();
            keystore.load(is, password.toCharArray());

            Certificate certificate = keystore.getCertificate(keystore.aliases().nextElement());
            Assert.assertNotNull(certificate);

            if (certificate instanceof X509Certificate) {
                X509Certificate x509cert = (X509Certificate) certificate;

                // Get subject
                Principal principal = x509cert.getSubjectDN();
                String subjectDn = principal.getName();
                Assert.assertEquals("wrong DN", "CN=cahost", subjectDn);

                // Get issuer
                principal = x509cert.getIssuerDN();
                String issuerDn = principal.getName();
                Assert.assertEquals("wrong Issuer DN", "CN=cahost", issuerDn);
            }
        } finally {
            if (null != is) {
                is.close();
            }
        }
    }

    @Test
    public void testContainerCertificateGeneration() throws Exception {
        certMan.generateContainerCertificate("testhost", "container1");
        Assert.assertTrue("container certificate not generated", new File(secDir, "container1.crt").exists());
    }

    @Test
    public void testContainerKeystoreGeneration() throws Exception {
        SecurityStore keystoreFile = certMan.generateContainerKeystore("testhost", "container1", "component1",
                "password");
        validateKeystore(keystoreFile.getFile(), "testhost", "cahost");
    }

    private void validateKeystore(File keystoreFile, String certHostname, String issuerHostname)
            throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
        Assert.assertTrue("container keystore not generated", keystoreFile.exists());

        InputStream is = null;
        try {

            is = new FileInputStream(keystoreFile);
            KeyStore keystore = KeyStore.getInstance("pkcs12");
            String password = "password";
            keystore.load(is, password.toCharArray());

            Certificate certificate = keystore.getCertificate(keystore.aliases().nextElement());
            Assert.assertNotNull(certificate);

            if (certificate instanceof X509Certificate) {
                X509Certificate x509cert = (X509Certificate) certificate;

                // Get subject
                Principal principal = x509cert.getSubjectDN();
                String subjectDn = principal.getName();
                Assert.assertEquals("wrong DN", "CN=" + certHostname + ", OU=container1", subjectDn);

                // Get issuer
                principal = x509cert.getIssuerDN();
                String issuerDn = principal.getName();
                Assert.assertEquals("wrong Issuer DN", "CN=" + issuerHostname, issuerDn);
            }
        } finally {
            if (null != is) {
                is.close();
            }
        }
    }

    @Test
    public void testContainerKeystoreGenerationViaStoresGenerator() throws Exception {
        AggregateConf instanceDefinition = new AggregateConf();
        MapOperations compOps = new MapOperations();
        instanceDefinition.getAppConf().components.put("component1", compOps);
        compOps.put(SliderKeys.COMP_KEYSTORE_PASSWORD_PROPERTY_KEY, "app1.component1.password.property");
        compOps.put(SliderKeys.COMP_STORES_REQUIRED_KEY, "true");
        instanceDefinition.getAppConf().global.put("app1.component1.password.property", "password");
        instanceDefinition.resolve();
        SecurityStore[] files = StoresGenerator.generateSecurityStores("testhost", "container1", "component1",
                instanceDefinition, compOps);
        assertEquals("wrong number of stores", 1, files.length);
        validateKeystore(files[0].getFile(), "testhost", "cahost");
    }

    @Test
    public void testContainerKeystoreGenerationViaStoresGeneratorUsingGlobalProps() throws Exception {
        AggregateConf instanceDefinition = new AggregateConf();
        MapOperations compOps = new MapOperations();
        instanceDefinition.getAppConf().components.put("component1", compOps);
        compOps.put(SliderKeys.COMP_KEYSTORE_PASSWORD_PROPERTY_KEY, "app1.component1.password.property");
        instanceDefinition.getAppConf().global.put(SliderKeys.COMP_STORES_REQUIRED_KEY, "true");
        compOps.put("app1.component1.password.property", "password");
        instanceDefinition.resolve();
        SecurityStore[] files = StoresGenerator.generateSecurityStores("testhost", "container1", "component1",
                instanceDefinition, compOps);
        assertEquals("wrong number of stores", 1, files.length);
        validateKeystore(files[0].getFile(), "testhost", "cahost");
    }

    @Test
    public void testContainerKeystoreGenerationViaStoresGeneratorOverrideGlobalSetting() throws Exception {
        AggregateConf instanceDefinition = new AggregateConf();
        MapOperations compOps = setupComponentOptions(true, null, "app1.component1.password.property", null, null);
        instanceDefinition.getAppConf().components.put("component1", compOps);
        instanceDefinition.getAppConf().global.put("app1.component1.password.property", "password");
        instanceDefinition.getAppConf().global.put(SliderKeys.COMP_STORES_REQUIRED_KEY, "false");
        instanceDefinition.resolve();
        SecurityStore[] files = StoresGenerator.generateSecurityStores("testhost", "container1", "component1",
                instanceDefinition, compOps);
        assertEquals("wrong number of stores", 1, files.length);
        validateKeystore(files[0].getFile(), "testhost", "cahost");
    }

    @Test
    public void testContainerTrusttoreGeneration() throws Exception {
        SecurityStore keystoreFile = certMan.generateContainerKeystore("testhost", "container1", "component1",
                "keypass");
        Assert.assertTrue("container keystore not generated", keystoreFile.getFile().exists());
        SecurityStore truststoreFile = certMan.generateContainerTruststore("container1", "component1", "trustpass");
        Assert.assertTrue("container truststore not generated", truststoreFile.getFile().exists());

        validateTruststore(keystoreFile.getFile(), truststoreFile.getFile());
    }

    @Test
    public void testContainerGenerationUsingStoresGeneratorNoTruststore() throws Exception {
        AggregateConf instanceDefinition = new AggregateConf();
        MapOperations compOps = new MapOperations();
        compOps.put(SliderKeys.COMP_STORES_REQUIRED_KEY, "true");
        compOps.put(SliderKeys.COMP_KEYSTORE_PASSWORD_ALIAS_KEY, "test.keystore.password");

        setupCredentials(instanceDefinition, "test.keystore.password", null);

        SecurityStore[] files = StoresGenerator.generateSecurityStores("testhost", "container1", "component1",
                instanceDefinition, compOps);
        assertEquals("wrong number of stores", 1, files.length);
        File keystoreFile = CertificateManager.getContainerKeystoreFilePath("container1", "component1");
        Assert.assertTrue("container keystore not generated", keystoreFile.exists());

        Assert.assertTrue("keystore not in returned list",
                Arrays.asList(files).contains(new SecurityStore(keystoreFile, SecurityStore.StoreType.keystore)));
        File truststoreFile = CertificateManager.getContainerTruststoreFilePath("component1", "container1");
        Assert.assertFalse("container truststore generated", truststoreFile.exists());
        Assert.assertFalse("truststore in returned list", Arrays.asList(files)
                .contains(new SecurityStore(truststoreFile, SecurityStore.StoreType.truststore)));

    }

    @Test
    public void testContainerGenerationUsingStoresGeneratorJustTruststoreWithDefaultAlias() throws Exception {
        AggregateConf instanceDefinition = new AggregateConf();
        MapOperations compOps = setupComponentOptions(true);

        setupCredentials(instanceDefinition, null, SliderKeys.COMP_TRUSTSTORE_PASSWORD_ALIAS_DEFAULT);

        SecurityStore[] files = StoresGenerator.generateSecurityStores("testhost", "container1", "component1",
                instanceDefinition, compOps);
        assertEquals("wrong number of stores", 1, files.length);
        File keystoreFile = CertificateManager.getContainerKeystoreFilePath("container1", "component1");
        Assert.assertFalse("container keystore generated", keystoreFile.exists());
        Assert.assertFalse("keystore in returned list", Arrays.asList(files).contains(keystoreFile));
        File truststoreFile = CertificateManager.getContainerTruststoreFilePath("component1", "container1");
        Assert.assertTrue("container truststore not generated", truststoreFile.exists());
        Assert.assertTrue("truststore not in returned list", Arrays.asList(files)
                .contains(new SecurityStore(truststoreFile, SecurityStore.StoreType.truststore)));

    }

    @Test
    public void testContainerTrusttoreGenerationUsingStoresGenerator() throws Exception {
        AggregateConf instanceDefinition = new AggregateConf();
        MapOperations compOps = setupComponentOptions(true, "test.keystore.password", null,
                "test.truststore.password", null);

        setupCredentials(instanceDefinition, "test.keystore.password", "test.truststore.password");

        SecurityStore[] files = StoresGenerator.generateSecurityStores("testhost", "container1", "component1",
                instanceDefinition, compOps);
        assertEquals("wrong number of stores", 2, files.length);
        File keystoreFile = CertificateManager.getContainerKeystoreFilePath("container1", "component1");
        Assert.assertTrue("container keystore not generated", keystoreFile.exists());
        Assert.assertTrue("keystore not in returned list",
                Arrays.asList(files).contains(new SecurityStore(keystoreFile, SecurityStore.StoreType.keystore)));
        File truststoreFile = CertificateManager.getContainerTruststoreFilePath("component1", "container1");
        Assert.assertTrue("container truststore not generated", truststoreFile.exists());
        Assert.assertTrue("truststore not in returned list", Arrays.asList(files)
                .contains(new SecurityStore(truststoreFile, SecurityStore.StoreType.truststore)));

        validateTruststore(keystoreFile, truststoreFile);
    }

    private void setupCredentials(AggregateConf instanceDefinition, String keyAlias, String trustAlias)
            throws Exception {
        Configuration conf = new Configuration();
        final Path jksPath = new Path(SecurityUtils.getSecurityDir(), "test.jks");
        final String ourUrl = JavaKeyStoreProvider.SCHEME_NAME + "://file" + jksPath.toUri();

        File file = new File(SecurityUtils.getSecurityDir(), "test.jks");
        file.delete();
        conf.set(CredentialProviderFactory.CREDENTIAL_PROVIDER_PATH, ourUrl);

        instanceDefinition.getAppConf().credentials.put(ourUrl, new ArrayList<String>());

        CredentialProvider provider = CredentialProviderFactory.getProviders(conf).get(0);

        // create new aliases
        try {

            if (keyAlias != null) {
                char[] storepass = { 'k', 'e', 'y', 'p', 'a', 's', 's' };
                provider.createCredentialEntry(keyAlias, storepass);
            }

            if (trustAlias != null) {
                char[] trustpass = { 't', 'r', 'u', 's', 't', 'p', 'a', 's', 's' };
                provider.createCredentialEntry(trustAlias, trustpass);
            }

            // write out so that it can be found in checks
            provider.flush();
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }

    private MapOperations setupComponentOptions(boolean storesRequired) {
        return this.setupComponentOptions(storesRequired, null, null, null, null);
    }

    private MapOperations setupComponentOptions(boolean storesRequired, String keyAlias, String keyPwd,
            String trustAlias, String trustPwd) {
        MapOperations compOps = new MapOperations();
        compOps.put(SliderKeys.COMP_STORES_REQUIRED_KEY, Boolean.toString(storesRequired));
        if (keyAlias != null) {
            compOps.put(SliderKeys.COMP_KEYSTORE_PASSWORD_ALIAS_KEY, "test.keystore.password");
        }
        if (trustAlias != null) {
            compOps.put(SliderKeys.COMP_TRUSTSTORE_PASSWORD_ALIAS_KEY, "test.truststore.password");
        }
        if (keyPwd != null) {
            compOps.put(SliderKeys.COMP_KEYSTORE_PASSWORD_PROPERTY_KEY, keyPwd);
        }
        if (trustPwd != null) {
            compOps.put(SliderKeys.COMP_TRUSTSTORE_PASSWORD_PROPERTY_KEY, trustPwd);
        }
        return compOps;
    }

    @Test
    public void testContainerStoresGenerationKeystoreOnly() throws Exception {
        AggregateConf instanceDefinition = new AggregateConf();
        MapOperations compOps = new MapOperations();
        compOps.put(SliderKeys.COMP_STORES_REQUIRED_KEY, "true");

        setupCredentials(instanceDefinition, SliderKeys.COMP_KEYSTORE_PASSWORD_ALIAS_DEFAULT, null);

        SecurityStore[] files = StoresGenerator.generateSecurityStores("testhost", "container1", "component1",
                instanceDefinition, compOps);
        assertEquals("wrong number of stores", 1, files.length);
        File keystoreFile = CertificateManager.getContainerKeystoreFilePath("container1", "component1");
        Assert.assertTrue("container keystore not generated", keystoreFile.exists());
        Assert.assertTrue("keystore not in returned list",
                Arrays.asList(files).contains(new SecurityStore(keystoreFile, SecurityStore.StoreType.keystore)));
        File truststoreFile = CertificateManager.getContainerTruststoreFilePath("component1", "container1");
        Assert.assertFalse("container truststore generated", truststoreFile.exists());
        Assert.assertFalse("truststore in returned list", Arrays.asList(files)
                .contains(new SecurityStore(truststoreFile, SecurityStore.StoreType.truststore)));

    }

    @Test
    public void testContainerStoresGenerationMisconfiguration() throws Exception {
        AggregateConf instanceDefinition = new AggregateConf();
        MapOperations compOps = new MapOperations();
        compOps.put(SliderKeys.COMP_STORES_REQUIRED_KEY, "true");

        setupCredentials(instanceDefinition, "cant.be.found", null);

        try {
            StoresGenerator.generateSecurityStores("testhost", "container1", "component1", instanceDefinition,
                    compOps);
            Assert.fail("SliderException should have been generated");
        } catch (SliderException e) {
            // ignore - should be thrown
        }
    }

    private void validateTruststore(File keystoreFile, File truststoreFile)
            throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
        InputStream keyis = null;
        InputStream trustis = null;
        try {

            // create keystore
            keyis = new FileInputStream(keystoreFile);
            KeyStore keystore = KeyStore.getInstance("pkcs12");
            String password = "keypass";
            keystore.load(keyis, password.toCharArray());

            // obtain server cert
            Certificate certificate = keystore.getCertificate(keystore.aliases().nextElement());
            Assert.assertNotNull(certificate);

            // create trust store from generated trust store file
            trustis = new FileInputStream(truststoreFile);
            KeyStore truststore = KeyStore.getInstance("pkcs12");
            password = "trustpass";
            truststore.load(trustis, password.toCharArray());

            // validate keystore cert using trust store
            TrustManagerFactory trustManagerFactory = TrustManagerFactory
                    .getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(truststore);

            for (TrustManager trustManager : trustManagerFactory.getTrustManagers()) {
                if (trustManager instanceof X509TrustManager) {
                    X509TrustManager x509TrustManager = (X509TrustManager) trustManager;
                    x509TrustManager.checkServerTrusted(new X509Certificate[] { (X509Certificate) certificate },
                            "RSA_EXPORT");
                }
            }

        } finally {
            if (null != keyis) {
                keyis.close();
            }
            if (null != trustis) {
                trustis.close();
            }
        }
    }

}