/* * 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.accumulo.core.conf; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.hdfs.MiniDFSCluster; import org.junit.Assert; import org.junit.Assume; import org.junit.BeforeClass; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * */ public class CredentialProviderFactoryShimTest { private static final Logger log = LoggerFactory.getLogger(CredentialProviderFactoryShimTest.class); private static final String populatedKeyStoreName = "/accumulo.jceks", emptyKeyStoreName = "/empty.jceks"; private static File emptyKeyStore, populatedKeyStore; @BeforeClass public static void checkCredentialProviderAvailable() { try { Class.forName(CredentialProviderFactoryShim.HADOOP_CRED_PROVIDER_CLASS_NAME); } catch (Exception e) { // If we can't load the credential provider class, don't run the tests Assume.assumeNoException(e); } URL populatedKeyStoreUrl = CredentialProviderFactoryShimTest.class.getResource(populatedKeyStoreName), emptyKeyStoreUrl = CredentialProviderFactoryShimTest.class .getResource(emptyKeyStoreName); Assert.assertNotNull("Could not find " + populatedKeyStoreName, populatedKeyStoreUrl); Assert.assertNotNull("Could not find " + emptyKeyStoreName, emptyKeyStoreUrl); populatedKeyStore = new File(populatedKeyStoreUrl.getFile()); emptyKeyStore = new File(emptyKeyStoreUrl.getFile()); } protected String getKeyStoreUrl(File absoluteFilePath) { return "jceks://file" + absoluteFilePath.getAbsolutePath(); } @Test(expected = NullPointerException.class) public void testNullConfigOnGetValue() throws IOException { CredentialProviderFactoryShim.getValueFromCredentialProvider(null, "alias"); } @Test(expected = NullPointerException.class) public void testNullAliasOnGetValue() throws IOException { CredentialProviderFactoryShim.getValueFromCredentialProvider(new Configuration(false), null); } protected void checkCredentialProviders(Configuration conf, Map<String,String> expectation) throws IOException { List<String> keys = CredentialProviderFactoryShim.getKeys(conf); Assert.assertNotNull(keys); Assert.assertEquals(expectation.keySet(), new HashSet<>(keys)); for (String expectedKey : keys) { char[] value = CredentialProviderFactoryShim.getValueFromCredentialProvider(conf, expectedKey); Assert.assertNotNull(value); Assert.assertEquals(expectation.get(expectedKey), new String(value)); } } @Test public void testExtractFromProvider() throws IOException { String absPath = getKeyStoreUrl(populatedKeyStore); Configuration conf = new Configuration(); conf.set(CredentialProviderFactoryShim.CREDENTIAL_PROVIDER_PATH, absPath); Map<String,String> expectations = new HashMap<>(); expectations.put("key1", "value1"); expectations.put("key2", "value2"); checkCredentialProviders(conf, expectations); } @Test public void testEmptyKeyStoreParses() throws IOException { String absPath = getKeyStoreUrl(emptyKeyStore); Configuration conf = new Configuration(); conf.set(CredentialProviderFactoryShim.CREDENTIAL_PROVIDER_PATH, absPath); checkCredentialProviders(conf, new HashMap<String,String>()); } @Test public void testEmptyAndPopulatedKeyStores() throws IOException { String populatedAbsPath = getKeyStoreUrl(populatedKeyStore), emptyAbsPath = getKeyStoreUrl(emptyKeyStore); Configuration conf = new Configuration(); conf.set(CredentialProviderFactoryShim.CREDENTIAL_PROVIDER_PATH, populatedAbsPath + "," + emptyAbsPath); Map<String,String> expectations = new HashMap<>(); expectations.put("key1", "value1"); expectations.put("key2", "value2"); checkCredentialProviders(conf, expectations); } @Test public void testNonExistentClassesDoesntFail() throws IOException { Configuration conf = new Configuration(); conf.set(CredentialProviderFactoryShim.CREDENTIAL_PROVIDER_PATH, "jceks://file/foo/bar.jceks"); List<String> keys = CredentialProviderFactoryShim.getKeys(conf); Assert.assertNotNull(keys); Assert.assertEquals(Collections.emptyList(), keys); Assert.assertNull(CredentialProviderFactoryShim.getValueFromCredentialProvider(conf, "key1")); } @Test public void testConfigurationCreation() throws IOException { final String path = "jceks://file/tmp/foo.jks"; final Configuration actualConf = CredentialProviderFactoryShim.getConfiguration(path); Assert.assertNotNull(actualConf); Assert.assertEquals(path, actualConf.get(CredentialProviderFactoryShim.CREDENTIAL_PROVIDER_PATH)); } @Test public void createKeystoreProvider() throws Exception { File targetDir = new File(System.getProperty("user.dir") + "/target"); File keystoreFile = new File(targetDir, "create.jks"); if (keystoreFile.exists()) { if (!keystoreFile.delete()) { log.error("Unable to delete {}", keystoreFile); } } String providerUrl = "jceks://file" + keystoreFile.getAbsolutePath(); Configuration conf = new Configuration(); conf.set(CredentialProviderFactoryShim.CREDENTIAL_PROVIDER_PATH, providerUrl); String alias = "foo"; char[] credential = "bar".toCharArray(); CredentialProviderFactoryShim.createEntry(conf, alias, credential); Assert.assertArrayEquals(credential, CredentialProviderFactoryShim.getValueFromCredentialProvider(conf, alias)); } @Test public void extractFromHdfs() throws Exception { File target = new File(System.getProperty("user.dir"), "target"); String prevValue = System.setProperty("test.build.data", new File(target, this.getClass().getName() + "_minidfs").toString()); MiniDFSCluster dfsCluster = new MiniDFSCluster.Builder(new Configuration()).build(); try { if (null != prevValue) { System.setProperty("test.build.data", prevValue); } else { System.clearProperty("test.build.data"); } // One namenode, One configuration Configuration dfsConfiguration = dfsCluster.getConfiguration(0); Path destPath = new Path("/accumulo.jceks"); FileSystem dfs = dfsCluster.getFileSystem(); // Put the populated keystore in hdfs dfs.copyFromLocalFile(new Path(populatedKeyStore.toURI()), destPath); Configuration cpConf = CredentialProviderFactoryShim.getConfiguration(dfsConfiguration, "jceks://hdfs/accumulo.jceks"); // The values in the keystore Map<String,String> expectations = new HashMap<>(); expectations.put("key1", "value1"); expectations.put("key2", "value2"); checkCredentialProviders(cpConf, expectations); } finally { dfsCluster.shutdown(); } } @Test public void existingConfigurationReturned() { Configuration conf = new Configuration(false); conf.set("foo", "bar"); Configuration conf2 = CredentialProviderFactoryShim.getConfiguration(conf, "jceks:///file/accumulo.jceks"); // Same object Assert.assertSame(conf, conf2); Assert.assertEquals("bar", conf.get("foo")); } }